Skip to main content
The Board API is the transactional source of truth for team task coordination. You create tasks, atomically claim them for a single assignee, transition their status through a fixed state machine, record execution runs, link dependency chains, and provision per-task git worktrees. Every write is validated by a Zod schema; an invalid body returns 400 with a details object carrying the schema errors.
The atomic claim is the board’s concurrency primitive. POST /api/board/:taskId/claim returns 409 when another worker already won. A 409 is data, not a transient error — do not retry it. The task is taken. The same rule applies to the 409 illegal_transition on PATCH /api/board/:taskId.

Task statuses

StatusTerminal?Notes
backlogNoTriage queue; not immediately claimable
todoNoReady to claim
in_progressNoClaimed and being worked
in_reviewNoWork complete, pending verification
blockedNoWaiting on a dependency or human input
doneYesVerified complete
cancelledYesAbandoned

Routes

MethodPathSummary
GET/api/boardList tasks for a team (or ready-to-work tasks)
POST/api/boardCreate a task
GET/api/board/:taskIdOne task plus comments and ancestor chain
POST/api/board/:taskId/claimAtomically claim a todo task
PATCH/api/board/:taskIdTransition status or edit metadata
POST/api/board/:taskId/commentsAdd a comment
GET/api/board/:taskId/executionsThe run ledger for a task
POST/api/board/:taskId/executionsOpen an execution row after a claim
PATCH/api/board/executions/:execIdClose an execution with its outcome
POST/api/board/:taskId/depsLink a dependency
POST/api/board/:taskId/cancel-dependentsCancel the dead downstream chain
POST/api/board/:taskId/workspaceProvision a git worktree
GET/api/board/:taskId/workspaceCold-resume read: workspace and reconstructed state
PATCH/api/board/:taskId/workspacePause or complete the worktree
POST/api/board/:taskId/workspace/handoffWrite the clock-out AGENT_HANDOFF.json
GET/api/board/:taskId/workspace/detailSoR file contents and unified diff

GET /api/board

Lists tasks for a team. With ready=true, returns only tasks whose dependencies are all done and that are immediately claimable (status: todo).
teamId
string
Scope results to one team. Omit for all teams.
status
string
Filter by one of the seven task statuses. Ignored when ready=true.
ready
string
Pass "true" to return only ready-to-work tasks. Overrides status and includeDropped.
includeDropped
string
Pass "true" to include soft-deleted tasks.

Response 200 OK

tasks
DbTask[]
The task list, newest updatedAt first. The ready variant orders by priority then updatedAt.
# Ready-to-work tasks for a team
curl 'http://localhost:18790/api/board?teamId=<team-id>&ready=true'

# All in-progress tasks
curl 'http://localhost:18790/api/board?teamId=<team-id>&status=in_progress'

POST /api/board

Creates a task. Defaults to status: "todo" (immediately claimable). Pass status: "backlog" for triage.

Request body

title
string
required
Task title. 1–500 chars.
description
string
Task description. Up to 20,000 chars.
status
string
Initial status. Defaults to "todo". One of the seven task statuses.
priority
number
Integer priority.
teamId
string
The team to assign this task to.
parentTaskId
string
Parent task id to make this a subtask. The parent chain bounds delegation depth.

Response 200 OK

{ "task": { "<DbTask>" } }
curl -X POST http://localhost:18790/api/board \
  -H 'Content-Type: application/json' \
  -d '{"title":"Implement /api/foo","teamId":"<team-id>","priority":1}'

POST /api/board/:taskId/claim

Atomically claims a todo task for a single assignee. At most one caller wins — the task flips to in_progress and the loser gets 409.
A 409 means another worker holds the task. Do not retry. A dead in_progress task is recovered by orphan reconciliation, which releases it back to todo.

Request body

assigneeAgentId
string
required
The agent id claiming the task. Must be non-empty.
assigneeRuntime
string
The runtime this agent runs on (e.g. claude-code, clawboo-native).

Responses

