{
  "slug": "pilot/sdk/react",
  "title": "Pilot React SDK",
  "description": "React hooks and components for Cuitty Pilot — manage playbooks, runs, and real-time events in React apps.",
  "url": "https://cuitty.com/docs/pilot/sdk/react",
  "markdown_url": "https://cuitty.com/docs/pilot/sdk/react.md",
  "json_url": "https://cuitty.com/docs/pilot/sdk/react.json",
  "frontmatter": {
    "title": "Pilot React SDK",
    "description": "React hooks and components for Cuitty Pilot — manage playbooks, runs, and real-time events in React apps.",
    "order": 12,
    "section": "Pilot",
    "updatedAt": "2026-06-01"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "pilot-react-sdk",
      "text": "Pilot React SDK"
    },
    {
      "depth": 2,
      "slug": "install",
      "text": "Install"
    },
    {
      "depth": 2,
      "slug": "quick-start",
      "text": "Quick start"
    },
    {
      "depth": 2,
      "slug": "pilotprovider",
      "text": "PilotProvider"
    },
    {
      "depth": 3,
      "slug": "usepilot",
      "text": "usePilot()"
    },
    {
      "depth": 2,
      "slug": "hooks",
      "text": "Hooks"
    },
    {
      "depth": 3,
      "slug": "useplaybooksoptions",
      "text": "usePlaybooks(options?)"
    },
    {
      "depth": 3,
      "slug": "userun",
      "text": "useRun()"
    },
    {
      "depth": 3,
      "slug": "useruneventsrunid",
      "text": "useRunEvents(runId)"
    },
    {
      "depth": 2,
      "slug": "components",
      "text": "Components"
    },
    {
      "depth": 3,
      "slug": "runstatusbadge",
      "text": "RunStatusBadge"
    },
    {
      "depth": 3,
      "slug": "runtimeline",
      "text": "RunTimeline"
    },
    {
      "depth": 3,
      "slug": "playbookcard",
      "text": "PlaybookCard"
    },
    {
      "depth": 2,
      "slug": "error-handling",
      "text": "Error handling"
    },
    {
      "depth": 2,
      "slug": "see-also",
      "text": "See also"
    }
  ],
  "body_markdown": "# Pilot React SDK\n\n`@cuitty/pilot-react` provides React hooks and pre-built components for the Pilot API. It wraps `@cuitty/pilot-sdk` with idiomatic React patterns — context providers, data-fetching hooks, and SSE subscriptions that clean up automatically.\n\n## Install\n\n```bash\nsfw bun add @cuitty/pilot-react\n# or\nsfw npm install @cuitty/pilot-react\n```\n\nPeer dependencies: `react>=18`, `@cuitty/pilot-sdk`.\n\n## Quick start\n\n```tsx\nimport { PilotProvider, usePlaybooks, useRun, useRunEvents } from \"@cuitty/pilot-react\";\n\nfunction App() {\n  return (\n    <PilotProvider baseUrl=\"http://localhost:4320\" auth={{ apiKey: \"pk_...\" }}>\n      <Dashboard />\n    </PilotProvider>\n  );\n}\n\nfunction Dashboard() {\n  const { data: playbooks, loading } = usePlaybooks();\n  const { run, start } = useRun();\n  const events = useRunEvents(run?.id);\n\n  if (loading) return <p>Loading...</p>;\n\n  return (\n    <div>\n      {playbooks?.map((pb) => (\n        <button key={pb.id} onClick={() => start({ playbookId: pb.id, mode: \"autonomous\" })}>\n          {pb.title}\n        </button>\n      ))}\n      {events.map((e, i) => (\n        <div key={i}>{e.type} {e.stepId}</div>\n      ))}\n    </div>\n  );\n}\n```\n\n## PilotProvider\n\nWraps your component tree with a `PilotClient` instance. Accepts all `PilotClientConfig` props plus `children`. The client is recreated when `baseUrl` or `auth.token` change, and closed on unmount.\n\n```tsx\nimport { PilotProvider } from \"@cuitty/pilot-react\";\n\n<PilotProvider\n  baseUrl=\"http://localhost:4320\"\n  auth={{ token: \"ey...\" }}\n  timeout={15000}\n>\n  {children}\n</PilotProvider>\n```\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `baseUrl` | `string` | Pilot server URL |\n| `auth` | `{ token?: string; cookie?: string; apiKey?: string }` | Authentication credentials |\n| `timeout` | `number` | Per-request timeout in ms (default 30000) |\n| `children` | `React.ReactNode` | Child components |\n\n### usePilot()\n\nReturns the `PilotClient` from context. Throws if used outside `<PilotProvider>`.\n\n```tsx\nimport { usePilot } from \"@cuitty/pilot-react\";\n\nconst pilot = usePilot();\nconst health = await pilot.health();\n```\n\n## Hooks\n\n### usePlaybooks(options?)\n\nFetches and caches the playbook list. Re-fetches when options change.\n\n```tsx\nconst { data, loading, error, refetch } = usePlaybooks();\nconst { data: cfOnly } = usePlaybooks({ target: \"cloudflare\" });\n```\n\n| Return | Type | Description |\n|--------|------|-------------|\n| `data` | `PlaybookSummary[] \\| null` | Fetched playbooks, `null` until loaded |\n| `loading` | `boolean` | `true` while fetching |\n| `error` | `Error \\| null` | Fetch error, if any |\n| `refetch` | `() => Promise<void>` | Manually re-fetch the list |\n\n### useRun()\n\nManages a single run lifecycle: start, abort, and refresh.\n\n```tsx\nconst { run, loading, error, start, abort, refresh } = useRun();\n\n// Start a new run\nconst result = await start({\n  playbookId: \"cloudflare.dns.add-a-record\",\n  mode: \"interactive\",\n  inputs: { zone: \"example.com\", record_name: \"api\", ip_address: \"1.2.3.4\" },\n});\n\n// Abort the active run\nawait abort();\n\n// Refresh run state from the server\nawait refresh();\n```\n\n| Return | Type | Description |\n|--------|------|-------------|\n| `run` | `Run \\| null` | Current run object |\n| `loading` | `boolean` | `true` while starting a run |\n| `error` | `Error \\| null` | Error from the last operation |\n| `start(req)` | `(StartRunRequest) => Promise<Run \\| null>` | Start a run and fetch its full details |\n| `abort()` | `() => Promise<void>` | Abort the current run |\n| `refresh()` | `() => Promise<void>` | Re-fetch current run state |\n\n### useRunEvents(runId)\n\nSubscribes to real-time SSE events for a run. Automatically unsubscribes on unmount or when `runId` changes. Returns a growing array of events.\n\n```tsx\nconst events = useRunEvents(run?.id);\n\n// events: RunEvent[]\nevents.forEach((event) => {\n  console.log(event.type, event.stepId);\n});\n```\n\n| Param | Type | Description |\n|-------|------|-------------|\n| `runId` | `string \\| null \\| undefined` | Run ID to subscribe to; `null`/`undefined` pauses subscription |\n\nReturns `RunEvent[]` — accumulates all events received since subscription started.\n\n## Components\n\n### RunStatusBadge\n\nRenders a colored pill badge for a run status.\n\n```tsx\nimport { RunStatusBadge } from \"@cuitty/pilot-react\";\n\n<RunStatusBadge status=\"running\" />\n<RunStatusBadge status=\"completed\" />\n<RunStatusBadge status=\"failed\" />\n```\n\nSupported statuses: `queued`, `running`, `awaiting_approval`, `completed`, `failed`, `aborted`.\n\n### RunTimeline\n\nRenders a vertical timeline of run events with color-coded borders (blue for in-progress, green for complete, red for failures).\n\n```tsx\nimport { RunTimeline } from \"@cuitty/pilot-react\";\n\nconst events = useRunEvents(runId);\n<RunTimeline events={events} />\n```\n\n### PlaybookCard\n\nDisplays a playbook summary card with an optional \"Run\" button.\n\n```tsx\nimport { PlaybookCard } from \"@cuitty/pilot-react\";\n\n<PlaybookCard\n  playbook={playbook}\n  onRun={(pb) => start({ playbookId: pb.id, mode: \"autonomous\" })}\n/>\n```\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `playbook` | `PlaybookSummary` | Playbook to display |\n| `onRun` | `(playbook: PlaybookSummary) => void` | Optional callback when \"Run\" is clicked |\n\n## Error handling\n\nErrors from hooks are captured in the `error` field rather than thrown. For direct `PilotClient` usage via `usePilot()`, catch `PilotApiError` and `PilotConnectionError` from `@cuitty/pilot-sdk`.\n\n```tsx\nimport { PilotApiError, PilotConnectionError } from \"@cuitty/pilot-sdk\";\n\nconst pilot = usePilot();\ntry {\n  await pilot.runs.start({ playbookId: \"nonexistent\" });\n} catch (err) {\n  if (err instanceof PilotApiError) {\n    console.error(`API ${err.status}: ${err.statusText}`, err.body);\n  } else if (err instanceof PilotConnectionError) {\n    console.error(\"Cannot reach Pilot:\", err.message);\n  }\n}\n```\n\n## See also\n\n- [JavaScript SDK](/docs/pilot/sdk/javascript) — underlying `PilotClient` API reference\n- [Playbook reference](/docs/pilot/playbook-reference) — YAML schema for playbook documents\n- [Quickstart](/docs/pilot/quickstart) — record and replay your first workflow",
  "body_html": "<h1 id=\"pilot-react-sdk\">Pilot React SDK</h1>\n<p><code>@cuitty/pilot-react</code> provides React hooks and pre-built components for the Pilot API. It wraps <code>@cuitty/pilot-sdk</code> with idiomatic React patterns — context providers, data-fetching hooks, and SSE subscriptions that clean up automatically.</p>\n<h2 id=\"install\">Install</h2>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"bash\"><code><span class=\"line\"><span style=\"color:#B392F0\">sfw</span><span style=\"color:#9ECBFF\"> bun</span><span style=\"color:#9ECBFF\"> add</span><span style=\"color:#9ECBFF\"> @cuitty/pilot-react</span></span>\n<span class=\"line\"><span style=\"color:#6A737D\"># or</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">sfw</span><span style=\"color:#9ECBFF\"> npm</span><span style=\"color:#9ECBFF\"> install</span><span style=\"color:#9ECBFF\"> @cuitty/pilot-react</span></span></code></pre>\n<p>Peer dependencies: <code>react>=18</code>, <code>@cuitty/pilot-sdk</code>.</p>\n<h2 id=\"quick-start\">Quick start</h2>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { PilotProvider, usePlaybooks, useRun, useRunEvents } </span><span style=\"color:#F97583\">from</span><span style=\"color:#9ECBFF\"> \"@cuitty/pilot-react\"</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#F97583\">function</span><span style=\"color:#B392F0\"> App</span><span style=\"color:#E1E4E8\">() {</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">  return</span><span style=\"color:#E1E4E8\"> (</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    &#x3C;</span><span style=\"color:#79B8FF\">PilotProvider</span><span style=\"color:#B392F0\"> baseUrl</span><span style=\"color:#F97583\">=</span><span style=\"color:#9ECBFF\">\"http://localhost:4320\"</span><span style=\"color:#B392F0\"> auth</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{{ apiKey: </span><span style=\"color:#9ECBFF\">\"pk_...\"</span><span style=\"color:#E1E4E8\"> }}></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">      &#x3C;</span><span style=\"color:#79B8FF\">Dashboard</span><span style=\"color:#E1E4E8\"> /></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    &#x3C;/</span><span style=\"color:#79B8FF\">PilotProvider</span><span style=\"color:#E1E4E8\">></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  );</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#F97583\">function</span><span style=\"color:#B392F0\"> Dashboard</span><span style=\"color:#E1E4E8\">() {</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">  const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#FFAB70\">data</span><span style=\"color:#E1E4E8\">: </span><span style=\"color:#79B8FF\">playbooks</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">loading</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#B392F0\"> usePlaybooks</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">  const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#79B8FF\">run</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">start</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#B392F0\"> useRun</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">  const</span><span style=\"color:#79B8FF\"> events</span><span style=\"color:#F97583\"> =</span><span style=\"color:#B392F0\"> useRunEvents</span><span style=\"color:#E1E4E8\">(run?.id);</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#F97583\">  if</span><span style=\"color:#E1E4E8\"> (loading) </span><span style=\"color:#F97583\">return</span><span style=\"color:#E1E4E8\"> &#x3C;</span><span style=\"color:#85E89D\">p</span><span style=\"color:#E1E4E8\">>Loading...&#x3C;/</span><span style=\"color:#85E89D\">p</span><span style=\"color:#E1E4E8\">>;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#F97583\">  return</span><span style=\"color:#E1E4E8\"> (</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    &#x3C;</span><span style=\"color:#85E89D\">div</span><span style=\"color:#E1E4E8\">></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">      {playbooks?.</span><span style=\"color:#B392F0\">map</span><span style=\"color:#E1E4E8\">((</span><span style=\"color:#FFAB70\">pb</span><span style=\"color:#E1E4E8\">) </span><span style=\"color:#F97583\">=></span><span style=\"color:#E1E4E8\"> (</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">        &#x3C;</span><span style=\"color:#85E89D\">button</span><span style=\"color:#B392F0\"> key</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{pb.id} </span><span style=\"color:#B392F0\">onClick</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{() </span><span style=\"color:#F97583\">=></span><span style=\"color:#B392F0\"> start</span><span style=\"color:#E1E4E8\">({ playbookId: pb.id, mode: </span><span style=\"color:#9ECBFF\">\"autonomous\"</span><span style=\"color:#E1E4E8\"> })}></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">          {pb.title}</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">        &#x3C;/</span><span style=\"color:#85E89D\">button</span><span style=\"color:#E1E4E8\">></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">      ))}</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">      {events.</span><span style=\"color:#B392F0\">map</span><span style=\"color:#E1E4E8\">((</span><span style=\"color:#FFAB70\">e</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#FFAB70\">i</span><span style=\"color:#E1E4E8\">) </span><span style=\"color:#F97583\">=></span><span style=\"color:#E1E4E8\"> (</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">        &#x3C;</span><span style=\"color:#85E89D\">div</span><span style=\"color:#B392F0\"> key</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{i}>{e.type} {e.stepId}&#x3C;/</span><span style=\"color:#85E89D\">div</span><span style=\"color:#E1E4E8\">></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">      ))}</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    &#x3C;/</span><span style=\"color:#85E89D\">div</span><span style=\"color:#E1E4E8\">></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  );</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}</span></span></code></pre>\n<h2 id=\"pilotprovider\">PilotProvider</h2>\n<p>Wraps your component tree with a <code>PilotClient</code> instance. Accepts all <code>PilotClientConfig</code> props plus <code>children</code>. The client is recreated when <code>baseUrl</code> or <code>auth.token</code> change, and closed on unmount.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { PilotProvider } </span><span style=\"color:#F97583\">from</span><span style=\"color:#9ECBFF\"> \"@cuitty/pilot-react\"</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">&#x3C;</span><span style=\"color:#79B8FF\">PilotProvider</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  baseUrl</span><span style=\"color:#F97583\">=</span><span style=\"color:#9ECBFF\">\"http://localhost:4320\"</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  auth</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{{ token: </span><span style=\"color:#9ECBFF\">\"ey...\"</span><span style=\"color:#E1E4E8\"> }}</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  timeout</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{</span><span style=\"color:#79B8FF\">15000</span><span style=\"color:#E1E4E8\">}</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  {children}</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">&#x3C;/</span><span style=\"color:#79B8FF\">PilotProvider</span><span style=\"color:#E1E4E8\">></span></span></code></pre>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Prop</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>baseUrl</code></td><td><code>string</code></td><td>Pilot server URL</td></tr><tr><td><code>auth</code></td><td><code>{ token?: string; cookie?: string; apiKey?: string }</code></td><td>Authentication credentials</td></tr><tr><td><code>timeout</code></td><td><code>number</code></td><td>Per-request timeout in ms (default 30000)</td></tr><tr><td><code>children</code></td><td><code>React.ReactNode</code></td><td>Child components</td></tr></tbody></table>\n<h3 id=\"usepilot\">usePilot()</h3>\n<p>Returns the <code>PilotClient</code> from context. Throws if used outside <code>&#x3C;PilotProvider></code>.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { usePilot } </span><span style=\"color:#F97583\">from</span><span style=\"color:#9ECBFF\"> \"@cuitty/pilot-react\"</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> pilot</span><span style=\"color:#F97583\"> =</span><span style=\"color:#B392F0\"> usePilot</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> health</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.</span><span style=\"color:#B392F0\">health</span><span style=\"color:#E1E4E8\">();</span></span></code></pre>\n<h2 id=\"hooks\">Hooks</h2>\n<h3 id=\"useplaybooksoptions\">usePlaybooks(options?)</h3>\n<p>Fetches and caches the playbook list. Re-fetches when options change.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#79B8FF\">data</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">loading</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">error</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">refetch</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#B392F0\"> usePlaybooks</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#FFAB70\">data</span><span style=\"color:#E1E4E8\">: </span><span style=\"color:#79B8FF\">cfOnly</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#B392F0\"> usePlaybooks</span><span style=\"color:#E1E4E8\">({ target: </span><span style=\"color:#9ECBFF\">\"cloudflare\"</span><span style=\"color:#E1E4E8\"> });</span></span></code></pre>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Return</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>data</code></td><td><code>PlaybookSummary[] | null</code></td><td>Fetched playbooks, <code>null</code> until loaded</td></tr><tr><td><code>loading</code></td><td><code>boolean</code></td><td><code>true</code> while fetching</td></tr><tr><td><code>error</code></td><td><code>Error | null</code></td><td>Fetch error, if any</td></tr><tr><td><code>refetch</code></td><td><code>() => Promise&#x3C;void></code></td><td>Manually re-fetch the list</td></tr></tbody></table>\n<h3 id=\"userun\">useRun()</h3>\n<p>Manages a single run lifecycle: start, abort, and refresh.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#79B8FF\">run</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">loading</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">error</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">start</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">abort</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">refresh</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#B392F0\"> useRun</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Start a new run</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> result</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#B392F0\"> start</span><span style=\"color:#E1E4E8\">({</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  playbookId: </span><span style=\"color:#9ECBFF\">\"cloudflare.dns.add-a-record\"</span><span style=\"color:#E1E4E8\">,</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  mode: </span><span style=\"color:#9ECBFF\">\"interactive\"</span><span style=\"color:#E1E4E8\">,</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  inputs: { zone: </span><span style=\"color:#9ECBFF\">\"example.com\"</span><span style=\"color:#E1E4E8\">, record_name: </span><span style=\"color:#9ECBFF\">\"api\"</span><span style=\"color:#E1E4E8\">, ip_address: </span><span style=\"color:#9ECBFF\">\"1.2.3.4\"</span><span style=\"color:#E1E4E8\"> },</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">});</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Abort the active run</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">await</span><span style=\"color:#B392F0\"> abort</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Refresh run state from the server</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">await</span><span style=\"color:#B392F0\"> refresh</span><span style=\"color:#E1E4E8\">();</span></span></code></pre>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Return</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>run</code></td><td><code>Run | null</code></td><td>Current run object</td></tr><tr><td><code>loading</code></td><td><code>boolean</code></td><td><code>true</code> while starting a run</td></tr><tr><td><code>error</code></td><td><code>Error | null</code></td><td>Error from the last operation</td></tr><tr><td><code>start(req)</code></td><td><code>(StartRunRequest) => Promise&#x3C;Run | null></code></td><td>Start a run and fetch its full details</td></tr><tr><td><code>abort()</code></td><td><code>() => Promise&#x3C;void></code></td><td>Abort the current run</td></tr><tr><td><code>refresh()</code></td><td><code>() => Promise&#x3C;void></code></td><td>Re-fetch current run state</td></tr></tbody></table>\n<h3 id=\"useruneventsrunid\">useRunEvents(runId)</h3>\n<p>Subscribes to real-time SSE events for a run. Automatically unsubscribes on unmount or when <code>runId</code> changes. Returns a growing array of events.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> events</span><span style=\"color:#F97583\"> =</span><span style=\"color:#B392F0\"> useRunEvents</span><span style=\"color:#E1E4E8\">(run?.id);</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// events: RunEvent[]</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">events.</span><span style=\"color:#B392F0\">forEach</span><span style=\"color:#E1E4E8\">((</span><span style=\"color:#FFAB70\">event</span><span style=\"color:#E1E4E8\">) </span><span style=\"color:#F97583\">=></span><span style=\"color:#E1E4E8\"> {</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  console.</span><span style=\"color:#B392F0\">log</span><span style=\"color:#E1E4E8\">(event.type, event.stepId);</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">});</span></span></code></pre>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Param</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>runId</code></td><td><code>string | null | undefined</code></td><td>Run ID to subscribe to; <code>null</code>/<code>undefined</code> pauses subscription</td></tr></tbody></table>\n<p>Returns <code>RunEvent[]</code> — accumulates all events received since subscription started.</p>\n<h2 id=\"components\">Components</h2>\n<h3 id=\"runstatusbadge\">RunStatusBadge</h3>\n<p>Renders a colored pill badge for a run status.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { RunStatusBadge } </span><span style=\"color:#F97583\">from</span><span style=\"color:#9ECBFF\"> \"@cuitty/pilot-react\"</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">&#x3C;</span><span style=\"color:#79B8FF\">RunStatusBadge</span><span style=\"color:#B392F0\"> status</span><span style=\"color:#F97583\">=</span><span style=\"color:#9ECBFF\">\"running\"</span><span style=\"color:#E1E4E8\"> /></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">&#x3C;</span><span style=\"color:#79B8FF\">RunStatusBadge</span><span style=\"color:#B392F0\"> status</span><span style=\"color:#F97583\">=</span><span style=\"color:#9ECBFF\">\"completed\"</span><span style=\"color:#E1E4E8\"> /></span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">&#x3C;</span><span style=\"color:#79B8FF\">RunStatusBadge</span><span style=\"color:#B392F0\"> status</span><span style=\"color:#F97583\">=</span><span style=\"color:#9ECBFF\">\"failed\"</span><span style=\"color:#E1E4E8\"> /></span></span></code></pre>\n<p>Supported statuses: <code>queued</code>, <code>running</code>, <code>awaiting_approval</code>, <code>completed</code>, <code>failed</code>, <code>aborted</code>.</p>\n<h3 id=\"runtimeline\">RunTimeline</h3>\n<p>Renders a vertical timeline of run events with color-coded borders (blue for in-progress, green for complete, red for failures).</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { RunTimeline } </span><span style=\"color:#F97583\">from</span><span style=\"color:#9ECBFF\"> \"@cuitty/pilot-react\"</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> events</span><span style=\"color:#F97583\"> =</span><span style=\"color:#B392F0\"> useRunEvents</span><span style=\"color:#E1E4E8\">(runId);</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">&#x3C;</span><span style=\"color:#79B8FF\">RunTimeline</span><span style=\"color:#B392F0\"> events</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{events} /></span></span></code></pre>\n<h3 id=\"playbookcard\">PlaybookCard</h3>\n<p>Displays a playbook summary card with an optional “Run” button.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { PlaybookCard } </span><span style=\"color:#F97583\">from</span><span style=\"color:#9ECBFF\"> \"@cuitty/pilot-react\"</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">&#x3C;</span><span style=\"color:#79B8FF\">PlaybookCard</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  playbook</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{playbook}</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  onRun</span><span style=\"color:#F97583\">=</span><span style=\"color:#E1E4E8\">{(</span><span style=\"color:#FFAB70\">pb</span><span style=\"color:#E1E4E8\">) </span><span style=\"color:#F97583\">=></span><span style=\"color:#B392F0\"> start</span><span style=\"color:#E1E4E8\">({ playbookId: pb.id, mode: </span><span style=\"color:#9ECBFF\">\"autonomous\"</span><span style=\"color:#E1E4E8\"> })}</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">/></span></span></code></pre>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Prop</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>playbook</code></td><td><code>PlaybookSummary</code></td><td>Playbook to display</td></tr><tr><td><code>onRun</code></td><td><code>(playbook: PlaybookSummary) => void</code></td><td>Optional callback when “Run” is clicked</td></tr></tbody></table>\n<h2 id=\"error-handling\">Error handling</h2>\n<p>Errors from hooks are captured in the <code>error</code> field rather than thrown. For direct <code>PilotClient</code> usage via <code>usePilot()</code>, catch <code>PilotApiError</code> and <code>PilotConnectionError</code> from <code>@cuitty/pilot-sdk</code>.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"tsx\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { PilotApiError, PilotConnectionError } </span><span style=\"color:#F97583\">from</span><span style=\"color:#9ECBFF\"> \"@cuitty/pilot-sdk\"</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> pilot</span><span style=\"color:#F97583\"> =</span><span style=\"color:#B392F0\"> usePilot</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">try</span><span style=\"color:#E1E4E8\"> {</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">  await</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">start</span><span style=\"color:#E1E4E8\">({ playbookId: </span><span style=\"color:#9ECBFF\">\"nonexistent\"</span><span style=\"color:#E1E4E8\"> });</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">} </span><span style=\"color:#F97583\">catch</span><span style=\"color:#E1E4E8\"> (err) {</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">  if</span><span style=\"color:#E1E4E8\"> (err </span><span style=\"color:#F97583\">instanceof</span><span style=\"color:#B392F0\"> PilotApiError</span><span style=\"color:#E1E4E8\">) {</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    console.</span><span style=\"color:#B392F0\">error</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">`API ${</span><span style=\"color:#E1E4E8\">err</span><span style=\"color:#9ECBFF\">.</span><span style=\"color:#E1E4E8\">status</span><span style=\"color:#9ECBFF\">}: ${</span><span style=\"color:#E1E4E8\">err</span><span style=\"color:#9ECBFF\">.</span><span style=\"color:#E1E4E8\">statusText</span><span style=\"color:#9ECBFF\">}`</span><span style=\"color:#E1E4E8\">, err.body);</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  } </span><span style=\"color:#F97583\">else</span><span style=\"color:#F97583\"> if</span><span style=\"color:#E1E4E8\"> (err </span><span style=\"color:#F97583\">instanceof</span><span style=\"color:#B392F0\"> PilotConnectionError</span><span style=\"color:#E1E4E8\">) {</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    console.</span><span style=\"color:#B392F0\">error</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">\"Cannot reach Pilot:\"</span><span style=\"color:#E1E4E8\">, err.message);</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  }</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}</span></span></code></pre>\n<h2 id=\"see-also\">See also</h2>\n<ul>\n<li><a href=\"/docs/pilot/sdk/javascript\">JavaScript SDK</a> — underlying <code>PilotClient</code> API reference</li>\n<li><a href=\"/docs/pilot/playbook-reference\">Playbook reference</a> — YAML schema for playbook documents</li>\n<li><a href=\"/docs/pilot/quickstart\">Quickstart</a> — record and replay your first workflow</li>\n</ul>",
  "links_out": [
    "/docs/pilot/sdk/javascript",
    "/docs/pilot/playbook-reference",
    "/docs/pilot/quickstart"
  ]
}