Skip to main content
You already run an agent. It has a loop, a model, a system prompt, and a chat UI, and Vendo replaces none of them. What you get is a pack of tools you spread into the tools you already pass your model. If your agent cannot import the package, because it runs in another service, another language, or an MCP client you don’t own, take the MCP door instead. If you have no agent yet, Vendo brings one — harness, model, and chat surface included. Ready to wire it: Quickstart.

The composition

You run createVendo and mount the wire route the same way any Vendo host does. What you leave out is Vendo’s chat loop and chat UI. The wire keeps serving apps, approvals, and connected accounts to the components in your own chat.
Init writes this call for you, inline in the wire route. The quickstart moves it into lib/vendo.ts and exports resolvePrincipal, so your chat route, your wire route, and the tool pack all resolve the caller the same way. If init wired an auth preset instead, it wrote auth in place of principal — the two fill the same seam, and createVendo refuses a config that sets both. Step 2 has each form. Everything init writes is listed on vendo init. Then build the pack per framework:
  • @vendoai/vendo/ai-sdk exports vendoTools(vendo, { principal }), an AI SDK ToolSet for streamText and generateText. Built per request, because tool execution needs a principal-scoped context.
  • @vendoai/vendo/mastra exports vendoMastraTools(vendo), the same pack in Mastra’s createTool shape. A Mastra agent definition is static, so the principal rides the request context instead.
Both return a Promise. Underneath they are the same framework-neutral pack, so the rest of this page holds either way.

What’s in the pack

Every tool is namespaced vendo_*, so nothing collides with a tool of your own. A host action called host_x ships as vendo_host_x. include and exclude trim the pack by final tool name, exact match. Leave include unset and you get everything; exclude wins over include. The in-process pack carries no vendo_apps_* tool. Moving a view your agent already made is done from your own code with the app id, not from the loop.

One principal, two places

Apps and approvals belong to a principal. Your chat turn creates them as whoever your loop passed: vendoTools(vendo, { principal }) on AI SDK, the request-context entry on Mastra. The components in your chat read them back through the wire route, as whoever that route’s principal resolves. If those two disagree, everything the agent makes is invisible to the person looking at it. The app embed polls “pending” forever while the agent reports success. Resolve both from the same session, and never take a principal from the client. Auth presets and the principal seam: Auth.

Approvals don’t block you

A guarded call that needs approval doesn’t throw and doesn’t stall the loop. The tool returns an approval ref immediately, so your model reads “pending, the person has to approve this”. The real call parks server-side. When the person approves in <VendoApprovalEmbed>, the wire runs it and the card resolves in place. Deny throws the parked call away. Parked calls expire on a sweep, 60 minutes by default: createVendo({ guard: guard({ approvals: { parkedCallTtlMs } }) }), where 0 means never. Your agent finds out on some later turn if it matters. The envelope contract and the three components that render it live on Embeds and envelopes.

Teaching your agent to use it

The system-prompt block that teaches a model when a screen beats a paragraph, and what the vendo_make receipt does and does not let it say, is on Instructions. How the view gets built, checked, and placed in a slot is on Generated UI.

Where the guard sits

Every call runs as the signed-in person, through the same guard-bound registry Vendo’s own surfaces use. Host actions reach your routes through the actAs seam, so no agent bearer token is ever forwarded and no credential is duplicated. Generated views render in an iframe with connect-src 'none', so a view reaches no host tool directly; its interactions ride the wire back through the guard, never through your loop. Full picture: Tools and safety.

Next

Quickstart

Five steps: init, one spread, one component, first screen.

AI SDK notes

Per-request builds, dynamic-tool parts, and the Next.js bundler line.

Mastra notes

Static agent definitions, the request-context principal, the model pin.

Embeds and envelopes

The envelope a vendo_* tool returns, and what renders it.