Pilot

Pilot SolidJS SDK

SolidJS primitives and components for Cuitty Pilot — reactive playbook management, run control, and real-time event streaming.

Pilot SolidJS SDK

@cuitty/pilot-solid provides SolidJS primitives and components for the Pilot API. It wraps @cuitty/pilot-sdk with idiomatic Solid patterns — context providers, createResource for data fetching, signals for run state, and automatic SSE cleanup.

Install

sfw bun add @cuitty/pilot-solid
# or
sfw npm install @cuitty/pilot-solid

Peer dependencies: solid-js>=1.8, @cuitty/pilot-sdk.

Quick start

import { PilotProvider, createPlaybooks, createRun, createRunEvents } from "@cuitty/pilot-solid";
import { For, Show, createSignal } from "solid-js";

function App() {
  return (
    <PilotProvider baseUrl="http://localhost:4320" auth={{ apiKey: "pk_..." }}>
      <Dashboard />
    </PilotProvider>
  );
}

function Dashboard() {
  const [playbooks] = createPlaybooks();
  const [run, { start }] = createRun();
  const events = createRunEvents(() => run()?.id);

  return (
    <div>
      <For each={playbooks()}>
        {(pb) => (
          <button onClick={() => start({ playbookId: pb.id, mode: "autonomous" })}>
            {pb.title}
          </button>
        )}
      </For>
      <For each={events()}>
        {(e) => <div>{e.type} {e.stepId}</div>}
      </For>
    </div>
  );
}

PilotProvider

Wraps your component tree with a PilotClient instance. Accepts all PilotClientConfig props plus children. The client is closed automatically via onCleanup.

import { PilotProvider } from "@cuitty/pilot-solid";

<PilotProvider
  baseUrl="http://localhost:4320"
  auth={{ token: "ey..." }}
  timeout={15000}
>
  {props.children}
</PilotProvider>
PropTypeDescription
baseUrlstringPilot server URL
auth{ token?: string; cookie?: string; apiKey?: string }Authentication credentials
timeoutnumberPer-request timeout in ms (default 30000)
childrenJSX.ElementChild components

usePilot()

Returns the PilotClient from context. Throws if used outside <PilotProvider>.

import { usePilot } from "@cuitty/pilot-solid";

const pilot = usePilot();
const health = await pilot.health();

Primitives

createPlaybooks(options?)

Reactive resource for listing playbooks. Wraps Solid’s createResource — re-fetches when the options accessor changes.

const [playbooks, { refetch }] = createPlaybooks();
const [cfOnly] = createPlaybooks(() => ({ target: "cloudflare" }));
ParamTypeDescription
opts() => ListPlaybooksOptions | undefinedOptional accessor returning filter options

Returns a Solid Resource<PlaybookSummary[]> tuple: [accessor, { refetch, mutate }].

createRun()

Manages a single run lifecycle with signals for run state and loading.

const [run, { start, abort, loading }] = createRun();

// 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();
ReturnTypeDescription
runAccessor<Run | null>Signal with the current run object
start(req)(StartRunRequest) => Promise<Run | null>Start a run and fetch its full details
abort()() => Promise<void>Abort the current run
loadingAccessor<boolean>Signal, true while starting

createRunEvents(runId)

Subscribes to real-time SSE events for a run. Automatically unsubscribes via onCleanup and re-subscribes when runId changes.

const events = createRunEvents(() => run()?.id);

// events is Accessor<RunEvent[]>
<For each={events()}>
  {(event) => <span>{event.type}</span>}
</For>
ParamTypeDescription
runId() => string | null | undefinedAccessor returning the run ID; null/undefined pauses subscription

Returns Accessor<RunEvent[]> — accumulates all events since subscription started.

Components

RunStatusBadge

Renders a colored pill badge for a run status.

import { RunStatusBadge } from "@cuitty/pilot-solid";

<RunStatusBadge status="running" />
<RunStatusBadge status="completed" />

Supported statuses: queued, running, awaiting_approval, completed, failed, aborted.

RunTimeline

Renders a vertical timeline of run events using <For>, with color-coded borders (blue for in-progress, green for complete, red for failures). Uses <Show> for conditional step ID display.

import { RunTimeline } from "@cuitty/pilot-solid";

const events = createRunEvents(() => runId);
<RunTimeline events={events()} />

PlaybookCard

Displays a playbook summary card with an optional “Run” button. Uses <Show> to conditionally render the button.

import { PlaybookCard } from "@cuitty/pilot-solid";

<PlaybookCard
  playbook={playbook}
  onRun={(pb) => start({ playbookId: pb.id, mode: "autonomous" })}
/>
PropTypeDescription
playbookPlaybookSummaryPlaybook to display
onRun(playbook: PlaybookSummary) => voidOptional callback when “Run” is clicked

Error handling

Errors in createPlaybooks surface through the resource’s error state. For createRun, errors thrown during start() propagate to the caller. For direct PilotClient usage via usePilot(), catch typed errors 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