# Durable approvals for long-running agents

Agents now run for minutes or hours, and a person may answer an approval long after the request that asked for it is gone. Candor's adapters keep the approval and the run as data, so neither depends on one browser tab or one server process.

With the Claude Agent SDK, permission requests wait in an ApprovalStore. The default is this process's memory; pass your own (a table, a queue) so any instance can take the answer. claudeCanUseTool works anywhere your agent runs, including a workflow engine: it records the request, waits for the answer, and turns it into what the SDK expects with claudePermissionResult. Answer it from your own route, or from the step that signals your workflow.

A ClaudeRunStore keeps a run's events. With `detach`, the run carries on when the browser goes away; after a reload, useClaudeAgent re-attaches through attachClaudeAgentRun from the run's id. Because the event fold is pure, a finished conversation replays exactly from its stored events (`initialEvents`).

With the Vercel AI SDK, a WorkflowAgent run streams the same UI messages: a tool that needs approval shows as waiting for as long as the workflow waits, and an approval made automatically is marked as one. The AI SDK's own WorkflowChatTransport re-attaches the stream after a reload.

Web page: https://candor.themethodic.com/patterns/durable-agent-approvals

## Components

- **Claude Agent SDK server** (`claude-agent-server`, free; https://candor.themethodic.com/docs/claude-agent-server.md): ApprovalStore, ClaudeRunStore, claudeCanUseTool, attachClaudeAgentRun, stop and the permission mode.
- **Claude Agent SDK** (`claude-agent-sdk`, free; https://candor.themethodic.com/docs/claude-agent-sdk.md): The pure event fold (replay) and claudePermissionResult for an answer that lands anywhere.
- **useClaudeAgent** (`use-claude-agent`, free; https://candor.themethodic.com/docs/use-claude-agent.md): initialEvents, attach after a reload, onRespond for your own route, runId to save.
- **AI SDK** (`ai-sdk`, free; https://candor.themethodic.com/docs/ai-sdk.md): WorkflowAgent's approvals, waiting or automatic, in the same messages.
- **Permission prompt** (`permission-prompt`, free; https://candor.themethodic.com/docs/permission-prompt.md): The waiting request, shown again after a reload.
- **Approval request** (`approval-request`, Pro; https://candor.themethodic.com/docs/approval-request.md): A second person's approval, compact for a phone or a notification (Pro).

## Install

```bash
npx candor-ui add claude-agent-server use-claude-agent permission-prompt
```

## Notes

- A store makes the answer and the record durable, not the agent: the agent still runs in the process that started it. When the process itself mustn't matter, run the agent in your workflow engine with claudeCanUseTool.
- A late answer to a run that already ended is refused, not lost: answering and closing a request each happen once, whichever comes first.
- `detach` needs a process that outlives the response, not a serverless function that's frozen when the response ends. Give it an `approvalTimeoutMs`, so a request nobody answers expires (denied) instead of holding the run for ever.
- Saving the conversation and re-attaching both? Pass the hook's `promptId` to the server's `prompt`: the re-attached run then replaces its own events in `initialEvents` instead of adding them twice.
- Policy lives on the server: `editable` says which tools a person may edit, and `modes` (or `allowed`) which permission modes a run may switch to. The browser can't widen either.
