Request and returns
a standard Response, so it runs in Express, Fastify, Hono, Bun, or any
Node-compatible runtime. The umbrella requires Node 20 or later.
Install and scaffold
Install the umbrella and runvendo init from your app root:
.vendo contract (tools, policy, theme, brief). It reads
package.json to decide what code to propose:
- Express (an
expressdependency): a diff-gatedvendo/server.ts(vendo/server.mjswhen the host has notsconfig.json) holding acreateVendo()composition and a Node HTTP-to-fetch adapter, plus a startervendo/ai.tsmodel module. Two manual wiring steps remain, and init prints both. - Any other runtime (Fastify, Hono, Bun): init detects only
nextandexpress, so it proposes Next-shaped files. Decline those diffs and mountvendo.handleryourself (see below). Detection checksnextfirst, so an app with both dependencies gets the Next scaffold.
Wire the Express adapter
Mount the exported adapter under one base path, normally/api/vendo:
<VendoRoot>:
Composition
The generatedvendo/server.ts calls createVendo once during boot:
principal with your session resolver. It receives the Request and
returns a Principal, or null for an anonymous session:
Mount the handler directly
Outside Express, mountvendo.handler under one base path yourself. It takes a
standard Request and returns a standard Response. The Node adapter that
vendo init generates for Express is the pattern to copy. An adapter must:
- Pass every method (GET, POST, DELETE) through unchanged.
- Preserve streaming for
POST /threads, never buffering the response body. - Reconstruct the request URL from
req.originalUrl, notreq.url, when mounted withapp.useon a base path (Express strips the mount path fromreq.url). - Keep cookie and authorization headers available to
principal(request)and to present-mode same-origin tool calls. - Return multi-value
Set-Cookieas a header array, not a joined string.
VENDO_BASE_URL to your trusted host origin — http://localhost:3000 in
development, your public HTTPS origin in production. It does three jobs.
It gates present-mode credential forwarding, so Vendo passes authorization
and cookie only to same-origin routes matching this value. It marks the
anonymous-session cookie Secure behind a TLS-terminating proxy. And it
provides the base for extracted route tools. When it is unset, present tool
calls run without inbound auth and the composition emits one
present-credentials-not-forwarded audit event so the misconfiguration
does not stay silent. vendo init writes it into .env.example for you.
Verify
Runvendo doctor against the running server:
createVendo from
@vendoai/vendo/server, that the client mounts <VendoRoot>, and makes one live
/status round trip. It also runs live HTTP probes that confirm present-mode
credentials reach the host and that actAs (if configured) mints material
the host accepts. It reports broken until both wiring steps are done. See
the CLI reference for the probe details.
Persistence
PasscreateStore({ url }) to use hosted Postgres for multi-process or
serverless deployments. The default is PGlite at .vendo/data.