> 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/sdk-reference/runtime.md).

# @frayme/runtime

Renders Frayme specs as live, interactive React UI — one renderer component, a streaming compose hook, and adapters for AI SDK and AG-UI transports.

```bash
npm i @frayme/runtime
```

ESM, MIT, Node ≥ 20.19, React ≥ 19. Version 0.3.2. The `ai` / `@ai-sdk/react` peers are optional — needed only for the `/ai-sdk` entrypoint.

## Entrypoints

| Entrypoint                   | Environment                        | Key exports                                                                                                                                                                               |
| ---------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@frayme/runtime`            | Server-safe (route handlers, Node) | `composeStreamToDataParts`, `validateFraymeSpec`, `themeToStyle`, `resolveInitialState`, `dispatch`, types (`Spec`, `DynamicActionEvent`, `ThemeTokens`, …)                               |
| `@frayme/runtime/react`      | Client                             | `FraymeRenderer`, `FraymeProvider`, `useFrayme`, `useFraymeCompose`, `createCustomComponents` + the BYOC author kit, `defaultRegistry`, `createRegistry`                                  |
| `@frayme/runtime/ai-sdk`     | Client                             | `FraymeMessageRenderer`, `createDynamicActionForwarder`, `SPEC_DATA_PART_TYPE` — see [Vercel AI SDK](/agent-frameworks/ai-sdk.md)                                                         |
| `@frayme/runtime/ag-ui`      | Client                             | `useFraymeAgUiSpec`, `FraymeAgUiRenderer`, `createAgUiActionForwarder`, `fraymeActionToolDefinition`, `FRAYME_SPEC_EVENT`, `FRAYME_ACTION_TOOL` — see [AG-UI](/agent-frameworks/ag-ui.md) |
| `@frayme/runtime/styles.css` | —                                  | Default styles + the `--frayme-*` theme variables. Import once, anywhere.                                                                                                                 |

Never import a client entrypoint from a route handler — the server-safe bridge (`composeStreamToDataParts`) lives on the root for exactly this reason.

## FraymeRenderer

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

<FraymeRenderer spec={spec} onDynamicAction={(e) => sendToAgent(e)} />;
```

### Props

