Skip to main content
Vendo’s handler is framework-agnostic. It takes a standard 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 run vendo init from your app root:
Init always writes the .vendo contract (tools, policy, theme, brief). It reads package.json to decide what code to propose:
  • Express (an express dependency): a diff-gated vendo/server.ts (vendo/server.mjs when the host has no tsconfig.json) holding a createVendo() composition and a Node HTTP-to-fetch adapter, plus a starter vendo/ai.ts model module. Two manual wiring steps remain, and init prints both.
  • Any other runtime (Fastify, Hono, Bun): init detects only next and express, so it proposes Next-shaped files. Decline those diffs and mount vendo.handler yourself (see below). Detection checks next first, 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:
Wrap the client root in <VendoRoot>:

Composition

The generated vendo/server.ts calls createVendo once during boot:
Replace 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, mount vendo.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, not req.url, when mounted with app.use on a base path (Express strips the mount path from req.url).
  • Keep cookie and authorization headers available to principal(request) and to present-mode same-origin tool calls.
  • Return multi-value Set-Cookie as a header array, not a joined string.
Set 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

Run vendo doctor against the running server:
For an Express host it checks that the server composes 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

Pass createStore({ url }) to use hosted Postgres for multi-process or serverless deployments. The default is PGlite at .vendo/data.