Pilot React SDK
React hooks and components for Cuitty Pilot — manage playbooks, runs, and real-time events in React apps.
Pilot React SDK
@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.
Install
sfw bun add @cuitty/pilot-react
# or
sfw npm install @cuitty/pilot-react
Peer dependencies: react>=18, @cuitty/pilot-sdk.
Quick start
import { PilotProvider, usePlaybooks, useRun, useRunEvents } from "@cuitty/pilot-react";
function App() {
return (
<PilotProvider baseUrl="http://localhost:4320" auth={{ apiKey: "pk_..." }}>
<Dashboard />
</PilotProvider>
);
}
function Dashboard() {
const { data: playbooks, loading } = usePlaybooks();
const { run, start } = useRun();
const events = useRunEvents(run?.id);
if (loading) return <p>Loading...</p>;
return (
<div>
{playbooks?.map((pb) => (
<button key={pb.id} onClick={() => start({ playbookId: pb.id, mode: "autonomous" })}>
{pb.title}
</button>
))}
{events.map((e, i) => (
<div key={i}>{e.type} {e.stepId}</div>
))}
</div>
);
}
PilotProvider
Wraps 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.
import { PilotProvider } from "@cuitty/pilot-react";
<PilotProvider
baseUrl="http://localhost:4320"
auth={{ token: "ey..." }}
timeout={15000}
>
{children}
</PilotProvider>
| Prop | Type | Description |
|---|---|---|
baseUrl | string | Pilot server URL |
auth | { token?: string; cookie?: string; apiKey?: string } | Authentication credentials |
timeout | number | Per-request timeout in ms (default 30000) |
children | React.ReactNode | Child components |
usePilot()
Returns the PilotClient from context. Throws if used outside <PilotProvider>.
import { usePilot } from "@cuitty/pilot-react";
const pilot = usePilot();
const health = await pilot.health();
Hooks
usePlaybooks(options?)
Fetches and caches the playbook list. Re-fetches when options change.
const { data, loading, error, refetch } = usePlaybooks();
const { data: cfOnly } = usePlaybooks({ target: "cloudflare" });
| Return | Type | Description |
|---|---|---|
data | PlaybookSummary[] | null | Fetched playbooks, null until loaded |
loading | boolean | true while fetching |
error | Error | null | Fetch error, if any |
refetch | () => Promise<void> | Manually re-fetch the list |
useRun()
Manages a single run lifecycle: start, abort, and refresh.
const { run, loading, error, start, abort, refresh } = useRun();
// Start a new run
const result = await start({
playbookId: "cloudflare.dns.add-a-record",
mode: "interactive",
inputs: { zone: "example.com", record_name: "api", ip_address: "1.2.3.4" },
});
// Abort the active run
await abort();
// Refresh run state from the server
await refresh();
| Return | Type | Description |
|---|---|---|
run | Run | null | Current run object |
loading | boolean | true while starting a run |
error | Error | null | Error from the last operation |
start(req) | (StartRunRequest) => Promise<Run | null> | Start a run and fetch its full details |
abort() | () => Promise<void> | Abort the current run |
refresh() | () => Promise<void> | Re-fetch current run state |
useRunEvents(runId)
Subscribes to real-time SSE events for a run. Automatically unsubscribes on unmount or when runId changes. Returns a growing array of events.
const events = useRunEvents(run?.id);
// events: RunEvent[]
events.forEach((event) => {
console.log(event.type, event.stepId);
});
| Param | Type | Description |
|---|---|---|
runId | string | null | undefined | Run ID to subscribe to; null/undefined pauses subscription |
Returns RunEvent[] — accumulates all events received since subscription started.
Components
RunStatusBadge
Renders a colored pill badge for a run status.
import { RunStatusBadge } from "@cuitty/pilot-react";
<RunStatusBadge status="running" />
<RunStatusBadge status="completed" />
<RunStatusBadge status="failed" />
Supported statuses: queued, running, awaiting_approval, completed, failed, aborted.
RunTimeline
Renders a vertical timeline of run events with color-coded borders (blue for in-progress, green for complete, red for failures).
import { RunTimeline } from "@cuitty/pilot-react";
const events = useRunEvents(runId);
<RunTimeline events={events} />
PlaybookCard
Displays a playbook summary card with an optional “Run” button.
import { PlaybookCard } from "@cuitty/pilot-react";
<PlaybookCard
playbook={playbook}
onRun={(pb) => start({ playbookId: pb.id, mode: "autonomous" })}
/>
| Prop | Type | Description |
|---|---|---|
playbook | PlaybookSummary | Playbook to display |
onRun | (playbook: PlaybookSummary) => void | Optional callback when “Run” is clicked |
Error handling
Errors 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.
import { PilotApiError, PilotConnectionError } from "@cuitty/pilot-sdk";
const pilot = usePilot();
try {
await pilot.runs.start({ playbookId: "nonexistent" });
} catch (err) {
if (err instanceof PilotApiError) {
console.error(`API ${err.status}: ${err.statusText}`, err.body);
} else if (err instanceof PilotConnectionError) {
console.error("Cannot reach Pilot:", err.message);
}
}
See also
- JavaScript SDK — underlying
PilotClientAPI reference - Playbook reference — YAML schema for playbook documents
- Quickstart — record and replay your first workflow