200 OK — the claim won; the task is now in_progress:
{ "ok": true, "task": { "<DbTask>" } }
409 Conflict — the task was not in a claimable state:
{ "ok": false, "error": "conflict" }
404 Not Found — the task does not exist:
{ "ok": false, "error": "not_found" }
curl -X POST http://localhost:18790/api/board/<task-id>/claim \
  -H 'Content-Type: application/json' \
  -d '{"assigneeAgentId":"native-leader-abc","assigneeRuntime":"clawboo-native"}'

PATCH /api/board/:taskId

Transitions a task’s status and/or edits its metadata. At least one field is required. The status change is enforced by the state machine — illegal transitions return 409. When the target status is done, the verification gate applies: a task with a failing deterministic verdict is rejected with 409 verification_required. Pass humanOverride: true to bypass the gate; the override is recorded in the governance audit log.
A task with no stored verification verdict is unverified, not failing — it lands done normally. The gate blocks known-failing verdicts, not un-run verification. Moving a task back to todo clears the assignee and verdict.

Request body

status
string
Target status. Must follow a legal state machine transition.
priority
number
Integer priority update.
title
string
Updated title (1–500 chars).
description
string
Updated description (up to 20,000 chars).
humanOverride
boolean
Audited bypass of the →done verification gate. Only meaningful with status: "done".

Responses

200 OK — the update was applied:
{ "ok": true, "task": { "<DbTask>" } }
409 Conflict — illegal transition or verification gate blocked →done:
{ "ok": false, "error": "illegal_transition" }
{ "ok": false, "error": "verification_required" }
# Transition to done (bypassing a failing gate, audited)
curl -X PATCH http://localhost:18790/api/board/<task-id> \
  -H 'Content-Type: application/json' \
  -d '{"status":"done","humanOverride":true}'

# Edit priority and title
curl -X PATCH http://localhost:18790/api/board/<task-id> \
  -H 'Content-Type: application/json' \
  -d '{"priority":5,"title":"Updated title"}'

GET /api/board/:taskId

Returns one task with its comments (oldest first) and its ancestor chain (parent-task lineage).

Response 200 OK

{
  task: DbTask
  comments: Array<{
    id: string
    taskId: string
    authorAgentId: string | null
    authorType: 'agent' | 'user' | 'system'
    body: string
    createdAt: number
  }>
  ancestors: Array<{
    id: string
    parent_task_id: string | null
    title: string
    status: string
  }>
}
curl http://localhost:18790/api/board/<task-id>

POST /api/board/:taskId/executions

Opens an execution-process row for a task — recorded immediately after a successful claim. The orphan reconciler reads this on restart; an executor that starts work must open one here and close it via the PATCH below, or a crash leaves the run orphaned.

Request body

executorType
string
required
The runtime id (e.g. claude-code, clawboo-native). 1–100 chars.
beforeCommit
string
Git SHA of the worktree at the start of the run (checkpoint).
runReason
string
Human-readable reason for this execution (up to 2,000 chars).

Response 200 OK

The created execution row starts in status: "running":
{
  ok: true
  execution: {
    id: string
    taskId: string
    executorType: string
    status: 'queued' | 'running' | 'succeeded' | 'failed' | 'timed_out' | 'cancelled'
    beforeCommit: string | null
    afterCommit: string | null
    inputTokens: number | null
    outputTokens: number | null
    costUsd: number | null
    summary: string | null
    error: string | null
    createdAt: number
  }
}
curl -X POST http://localhost:18790/api/board/<task-id>/executions \
  -H 'Content-Type: application/json' \
  -d '{"executorType":"claude-code","beforeCommit":"<sha>"}'

PATCH /api/board/executions/:execId

Closes an execution row with its outcome and an optional token/cost ledger.

Request body

status
string
required
Final execution status. One of succeeded, failed, timed_out, cancelled.
summary
string
Human-readable execution summary (up to 20,000 chars).
afterCommit
string
Git SHA of the worktree at the end of the run.
inputTokens
number
Input token count for billing.
outputTokens
number
Output token count for billing.
costUsd
number
USD cost of this execution.
error
string
Error message if the execution failed (up to 20,000 chars).
curl -X PATCH http://localhost:18790/api/board/executions/<exec-id> \
  -H 'Content-Type: application/json' \
  -d '{"status":"succeeded","inputTokens":1200,"outputTokens":340,"costUsd":0.012}'

GET /api/board/:taskId/executions

