{
  "slug": "pilot/sdk/javascript",
  "title": "Pilot JavaScript SDK",
  "description": "PilotClient for TypeScript and Node.js — run playbooks, manage runs, and stream events programmatically.",
  "url": "https://cuitty.com/docs/pilot/sdk/javascript",
  "markdown_url": "https://cuitty.com/docs/pilot/sdk/javascript.md",
  "json_url": "https://cuitty.com/docs/pilot/sdk/javascript.json",
  "frontmatter": {
    "title": "Pilot JavaScript SDK",
    "description": "PilotClient for TypeScript and Node.js — run playbooks, manage runs, and stream events programmatically.",
    "order": 4,
    "section": "Pilot",
    "updatedAt": "2026-06-01"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "pilot-javascript-sdk",
      "text": "Pilot JavaScript SDK"
    },
    {
      "depth": 2,
      "slug": "install",
      "text": "Install"
    },
    {
      "depth": 2,
      "slug": "quick-start",
      "text": "Quick start"
    },
    {
      "depth": 2,
      "slug": "pilotclient",
      "text": "PilotClient"
    },
    {
      "depth": 2,
      "slug": "playbookservice",
      "text": "PlaybookService"
    },
    {
      "depth": 2,
      "slug": "runservice",
      "text": "RunService"
    },
    {
      "depth": 2,
      "slug": "event-streaming",
      "text": "Event streaming"
    },
    {
      "depth": 3,
      "slug": "async-iterator",
      "text": "Async iterator"
    },
    {
      "depth": 3,
      "slug": "callback-subscription",
      "text": "Callback subscription"
    },
    {
      "depth": 3,
      "slug": "event-types",
      "text": "Event types"
    },
    {
      "depth": 2,
      "slug": "providerservice",
      "text": "ProviderService"
    },
    {
      "depth": 2,
      "slug": "error-handling",
      "text": "Error handling"
    },
    {
      "depth": 2,
      "slug": "see-also",
      "text": "See also"
    }
  ],
  "body_markdown": "# Pilot JavaScript SDK\n\n`@cuitty/pilot-sdk` is the TypeScript/Node.js client for the Pilot API. It provides typed methods for managing playbooks, starting runs, streaming real-time events, and listing providers.\n\n## Install\n\n```bash\nsfw bun add @cuitty/pilot-sdk\n# or\nsfw npm install @cuitty/pilot-sdk\n```\n\n## Quick start\n\n```typescript\nimport { PilotClient } from \"@cuitty/pilot-sdk\";\n\nconst pilot = new PilotClient({\n  baseUrl: \"http://localhost:4320\",\n  auth: { apiKey: process.env.PILOT_API_KEY },\n});\n\n// List all playbooks\nconst playbooks = await pilot.playbooks.list();\n\n// Start a run\nconst { id } = await pilot.runs.start({\n  playbookId: \"cloudflare.dns.add-a-record\",\n  mode: \"autonomous\",\n  inputs: { zone: \"example.com\", record_name: \"app\", ip_address: \"1.2.3.4\" },\n});\n\n// Stream events until completion\nfor await (const event of pilot.runs.stream(id)) {\n  console.log(event.type, event.stepId, event.status);\n}\n\n// Clean up\npilot.close();\n```\n\n## PilotClient\n\nThe main entry point. Creates service instances and manages shared configuration.\n\n```typescript\ninterface PilotClientConfig {\n  baseUrl: string;            // Pilot server URL\n  auth?: {\n    token?: string;           // Bearer token\n    cookie?: string;          // Raw cookie string\n    apiKey?: string;          // X-Pilot-API-Key header\n  };\n  timeout?: number;           // Per-request timeout in ms (default 30000)\n}\n\nconst pilot = new PilotClient(config);\n```\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `pilot.playbooks` | `PlaybookService` | Playbook CRUD |\n| `pilot.runs` | `RunService` | Run lifecycle + streaming |\n| `pilot.providers` | `ProviderService` | Provider profile listing |\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `pilot.health()` | `Promise<HealthStatus>` | Check server health |\n| `pilot.close()` | `void` | Close all active event subscriptions |\n\n## PlaybookService\n\n```typescript\n// List all playbooks, optionally filtered by target\nconst all = await pilot.playbooks.list();\nconst cfOnly = await pilot.playbooks.list({ target: \"cloudflare\" });\n\n// Get a single playbook (latest version)\nconst pb = await pilot.playbooks.get(\"cloudflare.dns.add-a-record\");\n\n// Create a new playbook\nconst { id, version } = await pilot.playbooks.create({\n  target: \"cloudflare\",\n  title: \"Add CNAME record\",\n  yaml: playbookYaml,\n  authoredBy: \"human\",\n});\n\n// Update (bumps version)\nawait pilot.playbooks.update(\"cloudflare.dns.add-cname\", {\n  yaml: updatedYaml,\n});\n\n// Delete all versions\nawait pilot.playbooks.delete(\"cloudflare.dns.add-cname\");\n```\n\n| Method | Params | Returns |\n|--------|--------|---------|\n| `list(options?)` | `{ target?: string }` | `PlaybookSummary[]` |\n| `get(id)` | playbook id | `Playbook` |\n| `create(req)` | `CreatePlaybookRequest` | `{ id, version, created }` |\n| `update(id, req)` | id + `UpdatePlaybookRequest` | `{ id, version }` |\n| `delete(id)` | playbook id | `{ deleted }` |\n\n## RunService\n\n```typescript\n// Start a run\nconst { id, status } = await pilot.runs.start({\n  playbookId: \"cloudflare.dns.add-a-record\",\n  mode: \"interactive\",         // \"autonomous\" | \"interactive\" | \"review\"\n  inputs: { zone: \"example.com\", record_name: \"api\", ip_address: \"1.2.3.4\" },\n  providerProfileId: \"cf-prod\",\n});\n\n// Get run details\nconst run = await pilot.runs.get(id);\n\n// List runs with filters\nconst recent = await pilot.runs.list({ status: \"running\", limit: 10 });\n\n// Abort a running run\nawait pilot.runs.abort(id);\n\n// Approve a step awaiting review\nawait pilot.runs.approve(id, {\n  stepId: \"save\",\n  decision: \"approve\",         // \"approve\" | \"skip\" | \"abort\"\n});\n```\n\n| Method | Returns |\n|--------|---------|\n| `start(req)` | `{ id, status }` |\n| `get(id)` | `Run` (includes `steps` array) |\n| `list(options?)` | `Run[]` |\n| `abort(id)` | `{ aborted, runId }` |\n| `approve(id, req)` | `{ approved, runId, stepId, decision }` |\n\n## Event streaming\n\nTwo patterns for consuming real-time run events via SSE:\n\n### Async iterator\n\n```typescript\nfor await (const event of pilot.runs.stream(runId)) {\n  switch (event.type) {\n    case \"step.start\":\n      console.log(`Step ${event.stepId} started`);\n      break;\n    case \"step.complete\":\n      console.log(`Step ${event.stepId} done in ${event.durationMs}ms`);\n      break;\n    case \"step.failed\":\n      console.error(`Step ${event.stepId} failed: ${event.error}`);\n      break;\n    case \"run.completed\":\n      console.log(\"Run finished\", event.outputs);\n      break;\n  }\n}\n```\n\nThe iterator yields events until the run reaches a terminal state (`run.completed`, `run.failed`, or `run.aborted`).\n\n### Callback subscription\n\n```typescript\nconst unsubscribe = pilot.runs.subscribe(runId, {\n  onStep: (event) => console.log(\"step\", event.stepId, event.status),\n  onComplete: (event) => console.log(\"done\", event.outputs),\n  onError: (event) => console.error(\"error\", event.error),\n  onEvent: (event) => {}, // every event\n});\n\n// Later: close the SSE connection\nunsubscribe();\n```\n\n### Event types\n\n| Type | Fields | When |\n|------|--------|------|\n| `step.start` | `stepId`, `action` | Step begins executing |\n| `step.complete` | `stepId`, `action`, `durationMs`, `aiUsed` | Step succeeded |\n| `step.failed` | `stepId`, `action`, `error` | Step errored |\n| `step.awaiting_approval` | `stepId`, `action` | Step paused at breakpoint |\n| `run.completed` | `outputs` | All steps finished |\n| `run.failed` | `error` | Run failed |\n| `run.aborted` | | Run was aborted |\n\n## ProviderService\n\n```typescript\nconst providers = await pilot.providers.list();\n// Returns: Provider[]\n// { id, projectId, provider, label, baseUrl, lastAuthenticated, expiresAt }\n```\n\n## Error handling\n\nThe SDK throws typed errors:\n\n```typescript\nimport { PilotApiError, PilotConnectionError } from \"@cuitty/pilot-sdk\";\n\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| Error class | Properties | When |\n|-------------|-----------|------|\n| `PilotApiError` | `status`, `statusText`, `body` | Non-2xx HTTP response |\n| `PilotConnectionError` | `message`, `cause` | Network / timeout failure |\n\n## See also\n\n- [Playbook reference](/docs/pilot/playbook-reference) — YAML schema for playbook documents\n- [Executors](/docs/pilot/executors) — Browser, Terraform, Git, and other executor types\n- [Quickstart](/docs/pilot/quickstart) — record and replay your first workflow",
  "body_html": "<h1 id=\"pilot-javascript-sdk\">Pilot JavaScript SDK</h1>\n<p><code>@cuitty/pilot-sdk</code> is the TypeScript/Node.js client for the Pilot API. It provides typed methods for managing playbooks, starting runs, streaming real-time events, and listing providers.</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-sdk</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-sdk</span></span></code></pre>\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=\"typescript\"><code><span class=\"line\"><span style=\"color:#F97583\">import</span><span style=\"color:#E1E4E8\"> { PilotClient } </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:#F97583\"> new</span><span style=\"color:#B392F0\"> PilotClient</span><span style=\"color:#E1E4E8\">({</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  baseUrl: </span><span style=\"color:#9ECBFF\">\"http://localhost:4320\"</span><span style=\"color:#E1E4E8\">,</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  auth: { apiKey: process.env.</span><span style=\"color:#79B8FF\">PILOT_API_KEY</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\">// List all playbooks</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> playbooks</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.playbooks.</span><span style=\"color:#B392F0\">list</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Start a run</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#79B8FF\">id</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.runs.</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\">\"autonomous\"</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\">\"app\"</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\">// Stream events until completion</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">for</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> (</span><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> event</span><span style=\"color:#F97583\"> of</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">stream</span><span style=\"color:#E1E4E8\">(id)) {</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, event.status);</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\">// Clean up</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">pilot.</span><span style=\"color:#B392F0\">close</span><span style=\"color:#E1E4E8\">();</span></span></code></pre>\n<h2 id=\"pilotclient\">PilotClient</h2>\n<p>The main entry point. Creates service instances and manages shared configuration.</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"typescript\"><code><span class=\"line\"><span style=\"color:#F97583\">interface</span><span style=\"color:#B392F0\"> PilotClientConfig</span><span style=\"color:#E1E4E8\"> {</span></span>\n<span class=\"line\"><span style=\"color:#FFAB70\">  baseUrl</span><span style=\"color:#F97583\">:</span><span style=\"color:#79B8FF\"> string</span><span style=\"color:#E1E4E8\">;            </span><span style=\"color:#6A737D\">// Pilot server URL</span></span>\n<span class=\"line\"><span style=\"color:#FFAB70\">  auth</span><span style=\"color:#F97583\">?:</span><span style=\"color:#E1E4E8\"> {</span></span>\n<span class=\"line\"><span style=\"color:#FFAB70\">    token</span><span style=\"color:#F97583\">?:</span><span style=\"color:#79B8FF\"> string</span><span style=\"color:#E1E4E8\">;           </span><span style=\"color:#6A737D\">// Bearer token</span></span>\n<span class=\"line\"><span style=\"color:#FFAB70\">    cookie</span><span style=\"color:#F97583\">?:</span><span style=\"color:#79B8FF\"> string</span><span style=\"color:#E1E4E8\">;          </span><span style=\"color:#6A737D\">// Raw cookie string</span></span>\n<span class=\"line\"><span style=\"color:#FFAB70\">    apiKey</span><span style=\"color:#F97583\">?:</span><span style=\"color:#79B8FF\"> string</span><span style=\"color:#E1E4E8\">;          </span><span style=\"color:#6A737D\">// X-Pilot-API-Key header</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  };</span></span>\n<span class=\"line\"><span style=\"color:#FFAB70\">  timeout</span><span style=\"color:#F97583\">?:</span><span style=\"color:#79B8FF\"> number</span><span style=\"color:#E1E4E8\">;           </span><span style=\"color:#6A737D\">// Per-request timeout in ms (default 30000)</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\">const</span><span style=\"color:#79B8FF\"> pilot</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> new</span><span style=\"color:#B392F0\"> PilotClient</span><span style=\"color:#E1E4E8\">(config);</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<table><thead><tr><th>Property</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>pilot.playbooks</code></td><td><code>PlaybookService</code></td><td>Playbook CRUD</td></tr><tr><td><code>pilot.runs</code></td><td><code>RunService</code></td><td>Run lifecycle + streaming</td></tr><tr><td><code>pilot.providers</code></td><td><code>ProviderService</code></td><td>Provider profile listing</td></tr></tbody></table>\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>Method</th><th>Returns</th><th>Description</th></tr></thead><tbody><tr><td><code>pilot.health()</code></td><td><code>Promise&#x3C;HealthStatus></code></td><td>Check server health</td></tr><tr><td><code>pilot.close()</code></td><td><code>void</code></td><td>Close all active event subscriptions</td></tr></tbody></table>\n<h2 id=\"playbookservice\">PlaybookService</h2>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"typescript\"><code><span class=\"line\"><span style=\"color:#6A737D\">// List all playbooks, optionally filtered by target</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> all</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.playbooks.</span><span style=\"color:#B392F0\">list</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> cfOnly</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.playbooks.</span><span style=\"color:#B392F0\">list</span><span style=\"color:#E1E4E8\">({ target: </span><span style=\"color:#9ECBFF\">\"cloudflare\"</span><span style=\"color:#E1E4E8\"> });</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Get a single playbook (latest version)</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> pb</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.playbooks.</span><span style=\"color:#B392F0\">get</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">\"cloudflare.dns.add-a-record\"</span><span style=\"color:#E1E4E8\">);</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Create a new playbook</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#79B8FF\">id</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">version</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.playbooks.</span><span style=\"color:#B392F0\">create</span><span style=\"color:#E1E4E8\">({</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  target: </span><span style=\"color:#9ECBFF\">\"cloudflare\"</span><span style=\"color:#E1E4E8\">,</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  title: </span><span style=\"color:#9ECBFF\">\"Add CNAME record\"</span><span style=\"color:#E1E4E8\">,</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  yaml: playbookYaml,</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  authoredBy: </span><span style=\"color:#9ECBFF\">\"human\"</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\">// Update (bumps version)</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">await</span><span style=\"color:#E1E4E8\"> pilot.playbooks.</span><span style=\"color:#B392F0\">update</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">\"cloudflare.dns.add-cname\"</span><span style=\"color:#E1E4E8\">, {</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  yaml: updatedYaml,</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\">// Delete all versions</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">await</span><span style=\"color:#E1E4E8\"> pilot.playbooks.</span><span style=\"color:#B392F0\">delete</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">\"cloudflare.dns.add-cname\"</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<table><thead><tr><th>Method</th><th>Params</th><th>Returns</th></tr></thead><tbody><tr><td><code>list(options?)</code></td><td><code>{ target?: string }</code></td><td><code>PlaybookSummary[]</code></td></tr><tr><td><code>get(id)</code></td><td>playbook id</td><td><code>Playbook</code></td></tr><tr><td><code>create(req)</code></td><td><code>CreatePlaybookRequest</code></td><td><code>{ id, version, created }</code></td></tr><tr><td><code>update(id, req)</code></td><td>id + <code>UpdatePlaybookRequest</code></td><td><code>{ id, version }</code></td></tr><tr><td><code>delete(id)</code></td><td>playbook id</td><td><code>{ deleted }</code></td></tr></tbody></table>\n<h2 id=\"runservice\">RunService</h2>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"typescript\"><code><span class=\"line\"><span style=\"color:#6A737D\">// Start a run</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#E1E4E8\"> { </span><span style=\"color:#79B8FF\">id</span><span style=\"color:#E1E4E8\">, </span><span style=\"color:#79B8FF\">status</span><span style=\"color:#E1E4E8\"> } </span><span style=\"color:#F97583\">=</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.runs.</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 style=\"color:#6A737D\">// \"autonomous\" | \"interactive\" | \"review\"</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\">  providerProfileId: </span><span style=\"color:#9ECBFF\">\"cf-prod\"</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\">// Get run details</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> run</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">get</span><span style=\"color:#E1E4E8\">(id);</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// List runs with filters</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> recent</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">list</span><span style=\"color:#E1E4E8\">({ status: </span><span style=\"color:#9ECBFF\">\"running\"</span><span style=\"color:#E1E4E8\">, limit: </span><span style=\"color:#79B8FF\">10</span><span style=\"color:#E1E4E8\"> });</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Abort a running run</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">await</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">abort</span><span style=\"color:#E1E4E8\">(id);</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Approve a step awaiting review</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">await</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">approve</span><span style=\"color:#E1E4E8\">(id, {</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  stepId: </span><span style=\"color:#9ECBFF\">\"save\"</span><span style=\"color:#E1E4E8\">,</span></span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  decision: </span><span style=\"color:#9ECBFF\">\"approve\"</span><span style=\"color:#E1E4E8\">,         </span><span style=\"color:#6A737D\">// \"approve\" | \"skip\" | \"abort\"</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\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Method</th><th>Returns</th></tr></thead><tbody><tr><td><code>start(req)</code></td><td><code>{ id, status }</code></td></tr><tr><td><code>get(id)</code></td><td><code>Run</code> (includes <code>steps</code> array)</td></tr><tr><td><code>list(options?)</code></td><td><code>Run[]</code></td></tr><tr><td><code>abort(id)</code></td><td><code>{ aborted, runId }</code></td></tr><tr><td><code>approve(id, req)</code></td><td><code>{ approved, runId, stepId, decision }</code></td></tr></tbody></table>\n<h2 id=\"event-streaming\">Event streaming</h2>\n<p>Two patterns for consuming real-time run events via SSE:</p>\n<h3 id=\"async-iterator\">Async iterator</h3>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"typescript\"><code><span class=\"line\"><span style=\"color:#F97583\">for</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> (</span><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> event</span><span style=\"color:#F97583\"> of</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">stream</span><span style=\"color:#E1E4E8\">(runId)) {</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">  switch</span><span style=\"color:#E1E4E8\"> (event.type) {</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">    case</span><span style=\"color:#9ECBFF\"> \"step.start\"</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\">(</span><span style=\"color:#9ECBFF\">`Step ${</span><span style=\"color:#E1E4E8\">event</span><span style=\"color:#9ECBFF\">.</span><span style=\"color:#E1E4E8\">stepId</span><span style=\"color:#9ECBFF\">} started`</span><span style=\"color:#E1E4E8\">);</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">      break</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">    case</span><span style=\"color:#9ECBFF\"> \"step.complete\"</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\">(</span><span style=\"color:#9ECBFF\">`Step ${</span><span style=\"color:#E1E4E8\">event</span><span style=\"color:#9ECBFF\">.</span><span style=\"color:#E1E4E8\">stepId</span><span style=\"color:#9ECBFF\">} done in ${</span><span style=\"color:#E1E4E8\">event</span><span style=\"color:#9ECBFF\">.</span><span style=\"color:#E1E4E8\">durationMs</span><span style=\"color:#9ECBFF\">}ms`</span><span style=\"color:#E1E4E8\">);</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">      break</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">    case</span><span style=\"color:#9ECBFF\"> \"step.failed\"</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\">`Step ${</span><span style=\"color:#E1E4E8\">event</span><span style=\"color:#9ECBFF\">.</span><span style=\"color:#E1E4E8\">stepId</span><span style=\"color:#9ECBFF\">} failed: ${</span><span style=\"color:#E1E4E8\">event</span><span style=\"color:#9ECBFF\">.</span><span style=\"color:#E1E4E8\">error</span><span style=\"color:#9ECBFF\">}`</span><span style=\"color:#E1E4E8\">);</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">      break</span><span style=\"color:#E1E4E8\">;</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">    case</span><span style=\"color:#9ECBFF\"> \"run.completed\"</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\">(</span><span style=\"color:#9ECBFF\">\"Run finished\"</span><span style=\"color:#E1E4E8\">, event.outputs);</span></span>\n<span class=\"line\"><span style=\"color:#F97583\">      break</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<p>The iterator yields events until the run reaches a terminal state (<code>run.completed</code>, <code>run.failed</code>, or <code>run.aborted</code>).</p>\n<h3 id=\"callback-subscription\">Callback subscription</h3>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"typescript\"><code><span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> unsubscribe</span><span style=\"color:#F97583\"> =</span><span style=\"color:#E1E4E8\"> pilot.runs.</span><span style=\"color:#B392F0\">subscribe</span><span style=\"color:#E1E4E8\">(runId, {</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  onStep</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\"> console.</span><span style=\"color:#B392F0\">log</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">\"step\"</span><span style=\"color:#E1E4E8\">, event.stepId, event.status),</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  onComplete</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\"> console.</span><span style=\"color:#B392F0\">log</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">\"done\"</span><span style=\"color:#E1E4E8\">, event.outputs),</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  onError</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\"> console.</span><span style=\"color:#B392F0\">error</span><span style=\"color:#E1E4E8\">(</span><span style=\"color:#9ECBFF\">\"error\"</span><span style=\"color:#E1E4E8\">, event.error),</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">  onEvent</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 style=\"color:#6A737D\">// every event</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\">// Later: close the SSE connection</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">unsubscribe</span><span style=\"color:#E1E4E8\">();</span></span></code></pre>\n<h3 id=\"event-types\">Event types</h3>\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\n\n\n\n\n<table><thead><tr><th>Type</th><th>Fields</th><th>When</th></tr></thead><tbody><tr><td><code>step.start</code></td><td><code>stepId</code>, <code>action</code></td><td>Step begins executing</td></tr><tr><td><code>step.complete</code></td><td><code>stepId</code>, <code>action</code>, <code>durationMs</code>, <code>aiUsed</code></td><td>Step succeeded</td></tr><tr><td><code>step.failed</code></td><td><code>stepId</code>, <code>action</code>, <code>error</code></td><td>Step errored</td></tr><tr><td><code>step.awaiting_approval</code></td><td><code>stepId</code>, <code>action</code></td><td>Step paused at breakpoint</td></tr><tr><td><code>run.completed</code></td><td><code>outputs</code></td><td>All steps finished</td></tr><tr><td><code>run.failed</code></td><td><code>error</code></td><td>Run failed</td></tr><tr><td><code>run.aborted</code></td><td></td><td>Run was aborted</td></tr></tbody></table>\n<h2 id=\"providerservice\">ProviderService</h2>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"typescript\"><code><span class=\"line\"><span style=\"color:#F97583\">const</span><span style=\"color:#79B8FF\"> providers</span><span style=\"color:#F97583\"> =</span><span style=\"color:#F97583\"> await</span><span style=\"color:#E1E4E8\"> pilot.providers.</span><span style=\"color:#B392F0\">list</span><span style=\"color:#E1E4E8\">();</span></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// Returns: Provider[]</span></span>\n<span class=\"line\"><span style=\"color:#6A737D\">// { id, projectId, provider, label, baseUrl, lastAuthenticated, expiresAt }</span></span></code></pre>\n<h2 id=\"error-handling\">Error handling</h2>\n<p>The SDK throws typed errors:</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"typescript\"><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\">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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Error class</th><th>Properties</th><th>When</th></tr></thead><tbody><tr><td><code>PilotApiError</code></td><td><code>status</code>, <code>statusText</code>, <code>body</code></td><td>Non-2xx HTTP response</td></tr><tr><td><code>PilotConnectionError</code></td><td><code>message</code>, <code>cause</code></td><td>Network / timeout failure</td></tr></tbody></table>\n<h2 id=\"see-also\">See also</h2>\n<ul>\n<li><a href=\"/docs/pilot/playbook-reference\">Playbook reference</a> — YAML schema for playbook documents</li>\n<li><a href=\"/docs/pilot/executors\">Executors</a> — Browser, Terraform, Git, and other executor types</li>\n<li><a href=\"/docs/pilot/quickstart\">Quickstart</a> — record and replay your first workflow</li>\n</ul>",
  "links_out": [
    "/docs/pilot/playbook-reference",
    "/docs/pilot/executors",
    "/docs/pilot/quickstart"
  ]
}