Skip to main content
The adapter exposes the runtime’s entire route table on whatever path you mount it at. The mount is a single catch-all middleware: app.use('/api/persona', toExpressRouter(runtime)) forwards every request under /api/persona/ to runtime.handle(). The runtime owns matching, params, and 404/405 (with Allow) — the adapter adds no routes of its own.

Always-on routes (end-user scoped)

Every route except GET /health requires an authenticated user (401 when the resolver returns null or throws). For the exact SDK call each route proxies to, see the Runtime routes reference.

Opt-in admin routes

The Project-level admin surface (agents CRUD, providers, skills, knowledge, stores, MCPs, audit logs, architect) is off by default — it’s gated behind capabilities.* on the runtime. When a capability is disabled, its routes are simply absent (a request 404s or 405s, never 403). See Runtime capabilities. To expose the admin surface, mount a second runtime with capabilities on and stricter auth:

How the adapter translates a request

toExpressRouter maps an Express Request to the runtime’s framework-neutral contract before runtime.handle() runs. The behaviors to know:

Error responses

  • Runtime responses — including sanitized error envelopes {"error":{code,message}} — are forwarded verbatim (status, headers, body).
  • Adapter translation failures (malformed JSON, unparsable multipart) respond 400 INVALID_REQUEST in the same envelope shape.
  • Any other adapter-side error goes to next(err) so your normal Express error middleware handles it — unless headers are already sent, in which case the connection is ended cleanly.
See Runtime errors for the two detail modes (development vs production).