Lists a task’s execution-process rows (the full run ledger), oldest first.
curl http://localhost:18790/api/board/<task-id>/executions

POST /api/board/:taskId/deps

Links a dependency: the task in the path will not become ready until dependsOnTaskId reaches done.

Request body

dependsOnTaskId
string
required
The id of the blocking task. Both tasks must exist.
curl -X POST http://localhost:18790/api/board/<step-2-id>/deps \
  -H 'Content-Type: application/json' \
  -d '{"dependsOnTaskId":"<step-1-id>"}'

POST /api/board/:taskId/cancel-dependents

Cancels still-pending (todo/backlog) transitive dependents of a failed task. A blocked task can never become done, so its downstream chain is dead. Dependents already in_progress, done, or cancelled are left untouched.

Response 200 OK

{ "cancelled": [{ "id": "<task-id>", "title": "..." }] }
curl -X POST http://localhost:18790/api/board/<failed-task-id>/cancel-dependents

POST /api/board/:taskId/workspace

Provisions a git worktree + branch + system-of-record scaffold for a file-mutating task. The worktree lives outside the user’s repo so it never pollutes git status. Research and review tasks are refused (422) because they have no file mutations to isolate.

Request body

repoPath
string
required
Absolute path to the git repository to branch from.
kind
string
Task kind that determines isolation. code (default) → worktree; research / review → refused with 422.
baseRef
string
Branch point (default HEAD) when no baseSha is provided.

Responses

200 OK — the worktree was provisioned:
{
  ok: true
  worktree: {
    taskId: string
    worktreePath: string     // absolute path to the checkout
    branch: string           // 'clawboo/task-<id>'
    baseCommit: string
    detached: boolean
  }
  workspaceId: string
  isolation: 'worktree'
}
422 Unprocessable Entity — the task kind resolves to no worktree:
{ "ok": false, "error": "no_isolation", "isolation": "none" }
curl -X POST http://localhost:18790/api/board/<task-id>/workspace \
  -H 'Content-Type: application/json' \
  -d '{"repoPath":"/path/to/repo","kind":"code"}'

PATCH /api/board/:taskId/workspace

Pauses or completes the worktree.
  • pause — commits uncommitted work, drops the worktree, keeps the branch (stays active and resumable).
  • complete — runs the verification gate on the diff: a green deterministic gate promotes to done; a failing gate routes to blocked or in_progress.

Request body

action
string
required
Either "pause" or "complete".
curl -X PATCH http://localhost:18790/api/board/<task-id>/workspace \
  -H 'Content-Type: application/json' \
  -d '{"action":"pause"}'

POST /api/board/:taskId/workspace/handoff

Writes the clock-out AGENT_HANDOFF.json into the task’s worktree — structured data so a different runtime (or a human) can pick up the task cleanly.

Request body

handoffFrom
string
required
Who is handing off (agent id or "human").
runtime
string
required
The producing runtime (e.g. clawboo-native, claude-code, or "human").
completedSubtasks
string[]
List of subtasks completed in this session.
brokenOrUnverified
string[]
List of items that are broken or unverified.
nextBestStep
string
The recommended next action for whoever picks up the task.
curl -X POST http://localhost:18790/api/board/<task-id>/workspace/handoff \
  -H 'Content-Type: application/json' \
  -d '{
    "handoffFrom":"native-specialist-abc",
    "runtime":"clawboo-native",
    "completedSubtasks":["wired the route"],
    "nextBestStep":"stabilize the flaky e2e test"
  }'

GET /api/board/:taskId/workspace

Cold-resume read: the task’s workspace row plus the resume state reconstructed from the system-of-record files (AGENT_HANDOFF.json, task-progress.md, init.sh). A fresh runtime can pick up the task from the worktree alone using this endpoint.
curl http://localhost:18790/api/board/<task-id>/workspace

GET /api/board/:taskId/workspace/detail

Returns the SoR file contents (TASK.md, task-progress.md, DECISIONS.json, init.sh, VERIFICATION.md, AGENT_HANDOFF.json) plus the unified diff and diff-stat against the baseline. Bookkeeping files are excluded from the diff.
curl http://localhost:18790/api/board/<task-id>/workspace/detail

See also