| Prop                | Type                                 | Description                                                                                                                                                                                                                                                                                                  |
| ------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `spec`              | `Spec \| null`                       | The spec to render — full or streaming snapshot.                                                                                                                                                                                                                                                             |
| `mode`              | `'strict' \| 'progressive'`          | `strict` (default) renders only specs passing the catalog gate. `progressive` renders partial streaming snapshots; the component whitelist + inert fallback is the safety boundary.                                                                                                                          |
| `skipValidation`    | `boolean`                            | Skip the strict-mode catalog re-validation for specs you already trust — e.g. one straight from the API, which was validated server-side before billing. No effect in `progressive` mode.                                                                                                                    |
| `components`        | `ComponentRegistry`                  | Per-instance component overrides, merged over the default registry.                                                                                                                                                                                                                                          |
| `catalog`           | `FraymeCatalogUnion`                 | BYOC: the built-ins ∪ custom-manifests union from `createCustomComponents(...).catalog`, so strict mode accepts custom types.                                                                                                                                                                                |
| `onDynamicAction`   | `(e: DynamicActionEvent) => unknown` | Receives spec-bound named actions — the \~10% of interactions that need your agent.                                                                                                                                                                                                                          |
| `theme`             | `ThemeTokens`                        | Per-instance theme tokens (see [Theming](#theming)).                                                                                                                                                                                                                                                         |
| `restartKey`        | `number`                             | Bump to discard all client state (remounts the state tree). `useFraymeCompose` bumps it automatically on restart.                                                                                                                                                                                            |
| `initialState`      | `Record<string, unknown>`            | Override the initial state (defaults to the spec's embedded `state`).                                                                                                                                                                                                                                        |
| `loading`           | `boolean`                            | Mark the UI as still streaming/loading.                                                                                                                                                                                                                                                                      |
| `actions`           | `string[] \| FraymeActionMap`        | Take full control of action routing. `string[]` is an allow-list; a map assigns each name a `local` / `recompose` / `agent` / `host` kind (or `false` to deny). Passing either makes you the sole router — `spec.actions` is ignored and unmapped names fail closed. Usually omit it and let the spec drive. |
| `defaultActionKind` | `DefaultActionKind`                  | Blanket kind for unmapped actions. Default: fail-closed (inert).                                                                                                                                                                                                                                             |
| `compose`           | `ComposeLike`                        | A compose client (e.g. `frayme.compose`). Enables the `recompose` action kind.                                                                                                                                                                                                                               |
| `onRecompose`       | `(nextSpec, { state }) => void`      | Where a `recompose` result lands — the spec owner's setter.                                                                                                                                                                                                                                                  |
| `hostTransport`     | `HostTransport`                      | Host bridge for the `host` action kind (postMessage surfaces).                                                                                                                                                                                                                                               |
| `interactive`       | `boolean`                            | Defaults to `true` when a handler is present. Set `false` for a display-only UI — controls render but clicks are inert.                                                                                                                                                                                      |
| `className`         | `string`                             | Extra class on the root wrapper.                                                                                                                                                                                                                                                                             |

### DynamicActionEvent

What `onDynamicAction` receives when a declared action fires:

```ts
interface DynamicActionEvent {
  action: string;                      // the bound action name, e.g. "approveRefund"
  params: Record<string, unknown>;     // resolved params (often form state)
  event?: string;                      // canonical verb: commit/select/change/dismiss/search/sort/page/move
  state?: Record<string, unknown>;     // live state snapshot at fire time
  generation_id?: string;              // correlates back to the compose that built this UI
}
```

Static interactions — typing, tabs, filters, sorting data you supplied — resolve entirely in the browser and never reach this seam. Only spec-declared actions do. See [Interactivity](/core-concepts/interactivity.md).

## useFraymeCompose

Frontend-direct streaming compose with restart handling built in:

```tsx
'use client';
import Frayme from '@frayme/api';
import { FraymeRenderer, useFraymeCompose } from '@frayme/runtime/react';

const frayme = new Frayme({ apiKey: null, baseURL: '/api/frayme-proxy' }); // keyless proxy mode

export function Composer() {
  const { compose, spec, status, restartKey, error } = useFraymeCompose(frayme);

  return (
    <>
      <button onClick={() => compose({ prompt: 'A weekly schedule board' })}>Generate</button>
      <FraymeRenderer spec={spec} mode="progressive" restartKey={restartKey} loading={status === 'streaming'} />
      {status === 'error' && <p>{error?.message}</p>}
    </>
  );
}
```

### Returns

| Field                        | Type                                                             | Description                                                                                                                                  |
| ---------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `compose(request, options?)` | `Promise<FinalSpec \| undefined>`                                | Start (or replace) a streaming composition. Resolves with the validated final spec; `undefined` on abort or when a newer call superseded it. |
| `spec`                       | `Spec \| null`                                                   | Live snapshot — render with `mode="progressive"`. Cleared on restart, committed on completion.                                               |
| `status`                     | `'idle' \| 'streaming' \| 'restarting' \| 'complete' \| 'error'` | Stream lifecycle.                                                                                                                            |
| `restartKey`                 | `number`                                                         | Bumps on every restart — pass straight to `<FraymeRenderer restartKey>`.                                                                     |
| `model`                      | `string \| undefined`                                            | Opaque identifier of the model serving the current attempt (changes on restarts).                                                            |
| `error`                      | `FraymeError \| undefined`                                       | Set when `status === 'error'`.                                                                                                               |
| `abort()`                    | `() => void`                                                     | Abort the in-flight stream.                                                                                                                  |

The hook takes an optional client argument; without one it reads `client` from the nearest `FraymeProvider`.

## FraymeProvider

Optional app-level defaults for every renderer beneath it:

```tsx
import { FraymeProvider } from '@frayme/runtime/react';

<FraymeProvider client={frayme} theme={{ primary: '#2563eb' }} onDynamicAction={handleAction}>
  <App />
</FraymeProvider>;
```

Context values: `client` (a keyless proxy-mode client for frontend-direct compose), `theme`, `onDynamicAction`, `components`. Per-instance props on `FraymeRenderer` win over provider values. `useFrayme()` reads the context directly.

## Theming

Ship `@frayme/runtime/styles.css` for the defaults, then override tokens per instance via the `theme` prop or globally in your own stylesheet — every token is a `--frayme-*` CSS variable on the `.frayme-root` wrapper:

```css
.frayme-root {
  --frayme-primary: #7c3aed;
  --frayme-radius: 0.75rem;
}
```

`ThemeTokens` keys: `primary`, `primaryForeground`, `background`, `foreground`, `card`, `cardForeground`, `border`, `muted`, `mutedForeground`, `danger`, `dangerForeground`, `success`, `successForeground`, `warning`, `warningForeground`, `info`, `infoForeground`, `radius`, `fontFamily`. The server-safe `themeToStyle(tokens)` converts a token object to the equivalent inline-style map. Full guide: [Theming](/guides/theming.md).

## Custom components (BYOC)

`createCustomComponents` wraps your own React components so they render inside a spec with the same guarantees as built-ins — gated props, a typed `emit` on the canonical verbs, optional `clientOnly` SSR skeletons:

```tsx
import { createCustomComponents } from '@frayme/runtime/react';

const custom = createCustomComponents([{ manifest: SeatMapManifest, component: SeatMapView }]);

<FraymeRenderer spec={spec} components={custom.registry} catalog={custom.catalog} />;
```

The author kit is exported alongside it: `useLocalOrBound`, `styleVars`, `cn`, `Icon` / `hasIcon` / `ICON_NAMES`, `safeUrl` / `safeImageSrc`, `safeColor` / `safeDimension`. Manifests are authored with [`defineFraymeComponent`](/sdk-reference/catalog.md#byoc-authoring) from `@frayme/catalog`. Full guide: [Custom components](/guides/custom-components.md).


---

# 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/sdk-reference/runtime.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.
