{
  "slug": "pilot/sdk/rust",
  "title": "Pilot Rust SDK",
  "description": "Async Rust client for the Cuitty Pilot API — manage playbooks, runs, and providers with reqwest and serde.",
  "url": "https://cuitty.com/docs/pilot/sdk/rust",
  "markdown_url": "https://cuitty.com/docs/pilot/sdk/rust.md",
  "json_url": "https://cuitty.com/docs/pilot/sdk/rust.json",
  "frontmatter": {
    "title": "Pilot Rust SDK",
    "description": "Async Rust client for the Cuitty Pilot API — manage playbooks, runs, and providers with reqwest and serde.",
    "order": 14,
    "section": "Pilot",
    "updatedAt": "2026-06-01"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "pilot-rust-sdk",
      "text": "Pilot Rust SDK"
    },
    {
      "depth": 2,
      "slug": "install",
      "text": "Install"
    },
    {
      "depth": 2,
      "slug": "quick-start",
      "text": "Quick start"
    },
    {
      "depth": 2,
      "slug": "pilotclient",
      "text": "PilotClient"
    },
    {
      "depth": 2,
      "slug": "playbooks",
      "text": "Playbooks"
    },
    {
      "depth": 2,
      "slug": "runs",
      "text": "Runs"
    },
    {
      "depth": 2,
      "slug": "types",
      "text": "Types"
    },
    {
      "depth": 3,
      "slug": "core-structs",
      "text": "Core structs"
    },
    {
      "depth": 3,
      "slug": "request-structs",
      "text": "Request structs"
    },
    {
      "depth": 2,
      "slug": "error-handling",
      "text": "Error handling"
    },
    {
      "depth": 2,
      "slug": "see-also",
      "text": "See also"
    }
  ],
  "body_markdown": "# Pilot Rust SDK\n\n`cuitty-pilot-sdk` is an async Rust client for the Pilot API. It uses `reqwest` for HTTP, `serde` for JSON serialization, and `thiserror` for typed errors.\n\n## Install\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\ncuitty-pilot-sdk = { path = \"../packages/sdk-rust\" }\n# or when published:\n# cuitty-pilot-sdk = \"0.1\"\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\"] }\n```\n\n## Quick start\n\n```rust\nuse cuitty_pilot_sdk::{PilotClient, StartRunRequest, PilotError};\n\n#[tokio::main]\nasync fn main() -> Result<(), PilotError> {\n    let client = PilotClient::new(\n        \"http://localhost:4320\",\n        Some(\"your-auth-token\".into()),\n    );\n\n    // List all playbooks\n    let playbooks = client.list_playbooks(None).await?;\n\n    // Start a run\n    let resp = client.start_run(&StartRunRequest {\n        playbook_id: \"cloudflare.dns.add-a-record\".into(),\n        mode: Some(\"autonomous\".into()),\n        inputs: Some(serde_json::json!({\n            \"zone\": \"example.com\",\n            \"record_name\": \"app\",\n            \"ip_address\": \"1.2.3.4\"\n        })),\n        ..Default::default()\n    }).await?;\n\n    println!(\"Run started: {} ({})\", resp.id, resp.status);\n\n    // Get run details\n    let run = client.get_run(&resp.id).await?;\n    println!(\"Run status: {}\", run.status);\n\n    Ok(())\n}\n```\n\n## PilotClient\n\nThe main entry point. All methods are `async` and return `Result<T, PilotError>`.\n\n```rust\n// Without auth\nlet client = PilotClient::new(\"http://localhost:4320\", None);\n\n// With bearer token\nlet client = PilotClient::new(\n    \"http://localhost:4320\",\n    Some(\"ey...\".into()),\n);\n```\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `health()` | `HealthStatus` | Check server health |\n| `list_playbooks(target)` | `Vec<PlaybookSummary>` | List playbooks, optionally filtered |\n| `get_playbook(id)` | `Playbook` | Get playbook by ID (latest version) |\n| `create_playbook(req)` | `CreatePlaybookResponse` | Create a new playbook |\n| `update_playbook(id, req)` | `UpdatePlaybookResponse` | Update (version-bump) a playbook |\n| `delete_playbook(id)` | `DeletePlaybookResponse` | Delete all versions |\n| `start_run(req)` | `StartRunResponse` | Start a new run |\n| `list_runs(status, playbook_id, limit)` | `Vec<Run>` | List runs with optional filters |\n| `get_run(id)` | `Run` | Get run details including steps |\n| `abort_run(id)` | `AbortRunResponse` | Abort a running or queued run |\n| `approve_run(id, req)` | `ApproveResponse` | Submit approval decision for a step |\n| `list_providers()` | `Vec<Provider>` | List all provider profiles |\n\n## Playbooks\n\n```rust\n// List all\nlet playbooks = client.list_playbooks(None).await?;\n\n// Filter by target\nlet cf = client.list_playbooks(Some(\"cloudflare\")).await?;\n\n// Get one\nlet pb = client.get_playbook(\"cloudflare.dns.add-a-record\").await?;\n\n// Create\nlet resp = client.create_playbook(&CreatePlaybookRequest {\n    target: \"cloudflare\".into(),\n    title: \"Add CNAME record\".into(),\n    yaml: playbook_yaml,\n    authored_by: Some(\"human\".into()),\n}).await?;\n\n// Update\nclient.update_playbook(\"cloudflare.dns.add-cname\", &UpdatePlaybookRequest {\n    yaml: updated_yaml,\n    target: None,\n    title: None,\n    authored_by: None,\n}).await?;\n\n// Delete\nclient.delete_playbook(\"cloudflare.dns.add-cname\").await?;\n```\n\n## Runs\n\n```rust\n// Start a run\nlet resp = client.start_run(&StartRunRequest {\n    playbook_id: \"cloudflare.dns.add-a-record\".into(),\n    mode: Some(\"interactive\".into()),\n    inputs: Some(serde_json::json!({\n        \"zone\": \"example.com\",\n        \"record_name\": \"api\",\n        \"ip_address\": \"1.2.3.4\"\n    })),\n    provider_profile_id: Some(\"cf-prod\".into()),\n    ..Default::default()\n}).await?;\n\n// Get run with steps\nlet run = client.get_run(&resp.id).await?;\nif let Some(steps) = &run.steps {\n    for step in steps {\n        println!(\"{}: {} ({}ms)\", step.step_id, step.status,\n            step.duration_ms.unwrap_or(0));\n    }\n}\n\n// List recent running runs\nlet running = client.list_runs(Some(\"running\"), None, Some(10)).await?;\n\n// Abort\nclient.abort_run(&resp.id).await?;\n\n// Approve a step\nclient.approve_run(&resp.id, &ApproveRequest {\n    step_id: \"save\".into(),\n    decision: Some(\"approve\".into()),\n}).await?;\n```\n\n## Types\n\n### Core structs\n\n| Struct | Key fields |\n|--------|-----------|\n| `Playbook` | `id`, `version`, `target`, `title`, `document_yaml`, `authored_by`, `created_at` |\n| `PlaybookSummary` | `id`, `version`, `target`, `title`, `authored_by` |\n| `Run` | `id`, `project_id`, `playbook_id`, `mode`, `status`, `inputs_json`, `outputs_json`, `steps: Option<Vec<RunStep>>` |\n| `RunStep` | `id`, `run_id`, `step_id`, `action`, `status`, `ai_used`, `duration_ms`, `error_message` |\n| `Provider` | `id`, `project_id`, `provider`, `label`, `base_url`, `last_authenticated`, `expires_at` |\n| `HealthStatus` | `status`, `database`, `driver_pool`, `provider_sessions`, `last_checked` |\n\n### Request structs\n\n| Struct | Fields |\n|--------|--------|\n| `StartRunRequest` | `playbook_id`, `version?`, `mode?`, `inputs?` (`serde_json::Value`), `provider_profile_id?`, `project_id?` |\n| `CreatePlaybookRequest` | `target`, `title`, `yaml`, `authored_by?` |\n| `UpdatePlaybookRequest` | `yaml`, `target?`, `title?`, `authored_by?` |\n| `ApproveRequest` | `step_id`, `decision?` |\n\nAll structs derive `Debug`, `Clone`, `Serialize`, and `Deserialize`.\n\n## Error handling\n\nThe SDK uses a single `PilotError` enum with three variants:\n\n```rust\nuse cuitty_pilot_sdk::PilotError;\n\nmatch client.start_run(&req).await {\n    Ok(resp) => println!(\"Started: {}\", resp.id),\n    Err(PilotError::Api { status, message }) => {\n        eprintln!(\"API error {}: {}\", status, message);\n    }\n    Err(PilotError::Connection(err)) => {\n        eprintln!(\"Network error: {}\", err);\n    }\n    Err(PilotError::Other(msg)) => {\n        eprintln!(\"Unexpected: {}\", msg);\n    }\n}\n```\n\n| Variant | Fields | When |\n|---------|--------|------|\n| `Api` | `status: u16`, `message: String` | Non-2xx HTTP response |\n| `Connection` | wraps `reqwest::Error` | Network or timeout failure |\n| `Other` | `String` | Any other error |\n\n## See also\n\n- [JavaScript SDK](/docs/pilot/sdk/javascript) — TypeScript client with event streaming\n- [Playbook reference](/docs/pilot/playbook-reference) — YAML schema for playbook documents\n- [Quickstart](/docs/pilot/quickstart) — record and replay your first workflow",
  "links_out": [
    "/docs/pilot/sdk/javascript",
    "/docs/pilot/playbook-reference",
    "/docs/pilot/quickstart"
  ]
}