> ## Documentation Index
> Fetch the complete documentation index at: https://smithers.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# <Approval>

> Durable human approval; persists ApprovalDecision, selection, or ranking.

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Approval, approvalDecisionSchema } from "smithers-orchestrator";

type ApprovalProps = {
  id: string;
  mode?: "approve" | "select" | "rank"; // default "approve"
  options?: ApprovalOption[]; // required for select/rank
  output: z.ZodObject | Table | string;
  outputSchema?: z.ZodObject; // default: mode-appropriate schema (approve→approvalDecisionSchema, select→approvalSelectionSchema, rank→approvalRankingSchema); or the output schema itself when output is a ZodObject
  request: { title: string; summary?: string; metadata?: Record<string, unknown> };
  onDeny?: "fail" | "continue" | "skip"; // default "fail"
  allowedScopes?: string[];
  allowedUsers?: string[];
  autoApprove?: {
    after?: number; // auto-approve after N consecutive manual approvals
    condition?: (ctx: WorkflowContext) => boolean;
    audit?: boolean;
    revertOn?: (ctx: WorkflowContext) => boolean;
  };
  async?: boolean; // unrelated downstream may continue while pending
  dependsOn?: string[];
  needs?: Record<string, string>;
  skipIf?: boolean;
  timeoutMs?: number;
  heartbeatTimeoutMs?: number;
  heartbeatTimeout?: number;
  retries?: number;
  retryPolicy?: { backoff?: "fixed" | "linear" | "exponential"; initialDelayMs?: number };
  continueOnFail?: boolean;
  cache?: { by?: (ctx) => unknown; version?: string };
  label?: string;
  meta?: Record<string, unknown>;
  key?: string;
  children?: React.ReactNode;
};
```

Complete runnable example (renders with `bunx smithers-orchestrator graph`). `async` parks the gate without blocking the run: the `deploy` lane waits on the decision through `needs`, while the `update-docs` lane proceeds in parallel.

```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
/** @jsxImportSource smithers-orchestrator */
import { createSmithers, Approval, Parallel, Sequence, ClaudeCodeAgent, approvalDecisionSchema } from "smithers-orchestrator";
import { z } from "zod";

const { Workflow, Task, smithers, outputs } = createSmithers({
  deployApproval: approvalDecisionSchema,
  deploy: z.object({ status: z.string() }),
  docs: z.object({ status: z.string() }),
});

const agent = new ClaudeCodeAgent({ model: "claude-sonnet-5" });

export default smithers(() => (
  <Workflow name="ship">
    <Parallel>
      <Sequence>
        <Approval
          id="approve-deploy"
          async
          output={outputs.deployApproval}
          request={{ title: "Approve production deploy?" }}
        />
        <Task id="deploy" output={outputs.deploy} needs={{ ok: "approve-deploy" }} agent={agent}>
          Deploy to production once the gate is approved.
        </Task>
      </Sequence>
      <Task id="update-docs" output={outputs.docs} agent={agent}>
        Update the changelog. This lane proceeds while approval is pending.
      </Task>
    </Parallel>
  </Workflow>
));
```

## Notes

* `mode="select"` returns `{ selected, notes }`; `mode="rank"` returns `{ ranked, notes }`.
* Deferred and keyed on (run, node, iteration); survives restarts. The operating agent relays the request, gets the decision, and resolves it via `bunx smithers-orchestrator approve`/`deny` (never hand the command to the human).
* For a pre-task pause without persisted decision, use `<Task needsApproval>`.
