{
  "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",
  "links_out": [
    "/docs/pilot/playbook-reference",
    "/docs/pilot/executors",
    "/docs/pilot/quickstart"
  ]
}