# Wiring recipes

Start from the example the bundle installs (`app/agent-workflow/page.tsx` and `app/api/agent-workflow/route.ts`). It runs as is; the steps below replace its demo parts with the app's own.

## The component

```tsx
'use client';
import '@/components/tokens.css';
import { AgentWorkflow } from '@/components/agent-workflow';

<AgentWorkflow
  runId={runId}
  planId={plan.id}
  steps={plan.steps}                                  // [{ id, text }] from the agent
  requestFor={(snapshot) => api('request', { runId, plan: snapshot })}     // server builds + stores the ActionRequest
  verify={(decision) => api('approve', { runId, decision })}              // server returns the receipt id, or throws
  execute={({ serverReceiptId }, report) => streamRun(runId, serverReceiptId, report)} // server runs, sends redacted frames
  onEvent={(e) => api('log', { runId, event: e })}    // the host's log of the run
/>
```

`execute` starts only after `verify` resolves. `report` takes `{ state, statusText, steps, cost? }`; each step has `{ id, label, status, planStepId, toolCalls? }`.

## Next.js App Router: the server side

```ts
// app/api/agent-workflow/route.ts
import { createApprovalStore, redactTrace } from '@/lib/agent-workflow-host';

const store = createApprovalStore(); // demo: in memory. Replace with the app's database.

// request: build the ActionRequest from the accepted plan on the server; store.issue(runId, request)
// approve: store.verify(runId, decision, personFromSession(req)); 409 with the reason when it is refused
// run:     store.check(runId, serverReceiptId) again; 403 when it is null; then run the agent
//          and send each frame through redactTrace before it leaves the server
```

To back the store with a database, keep the same checks: the stored request's id and version must match the decision, the outcome is `granted`, the args were not edited in the browser, one grant per version, and the person comes from the session.

## The app's agent

- **AI SDK tool approval.** When a tool needs approval, build the `ActionRequest` from the tool name and input on the server, and resume the tool call only once `store.check` passes for that request version.
- **A queue or worker.** Write the receipt id with the job. The worker calls `check` before it acts and refuses the job when the receipt is gone or the request version moved.
- **Streaming frames.** Server-sent events or a websocket both work. Redact each frame on the server, then call `report(frame)` in the browser.

## Vite with React and its own API server

The component and the contract are framework-free React. Install with `"rsc": false` in `components.json`, render `AgentWorkflow` in any page, and put the three server operations (request, approve, run) in the existing API server (Express, Hono, Fastify). `lib/agent-workflow-host.ts` has no Next.js import; only the example route does.

## Theming

Add one new CSS file, import it after `tokens.css`, and map the app's tokens:

```css
:root {
  --ah-font: var(--font-sans);
  --ah-ink: var(--foreground);
  --ah-bg: var(--background);
  --ah-line: var(--border);
  --actor-human-accent: var(--primary);
}
.dark { /* the same variables for dark mode, when the app switches with a class */ }
```

`tokens.css` switches dark mode on `[data-theme='dark']`. If the app uses `.dark`, set the dark values under `.dark` in your file.
