> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vendo.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview: the tool pack

> What Vendo hands an agent you already run: a namespaced pack of guarded tools, live micro-apps in your own chat, and approvals that never block the loop.

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.

| Stays yours                            | Comes from Vendo                               |
| -------------------------------------- | ---------------------------------------------- |
| the loop, the model, the system prompt | one tool per host action, guard-wrapped        |
| your chat UI and its message rendering | `vendo_make`, which builds live views          |
| your auth and your API                 | `vendo_delegate`, which hands off a whole task |

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](/mcp/quickstart)
instead. If you have no agent yet, [Vendo brings one](/vendo-agent/quickstart) — harness,
model, and chat surface included.

Ready to wire it: [Quickstart](/existing-agents/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.

```ts theme={null}
// lib/vendo.ts
import { createVendo, guard } from "@vendoai/vendo/server";

// the function init wrote — swap in your real session lookup
export const resolvePrincipal = async (req: Request) =>
  ({ kind: "user" as const, subject: "demo-user" });

export const vendo = createVendo({
  guard: guard({ policy: "cautious" }),
  principal: resolvePrincipal,
});
```

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](/existing-agents/quickstart#2-share-one-instance) has each form.
Everything init writes is listed on [vendo init](/reference/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`.

| Tool                  | What it does                                                                                                                    |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `vendo_<your action>` | one per registered host action, guard-wrapped per call                                                                          |
| `vendo_make`          | builds a live view; returns an app ref right away while the build streams over the wire, so your loop never waits on generation |
| `vendo_delegate`      | hands Vendo's own agent a whole task; returns `{ status, summary, refs }`                                                       |

`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](/deploy/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](/existing-agents/embeds).

## 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](/customize/instructions). How the view gets built, checked, and
placed in a slot is on [Generated UI](/capabilities/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](/concepts/tools-and-safety).

## Next

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/existing-agents/quickstart">
    Five steps: init, one spread, one component, first screen.
  </Card>

  <Card title="AI SDK notes" icon="https://mintcdn.com/vendo/WqTf_4moowoLY5gp/images/logos/vercel.svg?fit=max&auto=format&n=WqTf_4moowoLY5gp&q=85&s=3f20adfd29a7ede6e0fa4d67a8ee6ad1" href="/existing-agents/ai-sdk" width="256" height="222" data-path="images/logos/vercel.svg">
    Per-request builds, `dynamic-tool` parts, and the Next.js bundler line.
  </Card>

  <Card title="Mastra notes" icon="https://mintcdn.com/vendo/WqTf_4moowoLY5gp/images/logos/mastra.svg?fit=max&auto=format&n=WqTf_4moowoLY5gp&q=85&s=c691df53e88f3713090ea2191c39c28e" href="/existing-agents/mastra" width="1000" height="1000" data-path="images/logos/mastra.svg">
    Static agent definitions, the request-context principal, the model pin.
  </Card>

  <Card title="Embeds and envelopes" icon="code" href="/existing-agents/embeds">
    The envelope a `vendo_*` tool returns, and what renders it.
  </Card>
</CardGroup>
