Skip to main content
npx vendo doctor --json is the install gate. It prints one JSON object; each check carries a stable id, and every failing or warning check carries an error_code from the registry below plus a fix_ref URL that anchors into this page. Exit 0 means no broken checks: that is the definition of installed. Warnings do not block. The remediation loop: run doctor, open the fix_ref for each non-ok check, apply the fix, run doctor again. Repeat until exit 0. Doctor probes the wire at http://localhost:3000/api/vendo by default; override with --url <base> or VENDO_URL. In --json mode doctor never starts the dev server itself: start it yourself before running the live checks.

Wiring

E-WIRE-001

Symptom: Express server is not wired with createVendo from @vendoai/vendo/server. Cause: Doctor scanned the repo’s source files and found none that imports @vendoai/vendo/server and calls createVendo(. The composition module is missing or imports from the wrong specifier. Fix: Run npx vendo init; it scaffolds vendo/server.ts (or server.mjs) with the composition. If you composed by hand, make sure the file imports from @vendoai/vendo/server and calls createVendo({...}).

E-WIRE-002

Symptom: Express client is not wrapped in <VendoRoot>. Cause: No source file contains a <VendoRoot element. The client half of the wiring was never pasted. Fix: In the client entry, wrap the app:
vendo init prints these exact lines with resolved paths for your repo.

E-WIRE-003

Symptom: Missing app/api/vendo/[...vendo]/route.ts. Cause: The Next.js catch-all handler does not exist at app/api/vendo/[...vendo]/route.ts or src/app/api/vendo/[...vendo]/route.ts. Fix: Run npx vendo init; it scaffolds the route wired to the registry. Do not mount the handler anywhere else; doctor checks these two paths only.

E-WIRE-004

Symptom: Root layout is not wrapped in <VendoRoot>. Cause: Neither app/layout.tsx nor src/app/layout.tsx contains a <VendoRoot element. Fix: In the root layout, wrap {children}:
vendo init prints these lines with the import paths resolved for your repo.

E-WIRE-005

Symptom: @vendoai/vendo (or the vendoai alias) is not declared. Cause: Neither package appears in package.json dependencies or devDependencies. Fix: npm install vendoai (a thin alias of @vendoai/vendo; either name works and both ship the vendo bin).

Config files

E-CFG-001

Symptom: A required .vendo/ file is missing; the message names it, one of tools.json, overrides.json, policy.json, brief.md, theme.json. Cause: vendo init was never run in this directory, or the file was deleted. Fix: Run npx vendo init; it recreates missing .vendo/ files and never overwrites existing ones. A missing tools.json alone can also be regenerated with npx vendo sync.

E-CFG-002

Symptom (warning): .vendo/data/.gitignore is missing. Cause: The gitignore that keeps the local PGlite store out of version control was deleted, so .vendo/data/ contents could get committed. Fix: Run npx vendo init, or create .vendo/data/.gitignore containing:

Ejected UI

E-UI-001

Symptom (warning): An ejected surface came from an older @vendoai/ui than the one installed. Cause: You ejected a chrome surface, then upgraded @vendoai/ui. The ejected pixels are your code, so nothing is broken; only newer presentation is missed. Fix: Review the release notes and run npx vendo eject <surface> --force if you want the new presentation. Leaving it is also valid; this never blocks doctor.

Dev server

E-DEV-001

Symptom (warning): The dev server could not be started for the probe. Cause: Interactive doctor offered to start the dev server (run dev via your package manager) and /status never answered within the startup window. Fix: Start the dev server yourself (for example npm run dev), wait until it serves, and re-run vendo doctor. If the app listens on a non-default port or mount, pass --url <base> or set VENDO_URL. Note: --json runs never attempt the start; agents own the dev server.

Live composition

E-LIVE-001

Symptom: /status returned an invalid composition response. Cause: Something answered at <base>/status but not with the Vendo status shape (posture, version, blocks). Usually another handler owns the path, the mount is wrong, or the base URL points at the wrong app. Fix: Confirm the Vendo handler is mounted at the probed base (Next: app/api/vendo/[...vendo]/route.ts; Express: app.use("/api/vendo", mountVendo())) and that --url/VENDO_URL points at it.

E-LIVE-002

Symptom: /status is unreachable. Cause: Nothing is listening at the probed base: the dev server is not running, or it runs on a different port than the probe target. Fix: Start the dev server and re-run doctor. The default probe base is http://localhost:3000/api/vendo; override with --url <base> or VENDO_URL. All live checks (auth probes, model turn) depend on this one.

E-LIVE-003

Symptom: /status returned an invalid execution venue. Cause: blocks.sandbox in the status response is not one of the known venues (e2b, cloud, custom), false, or absent. The status route is patched or the composition is corrupted. Fix: Remove any custom /status handling and upgrade @vendoai/vendo so the stock status route answers.

E-LIVE-004

Symptom (warning): No execution venue is configured. Cause: The composition has no sandbox adapter, so user apps that need a server (anything beyond tree-only rendering) return sandbox-unavailable. Tree-only apps still work. Fix: One of: install the e2b package and set E2B_API_KEY; set VENDO_API_KEY for the managed Cloud sandbox; or pass sandbox: to createVendo. Ask your human which venue they want; this needs an account or key.

E-LIVE-005

Symptom (warning): The host /status does not report an execution venue. Cause: Version skew: the installed @vendoai/vendo predates the blocks.sandbox field, so the venue check cannot run. Fix: Upgrade: npm install vendoai@latest, restart the dev server, re-run doctor.

Auth probes

E-AUTH-001

Symptom: Present credentials did not reach the host API. Cause: Doctor POSTed <base>/doctor/present with seeded cookie and authorization headers, and they did not come back through the wire’s same-origin fetch. The wire does not trust the origin it is being probed on, so it strips credentials instead of forwarding them. Fix: Set VENDO_BASE_URL to the running host origin (for example VENDO_BASE_URL=http://localhost:3000 in .env.local), restart the dev server, and re-run doctor.

E-AUTH-002

Symptom: The present credential probe is unreachable. Cause: /status answered but <base>/doctor/present threw: the dev server died mid-run or a proxy blocks the doctor routes. Fix: Restart the dev server, verify VENDO_BASE_URL, and re-run doctor.

E-AUTH-003

Symptom: The present credential probe cannot run while the dev server is down. Cause: Follows from a failed /status round-trip; see E-LIVE-002. Fix: Start the dev server at the probed base and re-run doctor; this check runs once /status answers.

E-AUTH-004

Symptom: actAs mint + host verification failed. Cause: The composition minted an away credential but the host did not verify it. The verifier middleware is missing, or the secret the preset signs with differs from the one the host verifies with. Fix: Check createVendo({ auth }) (or the hand-wired actAs), its verifier middleware on the host API, and the host principal resolver. For Clerk/Auth0, VENDO_AWAY_TOKEN_SECRET must be the same value on both sides. See Host auth.

E-AUTH-005

Symptom: The actAs probe is unreachable. Cause: /status answered but <base>/doctor/act-as threw. Fix: Restart the dev server, check createVendo({ actAs }) (or the auth preset), and re-run doctor.

E-AUTH-006

Symptom: The actAs probe cannot run while the dev server is down. Cause: Follows from a failed /status round-trip; see E-LIVE-002. Fix: Start the dev server at the probed base and re-run doctor.

E-AUTH-007

Symptom (warning): actAs is not configured. Cause: The composition has neither an auth preset nor an actAs seam, so the agent cannot act through the host API while the user is away. Present (user-in-the-room) calls still work. Fix: Wire an auth preset (auth: authJs() and friends fill actAs) or pass createVendo({ actAs }) before enabling away host actions. Acceptable to leave for a present-only install; this never blocks doctor.

MCP door

These checks run only when the composition reports blocks.mcp: true.

E-MCP-001

Symptom: MCP protected-resource metadata did not resolve. Cause: GET <origin>/.well-known/oauth-protected-resource<mount>/mcp did not return a JSON object with a resource string. The metadata is path-inserted (RFC 9728): a door at /api/vendo/mcp serves /.well-known/oauth-protected-resource/api/vendo/mcp. Fix: Make sure the composition passes mcp: true with a working auth/oauth seam, the .well-known route is reachable at the origin (not swallowed by a proxy or middleware), and the probed --url matches the real mount.

E-MCP-002

Symptom: MCP authorization-server metadata did not resolve. Cause: GET <origin>/.well-known/oauth-authorization-server<mount>/mcp did not return a JSON object with an issuer string. Fix: Same as E-MCP-001: the two documents are served by the same door wiring; check the oauth adapter configuration.

E-MCP-003

Symptom: The MCP server card did not parse. Cause: GET <origin>/.well-known/mcp/server-card.json did not return an object with a name string and a transports array. Fix: Check that the door’s well-known routes are mounted at the origin and nothing rewrites the card response.

E-MCP-004

Symptom: server.json does not meet MCP registry discovery requirements; the message lists the exact validation errors. Cause: The repo has a server.json (the official MCP registry artifact) that fails schema validation. Fix: Regenerate it: npx vendo mcp server-json --domain <domain> --url <public-mcp-url> --force, or fix the listed fields by hand.

E-MCP-005

Symptom: The server.json remote does not match the live MCP door. Cause: The remote URL declared in server.json differs from the door doctor just probed; the file predates a URL or mount change. Fix: Regenerate server.json with the current public door URL: npx vendo mcp server-json --domain <domain> --url <public-mcp-url> --force.

E-MCP-006

Symptom: server.json is invalid JSON. Cause: The file does not parse. Fix: Regenerate it with npx vendo mcp server-json (see E-MCP-004) or repair the syntax.

E-MCP-007

Symptom: The local MCP registry auth challenge is malformed. Cause: public/.well-known/mcp-registry-auth exists but does not start with v=MCPv1. Fix: Regenerate the domain-verification material: npx vendo mcp verify-domain --domain <domain> --key-out <path> --write-well-known public.

E-MCP-008

Symptom: The live MCP registry auth challenge is malformed. Cause: GET <origin>/.well-known/mcp-registry-auth serves content that does not start with v=MCPv1, usually a stale or hand-edited deployed copy. Fix: Redeploy the file generated by npx vendo mcp verify-domain (see E-MCP-007); DNS verification is an alternative to serving it over HTTP.

Machine schedules

E-SCHED-001

Symptom (warning): Apps declare vendo.json schedules but no schedule caller is configured. Cause: At least one machine-bearing app’s vendo.json declares a schedule, but VENDO_TICK_SECRET is not set, so nothing can hit the authenticated POST /api/vendo/tick surface and the schedules never fire. Fix: Set VENDO_TICK_SECRET to a random secret in the server environment, then point any external cron — Vercel cron, a GitHub Actions schedule, or crontab — at POST <base>/tick with the header Authorization: Bearer $VENDO_TICK_SECRET. Every hit fires due schedules exactly once per cron window; a double-hit is a safe no-op.

Live model turn

E-TURN-001

Symptom: The live model turn did not answer; the message names the credential used and the error. Cause: Doctor POSTed one real turn to <base>/threads and no reply text arrived: no usable model credential, a provider error, or a timeout (90s). Fix: Check the credential the message names. With no key set, add ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_GENERATIVE_AI_API_KEY to .env.local (with the matching @ai-sdk/* provider installed), or use a free Vendo Cloud dev key: vendo cloud login stores the session, then re-run vendo init so its cloud step mints the key into .env.local (ask your human first). Then restart the dev server and check its logs for the turn error.

E-TURN-002

Symptom: The live model turn cannot run while the dev server is down. Cause: Follows from a failed /status round-trip; see E-LIVE-002. Fix: Start the dev server at the probed base and re-run doctor.

Vendo Cloud

E-CLOUD-001

Symptom (warning): VENDO_API_KEY is set but not usable. Cause: The key fails the local shape check (expected vnd_ + 40 hex characters). Doctor never validates keys against a server; a well-formed but revoked key surfaces on the first real service call instead. Fix: Re-copy the key from the Vendo Cloud console, or mint a fresh one: vendo cloud login, then re-run vendo init so its cloud step writes the minted key to .env.local (ask your human first). Unsetting VENDO_API_KEY also clears the warning; Cloud is optional.