Kanban API
Components, hooks, adapters, and types for the SDK's Kanban module. All symbols import from @cadraos/sdk/kanban except client.kanban, which is a resource on CadraClient from @cadraos/sdk.
client.kanban
Low-level REST methods exposed on every CadraClient instance. Use these directly when you need full control, or let the higher-level components call them for you.
| Method | Signature | Description |
|---|---|---|
| getBoard | () => Promise<KanbanBoard> | Auto-provisions the org board on first call |
| listCards | (input?: ListCardsInput) => Promise<CardList> | Optional lane / type / limit / offset filters |
| createCard | (input: CreateCardInput) => Promise<KanbanCard> | Never auto-retried on network failure |
| getCard | (cardId: string) => Promise<KanbanCard> | cardId is the integer PK as a string, NOT the execution UUID |
| updateCard | (cardId: string, patch: { title?; description?; sharedContext? }) => Promise<KanbanCard> | Partial patch — omitted fields are left unchanged |
| transitionCard | (input: TransitionCardInput) => Promise<KanbanCard> | Manual lane move; validates against allowed transitions |
| getCardRun | (executionId: string) => Promise<AgentExecution> | Poll fallback; use streamCardRun for live updates |
| streamCardRun | (executionId: string) => ExecutionStreamController | Attach .on() listeners then call .connect() |
const board = await client.kanban.getBoard();
const cards = await client.kanban.listCards({ lane: 'review', limit: 20 });
const card = await client.kanban.createCard({ title: 'Q4 report', lane: 'todo' });
const stream = client.kanban.streamCardRun(card.executionId!);
stream.on('textDelta', ({ delta }) => process.stdout.write(delta));
stream.on('complete', ({ execution }) => console.log(execution.status));
await stream.connect();KanbanBoard
Full-featured board component. Requires a KanbanAdapter and renders lanes, cards, and a run-stream drawer. For agent-config-driven boards see AgentBoard.
| Prop | Type | Description |
|---|---|---|
| adapter | KanbanAdapter (required) | Data-access layer; use createDefaultKanbanAdapter or supply your own |
| onCreateCard | (lane: KanbanLane) => CreateCardInput | null | undefined | Return input to create, or null/undefined to cancel |
| onRetryCard | (card: KanbanCard) => void | Called when the user clicks Retry on a failed card |
| onError | (message: string) => void | Surface adapter or transition errors in your own UI |
| onCardCreated | (card: KanbanCard) => void | Fires after the card is persisted and visible in the board |
| enableCreate | boolean (default true) | Show the "New card" button in each lane header |
| enableEdit | boolean (default true) | Allow editing card title / description from the drawer |
| enableAdvance | boolean (default true) | Show Approve / Advance button for human-gate lanes |
| pollIntervalMs | number | Background poll interval for cards without an active stream |
| className | string | CSS class applied to the board root element |
AgentBoard
Extends KanbanBoard with agent-config-driven lane/transition resolution. Fetches board configuration via BoardConfigClient and derives the card source from the resolved config. All KanbanBoardProps (except adapter) pass through.
| Prop | Type | Description |
|---|---|---|
| configClient | BoardConfigClient (required) | Resolves board config by UUID; see BoardConfigClient section |
| boardConfigUuid | string (required) | UUID of the board configuration to load |
| version | number | Pin to a specific config version; defaults to the active version |
| cardSource | AgentBoardCardSource (required) | Defines how cards are fetched for this board's data domain |
CardDrawer
Slide-over drawer that shows card detail, the live agent run stream, and transition controls. Used internally by KanbanBoard but can be mounted standalone when you manage selection state yourself.
| Prop | Type | Description |
|---|---|---|
| card | KanbanCard | null (required) | Card to display; null closes the drawer |
| adapter | KanbanAdapter (required) | Used to stream the card's agent run |
| onClose | () => void | Called when the drawer requests to be dismissed |
| onRetry | (card: KanbanCard) => void | Called when the user clicks Retry on a failed run |
| onUpdate | (cardId: string, patch: { title?; description?; sharedContext? }) => void | Promise<void> | Persist card edits; awaited before optimistic state is committed |
| onAdvance | (cardId: string) => void | Promise<void> | Called when the Approve / Advance button is clicked |
| canAdvance | boolean (default true) | Controls visibility of the Advance button |
| transitions | KanbanTransition[] | Override allowed transitions shown in the move menu |
| lanes | KanbanLane[] | All lanes — used to resolve lane labels in the drawer |
| onTransition | (cardId: string, toLane: string) => void | Promise<void> | Called when a manual lane move is confirmed |
| onRunTerminal | (status: 'completed' | 'failed') => void | Fires when the streamed run reaches a terminal state; trigger a board refresh here |
| onError | (message: string) => void | Stream or transition error handler |
| className | string | CSS class applied to the drawer panel |
useKanbanBoard
Core hook that powers KanbanBoard. Use it directly when you need custom board UI while keeping the SDK's state management.
UseKanbanBoardOptions
| Prop | Type | Description |
|---|---|---|
| adapter | KanbanAdapter (required) | Data-access layer for all board operations |
| autoLoad | boolean (default true) | Fetch board + cards on mount; set false to defer |
| onError | (message: string) => void | Called on any adapter error |
| onCardCreated | (card: KanbanCard) => void | Fires after a card is created and added to local state |
| onTransition | (card: KanbanCard, toLane: string) => void | Fires after a successful lane transition |
| pollIntervalMs | number | Background poll interval in milliseconds |
UseKanbanBoardResult
| Property | Type | Description |
|---|---|---|
| board | KanbanBoard | null | Raw board record; null until first load completes |
| lanes | KanbanLane[] | Ordered lane definitions for the board |
| cards | KanbanCard[] | All cards, flat — use cardsByLane for column rendering |
| cardsByLane | Record<string, KanbanCard[]> | Cards keyed by lane slug; ready for column rendering |
| selectedCard | KanbanCard | null | Currently open card (drives CardDrawer open state) |
| isLoading | boolean | True during initial board + card fetch |
| error | string | null | Last error message, or null when healthy |
| refresh | () => void | Full reload; shows loading state |
| silentRefresh | () => void | Reload without toggling isLoading (post-run sync) |
| openCard | (cardId: string) => void | Set selectedCard by card ID |
| closeCard | () => void | Clear selectedCard |
| createCard | (input: CreateCardInput) => Promise<KanbanCard> | Create and optimistically insert into cards state |
| updateCard | (cardId: string, patch: { title?; description?; sharedContext? }) => Promise<void> | Persist patch and update local state on success |
| transitionCard | (input: TransitionCardInput) => Promise<void> | Move card to a new lane and update local state |
| handleRunTerminal | (status: 'completed' | 'failed') => void | Pass to CardDrawer's onRunTerminal; triggers silentRefresh |
createDefaultKanbanAdapter
Factory that builds a KanbanAdapter backed by the Cadra REST API. Pass either a pre-configured CadraClient or the raw connection fields — not both.
import { createDefaultKanbanAdapter } from '@cadraos/sdk/kanban';
// Option A — reuse an existing CadraClient
const adapter = createDefaultKanbanAdapter({ client });
// Option B — supply connection fields directly
const adapter = createDefaultKanbanAdapter({
baseUrl: 'https://api.cadraos.com',
tokenProvider: async () => await getSessionToken(),
orgId: 42,
});DefaultKanbanAdapterConfig
| Field | Type | Description |
|---|---|---|
| client | CadraClient | Pre-configured client; takes precedence over the fields below |
| baseUrl | string | Cadra API base URL (e.g. https://api.cadraos.com) |
| apiKey | string | Static API key for server-side usage |
| token | string | Static bearer token (not refreshed) |
| tokenProvider | () => Promise<string> | Async token getter; called before each request |
| orgId | number | Organisation ID scoping all board operations |
KanbanAdapter
Interface you implement to connect the board to a custom backend. Return the same shapes as the default REST adapter — the components and hook only care about this contract.
| Method | Signature | Description |
|---|---|---|
| getBoard | () => Promise<KanbanBoard> | Fetch or provision the board |
| listCards | (input?: ListCardsInput) => Promise<CardList> | Return cards, honouring any filter input |
| createCard | (input: CreateCardInput) => Promise<KanbanCard> | Persist a new card and return it |
| getCard | (cardId: string) => Promise<KanbanCard> | Fetch a single card by integer PK string |
| updateCard | (cardId: string, patch: { title?; description?; sharedContext? }) => Promise<KanbanCard> | Apply a partial patch and return the updated card |
| transitionCard | (input: TransitionCardInput) => Promise<KanbanCard> | Move card to new lane; validate transitions server-side |
| createRunStream | (executionId: string) => ExecutionStreamController | Optional. If absent the drawer falls back to polling via getCardRun |
BoardConfigClient
Resolves and caches board configurations by UUID. Used by AgentBoard but also useful when you need to inspect config details before rendering.
| Method | Signature | Description |
|---|---|---|
| getActive | (uuid: string) => Promise<ResolvedBoardConfig> | Fetch the currently active (published) version of a board config |
| getPinned | (uuid: string, version: number) => Promise<ResolvedBoardConfig> | Fetch a specific version; useful for canary / A-B rollouts |
| clearCache | () => void | Evict all cached resolutions; call after a config publish |
Types
Illustrative shapes for the consumer-facing types. Full definitions — including every optional field — ship with the package .d.ts.
// @cadraos/sdk/kanban — key consumer types
interface KanbanCard {
id: string; // integer PK serialised as string (use for getCard, updateCard)
executionId?: string; // agent run UUID (use for streamCardRun / getCardRun)
currentLane: string; // slug of the lane this card is currently in
title: string;
description?: string;
type?: string; // card type tag (e.g. "task", "approval")
sharedContext?: Record<string, unknown>; // arbitrary metadata passed to the agent
// run summary fields populated after the agent run completes
// ...
}
interface KanbanLane {
id: string;
slug: string;
label: string;
order: number;
// ...
}
interface KanbanTransition {
fromLane: string;
toLane: string;
label?: string;
requiresApproval?: boolean;
// ...
}
interface CreateCardInput {
title: string;
lane?: string; // defaults to the board's entry lane
description?: string;
type?: string;
sharedContext?: Record<string, unknown>;
// ...
}
interface TransitionCardInput {
cardId: string;
toLane: string;
reason?: string;
// ...
}
interface ListCardsInput {
lane?: string;
type?: string;
limit?: number;
offset?: number;
// ...
}