Skip to main content
Keep your loop. Vendo adds the guarded tools and renders what they return. The setup command is the same npx vendo init as every path: it reads your repo, asks how people will use your agent, and writes the wiring. Step 1 runs it.
1

Spread the tools in

The pack takes the caller you already resolved, so it is built inside the handler. Spread it beside your own tools.Already ran vendo init? It installed ai and your model provider, but never @ai-sdk/react — add that one, then pick up at the lib/vendo.ts below.
No pins needed. Vendo speaks both live AI SDK majors, so ai@6 and ai@7 are each supported — keep the pair together (ai@7 with @ai-sdk/*@4, ai@6 with @ai-sdk/*@3), which is what a bare install gives you.vendo doctor checks the ai major and nothing else: it reports E-DEP-001 when ai falls outside that pair. It never inspects @ai-sdk/anthropic, so a @ai-sdk/* major that drifts out of step with ai passes doctor clean — keep that pin matched by hand.Answer the first question with Through my own agent loop (AI SDK / Mastra), and take Vendo Cloud on the model one. Init writes the wire route and lands a VENDO_API_KEY in .env.local.Init put that createVendo call in lib/vendo.ts already (src/lib/vendo.ts when your app lives under src/), with the wire route a thin handler over it. Export the caller resolver beside it — your chat route, your wire route, and the pack all need the same instance.
lib/vendo.ts
Every snippet on this track imports those two from there. Swap authJs() for your own provider’s preset — Auth lists all five.No provider yet? Then init wrote a demo principal in place of a preset, and the resolver you export beside it hands your chat route that same subject:
lib/vendo.ts
Both sides have to resolve the SAME subject. Your loop and the wire route the embeds call are two different requests, and an app or approval created under one subject is invisible to a surface asking as another — the embed then polls a screen it will never be shown. Everything below stays as written: the demo resolver never returns null, so the 401 guard simply never fires.
AI SDK · app/api/chat/route.ts
That system line is yours and stays yours — Vendo assembles nothing into it, and a turn that loses it answers like a different product. The section at the bottom of this page is what you ADD to it.
Mastra · src/mastra/agents/your-agent.ts
Every tool lands under a vendo_ prefix, so nothing collides with a tool of your own.Pass include or exclude to trim the pack by final tool name, exact match.
One Mastra definition serves every user, so its pack reads the caller off RequestContext per call instead. Mastra has that route.
2

Render the embeds

Vendo calls arrive in your chat as dynamic-tool parts. Hand the finished ones to <VendoToolResult>, anywhere under one provider.
app/page.tsx

Plain data

no envelopeYour model reads the result and answers in words.

App ref

vendo/app-ref@1A live app builds inline, streamed over the wire.

Approval ref

vendo/approval-ref@1An approve or deny card, resolving in place.
One component covers all three, so you never branch on the envelope yourself.
3

See it live

Run your own chat and ask for something behind your API. The answer comes back as a working card, inside your own bubble.
VENDO_BASE_URL in development — init already asked you for it. A vendo_* tool call is a real HTTP request back at your own API, so something has to name the origin to send it to. Vendo learns that origin from requests that reach the wire route init wrote — but on this path the tool runs in your chat route, which is not one of them, so the variable is what names it:
.env.local
An interactive vendo init writes that line from your answer, prefilled with the port your dev script names. If init ran unattended it wrote nothing — add the line with the port your dev server actually prints. Without it, the first tool call comes back with Cannot execute … set VENDO_BASE_URL, or pass baseUrl, and forwarding the caller’s own credentials is refused. Deployments set the same variable in the hosting platform, to the public URL, path prefix included (environment variables).
A host's own chat thread where the assistant's answer is a working comparison screen rendered inside the message

Teach your model when to build UI

Your system prompt is yours, so nothing Vendo assembles reaches it. A tool your model never reaches for is not a feature, so paste this beside whatever you already say about your other tools.
your agent's system prompt
Those slot ids are yours to publish. A <VendoSlot id="…"> from @vendoai/vendo/react is a place in one of your own pages a generated view can occupy — without one, every screen lands in the person’s own list of views. Mount the surface has the component. The same guidance ships to Claude Code as a skill, examples/claude-code-plugin/skills/make-a-screen.
The in-process tool pack carries no vendo_apps_* tool. Teaching your model to pin or unpin a view here buys you an invented tool call that nothing answers.Pinning and unpinning live on the door your own agent connects to, in How the door works.

Where to go next

The pack is in your loop. These three are the rest of this track.

AI SDK

Per-request packs, dynamic-tool parts, one Next.js config line.vendoTools(vendo, { principal })

Mastra

A static definition, the request-context caller, warming the store.VENDO_PRINCIPAL_KEY

Embeds in your chat

The envelope your tools return, and the three embeds that render it.<VendoToolResult output={…} />