{
  "slug": "pilot/sdk/go",
  "title": "Pilot Go SDK",
  "description": "Go client for the Cuitty Pilot API — manage playbooks, runs, and providers with idiomatic Go error handling.",
  "url": "https://cuitty.com/docs/pilot/sdk/go",
  "markdown_url": "https://cuitty.com/docs/pilot/sdk/go.md",
  "json_url": "https://cuitty.com/docs/pilot/sdk/go.json",
  "frontmatter": {
    "title": "Pilot Go SDK",
    "description": "Go client for the Cuitty Pilot API — manage playbooks, runs, and providers with idiomatic Go error handling.",
    "order": 15,
    "section": "Pilot",
    "updatedAt": "2026-06-01"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "pilot-go-sdk",
      "text": "Pilot Go SDK"
    },
    {
      "depth": 2,
      "slug": "install",
      "text": "Install"
    },
    {
      "depth": 2,
      "slug": "quick-start",
      "text": "Quick start"
    },
    {
      "depth": 2,
      "slug": "newclient",
      "text": "NewClient"
    },
    {
      "depth": 2,
      "slug": "playbooks",
      "text": "Playbooks"
    },
    {
      "depth": 2,
      "slug": "runs",
      "text": "Runs"
    },
    {
      "depth": 2,
      "slug": "types",
      "text": "Types"
    },
    {
      "depth": 3,
      "slug": "core-types",
      "text": "Core types"
    },
    {
      "depth": 3,
      "slug": "request-types",
      "text": "Request types"
    },
    {
      "depth": 2,
      "slug": "error-handling",
      "text": "Error handling"
    },
    {
      "depth": 2,
      "slug": "see-also",
      "text": "See also"
    }
  ],
  "body_markdown": "# Pilot Go SDK\n\n`github.com/cuitty/pilot-sdk-go` is a Go client for the Pilot API. It requires Go 1.22+ and has zero external dependencies beyond the standard library.\n\n## Install\n\n```bash\ngo get github.com/cuitty/pilot-sdk-go\n```\n\n## Quick start\n\n```go\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\n\tpilot \"github.com/cuitty/pilot-sdk-go\"\n)\n\nfunc main() {\n\tclient := pilot.NewClient(\"http://localhost:4320\", \"your-auth-token\")\n\n\t// List all playbooks\n\tplaybooks, err := client.ListPlaybooks(\"\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfor _, pb := range playbooks {\n\t\tfmt.Printf(\"%s: %s\\n\", pb.ID, pb.Title)\n\t}\n\n\t// Start a run\n\tinputs, _ := json.Marshal(map[string]string{\n\t\t\"zone\":        \"example.com\",\n\t\t\"record_name\": \"app\",\n\t\t\"ip_address\":  \"1.2.3.4\",\n\t})\n\tresp, err := client.StartRun(&pilot.StartRunRequest{\n\t\tPlaybookID: \"cloudflare.dns.add-a-record\",\n\t\tMode:       \"autonomous\",\n\t\tInputs:     inputs,\n\t})\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfmt.Printf(\"Run started: %s (%s)\\n\", resp.ID, resp.Status)\n}\n```\n\n## NewClient\n\nCreates a new Pilot API client. Pass an empty string for `authToken` to skip authentication.\n\n```go\n// With auth\nclient := pilot.NewClient(\"http://localhost:4320\", \"ey...\")\n\n// Without auth\nclient := pilot.NewClient(\"http://localhost:4320\", \"\")\n```\n\nThe `Client` struct exposes `BaseURL`, `AuthToken`, and `HTTP` (*http.Client) fields for customization.\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `Health()` | `*HealthStatus, error` | Check server health |\n| `ListPlaybooks(target)` | `[]PlaybookSummary, error` | List playbooks; pass `\"\"` for all |\n| `GetPlaybook(id)` | `*Playbook, error` | Get playbook by ID (latest version) |\n| `CreatePlaybook(req)` | `*CreatePlaybookResponse, error` | Create a new playbook |\n| `UpdatePlaybook(id, req)` | `*UpdatePlaybookResponse, error` | Update (version-bump) a playbook |\n| `DeletePlaybook(id)` | `*DeletePlaybookResponse, error` | Delete all versions |\n| `StartRun(req)` | `*StartRunResponse, error` | Start a new run |\n| `ListRuns(opts)` | `[]Run, error` | List runs with optional filters |\n| `GetRun(id)` | `*Run, error` | Get run details including steps |\n| `AbortRun(id)` | `*AbortRunResponse, error` | Abort a running or queued run |\n| `ApproveRun(id, req)` | `*ApproveResponse, error` | Submit approval decision for a step |\n| `ListProviders()` | `[]Provider, error` | List all provider profiles |\n\n## Playbooks\n\n```go\n// List all\nplaybooks, err := client.ListPlaybooks(\"\")\n\n// Filter by target\ncfPlaybooks, err := client.ListPlaybooks(\"cloudflare\")\n\n// Get one\npb, err := client.GetPlaybook(\"cloudflare.dns.add-a-record\")\n\n// Create\nresp, err := client.CreatePlaybook(&pilot.CreatePlaybookRequest{\n\tTarget:     \"cloudflare\",\n\tTitle:      \"Add CNAME record\",\n\tYAML:       playbookYAML,\n\tAuthoredBy: \"human\",\n})\n\n// Update\nresp, err := client.UpdatePlaybook(\"cloudflare.dns.add-cname\",\n\t&pilot.UpdatePlaybookRequest{YAML: updatedYAML})\n\n// Delete\nresp, err := client.DeletePlaybook(\"cloudflare.dns.add-cname\")\n```\n\n## Runs\n\n```go\n// Start a run\ninputs, _ := json.Marshal(map[string]string{\n\t\"zone\": \"example.com\",\n\t\"record_name\": \"api\",\n\t\"ip_address\": \"1.2.3.4\",\n})\nresp, err := client.StartRun(&pilot.StartRunRequest{\n\tPlaybookID:        \"cloudflare.dns.add-a-record\",\n\tMode:              \"interactive\",\n\tInputs:            inputs,\n\tProviderProfileID: \"cf-prod\",\n})\n\n// Get run with steps\nrun, err := client.GetRun(resp.ID)\nfor _, step := range run.Steps {\n\tfmt.Printf(\"%s: %s\\n\", step.StepID, step.Status)\n}\n\n// List runs with filters\nruns, err := client.ListRuns(&pilot.ListRunsOptions{\n\tStatus: \"running\",\n\tLimit:  10,\n})\n\n// Abort\nresp, err := client.AbortRun(runID)\n\n// Approve a step\nresp, err := client.ApproveRun(runID, &pilot.ApproveRequest{\n\tStepID:   \"save\",\n\tDecision: \"approve\",\n})\n```\n\n## Types\n\n### Core types\n\n| Type | Key fields |\n|------|-----------|\n| `Playbook` | `ID`, `Version`, `Target`, `Title`, `DocumentYAML`, `AuthoredBy`, `CreatedAt` |\n| `PlaybookSummary` | `ID`, `Version`, `Target`, `Title`, `AuthoredBy` |\n| `Run` | `ID`, `ProjectID`, `PlaybookID`, `Mode`, `Status`, `InputsJSON`, `OutputsJSON`, `Steps []RunStep` |\n| `RunStep` | `ID`, `RunID`, `StepID`, `Action`, `Status`, `AIUsed`, `DurationMs *int`, `ErrorMessage *string` |\n| `Provider` | `ID`, `ProjectID`, `Provider`, `Label`, `BaseURL`, `LastAuthenticated`, `ExpiresAt` |\n| `HealthStatus` | `Status`, `Database`, `DriverPool`, `ProviderSessions`, `LastChecked` |\n\n### Request types\n\n| Type | Fields |\n|------|--------|\n| `StartRunRequest` | `PlaybookID`, `Version *int`, `Mode`, `Inputs json.RawMessage`, `ProviderProfileID`, `ProjectID` |\n| `CreatePlaybookRequest` | `Target`, `Title`, `YAML`, `AuthoredBy` |\n| `UpdatePlaybookRequest` | `YAML`, `Target`, `Title`, `AuthoredBy` |\n| `ApproveRequest` | `StepID`, `Decision` |\n| `ListRunsOptions` | `Status`, `PlaybookID`, `Limit int` |\n\n## Error handling\n\nThe SDK returns `*APIError` for non-2xx responses. All other errors are standard Go errors from `net/http` or `encoding/json`.\n\n```go\nimport (\n\t\"errors\"\n\tpilot \"github.com/cuitty/pilot-sdk-go\"\n)\n\nresp, err := client.StartRun(&req)\nif err != nil {\n\tvar apiErr *pilot.APIError\n\tif errors.As(err, &apiErr) {\n\t\tfmt.Printf(\"API error %d: %s\\n\", apiErr.StatusCode, apiErr.Message)\n\t} else {\n\t\tfmt.Printf(\"Network error: %v\\n\", err)\n\t}\n}\n```\n\n| Type | Fields | When |\n|------|--------|------|\n| `*APIError` | `StatusCode int`, `Message string` | Non-2xx HTTP response |\n| `error` | standard | Network, JSON, or other failure |\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"
  ]
}