@personaai/express exposes the Persona runtime as an Express
Router. Mount it, give it a user resolver, and your Express app has the entire runtime surface —
AG-UI streaming chat, threads, files, memory, MCP OAuth callbacks, health — without writing any
stream forwarding, protocol parsing, or thread-CRUD plumbing.
It’s a thin translation layer: all logic lives in the runtime. If you need a raw call the adapter
doesn’t cover, drop down to @personaai/sdk alongside it.
Prerequisites
- Node.js 18+ and Express 4 or 5 (the
express >= 4peer range is tested against both) - A Project credential shaped
"<keyId>.<secret>", minted in Developer Studio - An Agent to talk to (create one in Studio, or via the SDK’s
agents.create)
Install
@personaai/runtime (the engine) and peer-depends on express >= 4.
Mount the runtime
/api/persona/*:
The complete route table is in the Express routes reference, and the
underlying SDK calls each route proxies to are in the
Runtime routes reference.
Two ways to tell the runtime who a request is from
Persona never authenticates users. The runtime asks you who a request is from — see the auth guide for the full picture. Both idioms in brief: Runtime-level resolver — receives the translated request; read cookies, headers, or JWTs however your app already does (shown above). Express middleware pattern — your own auth middleware runs before the adapter and attaches the identity toreq. Use the createExpressAdapter factory and a resolveUserFrom resolver:
null (or throwing) makes the runtime respond 401. Every route except
GET /health requires an authenticated user.
Lifecycle hooks
All eight hooks (beforeRun, afterRun, onError, beforeToolCall, afterToolCall,
onFileUpload, onThreadCreate, onMemoryWrite) pass straight through to the runtime — see the
Runtime Hooks reference. Configure them on createRuntime or in the
factory options; the adapter never inspects them.
What you get for free
- SSE streaming with heartbeats and
drain-based backpressure; the chatx-persona-run-idheader andGET /chat/:runId/resumepower reconnects — see Streaming & disconnects. - Multipart uploads parsed natively (
POST /files,POST /knowledge/:id/documents) — and if you already usemulter, the adapter honors your parsedreq.file/req.files. See Uploads. - Clean disconnects — a client hanging up mid-stream unsubscribes the runtime immediately.
- Sanitized errors — runtime envelopes (
{"error":{code,message}}) are forwarded verbatim; adapter-side failures (e.g. malformed JSON) respond400 INVALID_REQUESTin the same shape.
Next steps
- Auth & user resolution — the two resolver patterns in depth.
- Routes — every route the mount exposes, and adapter translation details.
- Uploads — multipart parsing, multer coexistence, body-size limits.
- Streaming & disconnects — SSE, backpressure, reconnect, teardown.
- Build a chat UI with the raw SDK’s
chat.streamand the AG-UI events it emits (see the SDK chat guide), or drop in pre-built components when the experience layer ships. - Drop to
@personaai/sdkfor any call the adapter doesn’t cover.