> For the complete documentation index, see [llms.txt](https://docs.frayme.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.frayme.ai/agent-frameworks/mastra.md).

# Mastra

Register Frayme's compose tool on a Mastra agent so it can generate live, interactive UI whenever an interface serves the user better than prose.

## The one tool definition

`@frayme/api/tools` ships a single, framework-neutral tool definition. Its schema is Zod v4 (Standard Schema), which Mastra's `createTool` accepts as `inputSchema` directly — no conversion, no re-authoring.

```bash
npm i @frayme/api @frayme/runtime @mastra/core
```

```ts
// src/mastra/tools/frayme.ts
import { createTool } from '@mastra/core/tools';
import Frayme from '@frayme/api';
import { createComposeTool } from '@frayme/api/tools';

const frayme = new Frayme({ apiKey: process.env.FRAYME_API_KEY });

// Binds the definition to your client: execute() performs a non-streaming
// compose and resolves with the validated result.
const compose = createComposeTool(frayme);

export const fraymeCompose = createTool({
  id: compose.name, // 'frayme_compose'
  description: compose.description,
  inputSchema: compose.inputSchema,
  outputSchema: compose.outputSchema,
  execute: async ({ context }) => compose.execute(context),
});
```

The definition carries everything the model needs — the full compose contract (`prompt`, `data`, `actions`, `ui_type`, …), the 8-verb interaction vocabulary, and three worked call examples — inside its `description` and schema. You do not write any prompt text about how to call Frayme.

## A minimal agent

```ts
// src/mastra/agents/ui-agent.ts
import { Agent } from '@mastra/core/agent';
import { fraymeCompose } from '../tools/frayme';

export const uiAgent = new Agent({
  name: 'ui-agent',
  instructions:
    'When an interface serves the user better than prose — a form, dashboard, ' +
    'table, confirmation — call frayme_compose. Pass every fact the UI must ' +
    'show in `data`. Never print the returned spec as text.',
  model: 'your-provider/your-model', // any model Mastra supports — your choice
  tools: { fraymeCompose },
});
```

```ts
// anywhere on your server
const result = await uiAgent.generate('A signup form: name, work email, Create account button.');

// The compose result rides the tool-result channel:
const toolResult = result.toolResults.find((r) => r.toolName === 'fraymeCompose');
const { spec, generation_id } = toolResult.result;
```

## Rendering the returned spec

Ship `spec` to your front-end (as JSON — it is a plain json-render document) and render it:

```tsx
'use client';
import { FraymeRenderer } from '@frayme/runtime/react';
import '@frayme/runtime/styles.css';

<FraymeRenderer
  spec={spec}
  skipValidation // the API already validated before billing
  onDynamicAction={(e) => {
    // { action, event, params, state, generation_id } — a declared action fired.
    // Feed it back to your agent to continue the journey.
  }}
/>;
```

Most interactions (typing, tabs, sorting supplied data) resolve locally in the renderer — only actions you declared in the compose call reach `onDynamicAction`.

## Closing the loop

Register the round-trip tool too, so a user interaction recomposes the UI in context:

```ts
import { createActionTool } from '@frayme/api/tools';

const action = createActionTool(frayme);

export const fraymeAction = createTool({
  id: action.name, // 'frayme_action'
  description: action.description,
  inputSchema: action.inputSchema,
  outputSchema: action.outputSchema,
  execute: async ({ context }) => action.execute(context),
});
```

Forward the `onDynamicAction` event to your agent verbatim (`{ action, event, params, state, generation_id }`); the agent calls `frayme_action` with it and gets back a new validated spec that preserves the state the user already entered.

{% hint style="info" %}
Streaming to the browser: Mastra is on the AG-UI integrations matrix. To stream specs live instead of delivering the final result, use the [AG-UI adapter](/agent-frameworks/ag-ui.md) — the spec travels as `frayme:spec` custom events and actions return via the `frayme:action` frontend tool.
{% endhint %}

## Next steps

* [@frayme/api reference](/sdk-reference/api.md) — `compose.stream()` if you want progressive rendering
* [@frayme/runtime reference](/sdk-reference/runtime.md) — full renderer props
* [AG-UI](/agent-frameworks/ag-ui.md) — streaming transport for Mastra front-ends


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.frayme.ai/agent-frameworks/mastra.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
