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

# Mastra

> Spread Vendo's guarded tool pack into a Mastra agent you already run, and render what it returns in your own chat.

Keep your agent. Vendo adds the guarded tools and renders what they return.

<Note>
  This page picks up inside an app you already have: a Next.js App Router
  project with a Mastra `Agent`, a chat route that invokes it, a React chat that
  renders the parts, and your own sign-in. On that path init writes
  `lib/vendo.ts` — the composition the steps below import. A project init reads
  as a custom runtime gets `vendo/server.mjs` instead, and these imports will not
  resolve. No app yet? [Vendo's full-stack agent](/product/quickstart) scaffolds
  the whole surface.
</Note>

<Steps>
  <Step title="Install and run init">
    <CodeGroup>
      ```bash npm theme={null}
      npm install @vendoai/vendo @mastra/core
      npx vendo init
      ```

      ```bash pnpm theme={null}
      pnpm add @vendoai/vendo @mastra/core
      pnpm exec vendo init
      ```
    </CodeGroup>

    `@mastra/core` is an optional peer, so it is not pulled in for you — step 2 imports `Agent` from it.

    Answer the first question with **Through my own agent loop (AI SDK / Mastra)**, and take **Vendo Cloud** on the model one. Init asks four things in all and takes a few minutes; [`vendo init`](/reference/vendo-init) covers them. Two matter here: the URL your app serves in dev, which becomes `VENDO_BASE_URL`, and whether a coding agent may read your source to draft tool descriptions and your product brief — **Skip — keep extractor defaults** if you would rather send nothing. Extraction also needs `typescript` 4.9 or newer in the project; without it init finds zero tools.
  </Step>

  <Step title="Spread the tools into your agent">
    `vendoMastraTools` is async, so the agent takes the tools-as-function form. Tools arrive under a `vendo_` prefix; `include` and `exclude` trim the pack.

    ```ts src/mastra/agents/your-agent.ts focus={2,10} theme={null}
    import { Agent } from "@mastra/core/agent";
    import { vendoMastraTools } from "@vendoai/vendo/mastra";
    import { vendo } from "@/lib/vendo";

    export const yourAgent = new Agent({
      id: "your-agent",
      name: "your-agent",
      instructions: "…your system prompt as it is",
      model: "openai/gpt-4.1-mini", // your model, unchanged
      tools: async () => ({ ...yourTools, ...(await vendoMastraTools(vendo)) }),
    });
    ```

    Your agent keeps thinking on your own model. The **Vendo Cloud** key you took in step 1 pays for *Vendo's* turns — app generation, `vendo_delegate` — not your loop's. With no model key of your own, point Mastra at the Cloud gateway instead:

    ```ts theme={null}
    import { createAnthropic } from "@ai-sdk/anthropic";

    const model = createAnthropic({
      apiKey: process.env.VENDO_API_KEY,
      baseURL: `${process.env.VENDO_CONSOLE_URL ?? "https://console.vendo.run"}/api/v1`,
    })("vendo");
    ```
  </Step>

  <Step title="Hand the caller to the route">
    ```ts app/api/chat/route.ts theme={null}
    import { RequestContext } from "@mastra/core/request-context";
    import { VENDO_PRINCIPAL_KEY } from "@vendoai/vendo/mastra";
    import { resolvePrincipal } from "@/lib/vendo";

    // in your existing POST handler, before you invoke the agent:
    const caller = await resolvePrincipal(req);
    if (!caller) return new Response("Unauthorized", { status: 401 });
    const requestContext = new RequestContext();
    requestContext.set(VENDO_PRINCIPAL_KEY, caller);
    params.requestContext = requestContext;
    ```

    One agent definition serves every user, so the caller travels per request: Vendo's tools read the principal off Mastra's `RequestContext` on every call.
  </Step>

  <Step title="Render the embeds">
    Mastra streams tool calls in two shapes, `dynamic-tool` and `tool-<name>`. `isVendoToolPart` covers both.

    ```tsx components/vendo-part.tsx focus={5-8} theme={null}
    import { getToolName, type UIMessage } from "ai";
    import { isVendoToolPart, VendoToolResult } from "@vendoai/vendo/react";

    export function VendoPart({ part }: { part: UIMessage["parts"][number] }) {
      if (!isVendoToolPart(part)) return null; // your own parts render elsewhere
      return part.state === "output-available"
        ? <VendoToolResult output={part.output} />
        : <span>Running {getToolName(part)}…</span>;
    }
    ```

    Nothing to wrap: the embed finds the wire at `/api/vendo` and rides your host session cookie. The guard narrows the part, so `state` and `output` typecheck. One component covers data, apps, and approvals — [Embeds in your chat](/existing-agent/embeds) has the full contract.
  </Step>

  <Step title="See it live">
    Start your app and ask your agent for something behind your API. The tool call runs under the guard and the answer comes back as a working card inside your own chat bubble.

    Init wrote `VENDO_BASE_URL` into `.env.local`; deployments set the same variable to their public origin, path prefix included — see [environment variables](/reference/environment-variables). Outside dev it has to be `https`: Vendo Cloud refuses to enrol an `http` origin, and scheduled automations will not fire.

    A complete working version of this page is [`examples/mastra-agent`](https://github.com/runvendo/vendo/tree/main/examples/mastra-agent).
  </Step>
</Steps>

## Make it yours

The setup was the same for everyone. These, in order, make it yours.

<CardGroup cols={3}>
  <Card title="Wire auth" icon="key" href="/howto/auth">
    Swap the demo principal for your real sign-in.
  </Card>

  <Card title="Add tools" icon="wrench" href="/howto/tools">
    Point Vendo at your API — the agent gets hands.
  </Card>

  <Card title="Approve actions" icon="shield-check" href="/howto/approvals">
    Decide what runs and what asks first.
  </Card>

  <Card title="Generate screens" icon="wand-magic-sparkles" href="/howto/screens">
    Ask for a view, pin it into your grid.
  </Card>

  <Card title="Theme it" icon="palette" href="/howto/theming">
    Your fonts, colors, and radii on every surface.
  </Card>

  <Card title="Set instructions" icon="file-pen" href="/howto/instructions">
    The brief your agent reads before every turn.
  </Card>
</CardGroup>
