Skip to main content
This walkthrough mirrors examples/mastra-agent in the repo: the unmodified create-mastra weather-agent starter, fronted with Next.js per Mastra’s own guide (@mastra/ai-sdkuseChat + AI SDK UI), plus four touches (~60 lines). Every Vendo line in the example sits inside --- vendo: / --- /vendo comment fences. Read the overview first for the tool pack and envelope contract. The frontend here is identical to the AI SDK example: the embed contract is framework-agnostic.

Touch 1: the Vendo composition

One createVendo call with the cautious policy and two host actions: get_weather (risk read, so generated apps can query live data) and the deliberately risky send_trip_report (risk write, which exercises approvals).
The action implementations live in src/lib/vendo-actions.ts (the same open-meteo lookup as the starter’s weatherTool, plus the send action), and their descriptors (name, schema, risk) in .vendo/tools.json, exactly where vendo init extracts them in a real app. The shipped example wraps this call in a small composeVendo(overrides) helper so its fixture e2e can inject a scripted model; the config is what you see above.

Touch 2: the wire route

The stock catch-all route, what vendo init scaffolds. It serves apps and approvals to the embeds.

Touch 3: the tools spread

The starter’s agent definition gains the pack next to its own weatherTool. vendoMastraTools returns a Promise (the pack enumerates the live registry), which is why the agent uses Mastra’s tools-as-function form:
A Mastra agent definition is static: one definition serves every user, so the shim takes no principal. Each vendo_* call resolves the caller’s principal lazily from Mastra’s request context under the key vendo-principal (exported as VENDO_PRINCIPAL_KEY). A call without one fails closed. The optional vendo-session-id key (VENDO_SESSION_KEY) carries your host session id into Vendo’s audit trail.
The starter scaffolds openai/gpt-5-mini, but multi-turn tool use with GPT-5 reasoning models currently fails on history replay (mastra-ai/mastra#9005). The example pins openai/gpt-4.1-mini, the workaround those issues document.

Touch 4: the principal and the embeds

The chat route is Mastra’s own Next.js guide route with two additions: the caller’s principal set server-side on the RequestContext (never trust the client for identity), and a store warm-up so guarded tools can execute before any wire request has run.
The page is a plain useChat chat wrapped once in VendoProvider, handing each finished tool part to <VendoToolResult>. Mastra streams tool calls as dynamic-tool or tool-* parts, so the example matches both:
<VendoToolResult> renders the app embed for vendo/app-ref@1, the approval card for vendo/approval-ref@1, and nothing for plain data, like the starter’s own weatherTool output.

Run it

App generation resolves its own model independently: an explicit createVendo({ model }) wins, otherwise Vendo walks the dev-mode credential ladder. Two models, deliberately: your agent keeps its model; Vendo’s model seam powers generation and the delegate.

The demo script

  1. “What’s the weather in Paris?” The starter’s own weatherTool, untouched.
  2. “Make me a dashboard comparing weather in Paris, Tokyo and NYC.” The agent calls vendo_create_app; the app builds live inline in the chat.
  3. “Email the report to ops@example.com.” vendo_send_trip_report parks on the cautious policy; an approval card renders inline; approving executes the parked call in place.
A generated weather comparison dashboard rendered inline in the Mastra starter's chat

Step 2 in the Mastra chat: the generated weather dashboard, live inside VendoAppEmbed, querying the registered host action for real data.

Tests

The example ships a hermetic fixture e2e (examples/mastra-agent/e2e/vendo-seam.e2e.test.ts): a real Mastra agent turn through the pack, the approval park → wire approve → execute round trip, the app-ref envelope from a real generation, delegation, and the fail-closed principal check. Scripted models and a temp store, so no keys are needed. Run it with pnpm test in the example.