BoardPanel React module and reads GET /api/board; the detail drawer (TaskDetailDrawer) reads GET /api/board/:taskId, GET /api/board/:taskId/executions, and GET /api/board/:taskId/workspace/detail. For the underlying model, the state machine, the atomic claim, and dependency chains, see The board. For the full request/response shapes, see the Board API reference.

Prerequisites
The Board panel is always available. Its subsystem is always on, so the panel renders real content with no feature gate; an empty board is just a board with no tasks yet.
- A running Clawboo dashboard (
clawboo). - Tasks on the board. Tasks appear when a team delegates work in group chat, when an agent claims work, or when you create one directly via
POST /api/board. A fresh install with no team activity shows empty columns.
Open the board
Click Board (the kanban-square icon) in the primary nav of the left sidebar, or pressCmd/Ctrl + 4. The panel mounts in the main content area.
The number shortcuts cover the four sidebar work surfaces only:
Cmd/Ctrl+1 Atlas, +2 Fleet, +3 Marketplace, +4 Board. Everything else (Scheduler, Tokens Used, System, and the rest) lives in the Settings modal (Cmd/Ctrl+,).The columns
The board renders seven status columns, one per task status, in lifecycle order:
Ahead of those sits a Needs approval column, always the first column on the board. It is scoped to the team filter, collapses to a thin rail when there is nothing pending, and auto-expands the moment a request arrives. It is fed by its own poll rather than by
GET /api/board, so a board outage never hides a pending, time-sensitive gate. See Approvals.
Each column shows its label and a live count of the tasks in it. The panel header shows a total task count ({N} tasks) and polls GET /api/board every five seconds, so status changes and new tasks appear without a manual refresh. A Refresh button forces an immediate re-fetch.
Those reads overlap on purpose (the poll, the Refresh button, and the reconcile that follows a manual create all share one path), so they are sequenced: a response may only update the board while it is still the newest read and no local change has been committed since it was issued. A read that resolves out of order is discarded and the next poll reconciles instead, so a card you just created or dragged is never briefly reverted by a request that was already in flight.
Because the board is a live projection of agent activity — cards are created and moved by agents as they work — a one-line hint under the header (“AI agents continuously create and move work. You can also manage tasks manually.”) sets that expectation up front. The manual path is real, though, and there are three ways to drive the board by hand: a New task button in the header opens a composer, each task’s status is editable from its detail drawer, and you can drag a card between columns (see below).
A task whose status falls outside the canonical seven is not silently dropped; an Other column is appended only when such a task exists, so off-list statuses stay visible and counted.
Until the first fetch resolves, the board shows skeleton columns. If that first fetch fails, the board shows a “Couldn’t load the board” error with a Retry link (distinct from a genuinely empty board). A transient poll failure after a good load keeps the last good snapshot rather than blanking an actively-watched board.
Creating a task manually
The header’s New task button opens a small composer for adding work to the board by hand — the human counterpart to agent delegation. It collects a title (required), an optional description, a team (prefilled from the active team filter), and an initial status (To do by default, or Backlog for triage), then writes it throughPOST /api/board. On success the task appears on the board immediately (optimistically, then reconciled by the next poll) and a toast confirms it; a poll that was already in flight when the task was created is discarded rather than blanking the new card. A failed write keeps the composer open and toasts the error. Once on the board, a manually-created task is indistinguishable from a delegated one — an agent can claim and run it normally.
Moving a task by drag-and-drop
Each card has a grip handle (top-right, visible on hover or keyboard focus). Dragging a card to another column is a status change: it writes through the samePATCH /api/board/:taskId path as the drawer’s status editor, so the server stays authoritative and the same rules apply.
- Only legal moves are offered. Mid-drag, columns the card can’t legally transition to (per the state machine) are dimmed and won’t accept a drop; terminal cards (
done/cancelled) and off-list Other cards aren’t draggable at all. - The agent-release guard still applies. Dragging an assigned task to To do — which unassigns its agent — asks for confirmation first, exactly as the drawer editor does.
- Optimistic + poll-safe. The card moves instantly and is reconciled against the server; a rejected move (e.g. a
→ doneverification gate) rolls back with a toast. Neither an in-flight move nor a just-committed one is reverted by the five-second poll, including a poll already in flight when the move landed. - Keyboard and touch. Focus a card’s handle and press Space to pick it up, arrow keys to choose a column, Space to drop, Escape to cancel; touch drag is supported too.
Task cards
Each task is a card showing its title plus a row of badges:- Runtime badge: the task’s
assigneeRuntime(the runtime that owns the work), defaulting toopenclawwhen unset. - Verification badge: present only once a verification verdict is stored. The card parses the task’s
verificationJSON and renders the verdict:pass(green),fail(red), ordebtforcompleted_with_debt(amber). - Cost: the task’s
costUsd, shown only when a cost is recorded. An exactly-zero cost reads$0.000; a sub-cent cost keeps four decimals ($0.0004) so a real charge is never rounded away; a cost of one cent or more shows cents ($0.42). - Sub badge: a “sub” marker when the task has a
parentTaskId(it was spawned by a delegation).
The task-detail drawer
Clicking a card slides in a right-hand drawer (TaskDetailDrawer) for that task. It loads three reads in parallel: the task itself, its execution ledger, and its workspace detail, and presents them as sections. Press Escape or click the scrim to close.

Overview
The task’s core fields: Status, Assignee (assigneeAgentId), Runtime (assigneeRuntime, default openclaw), Cost (costUsd to four decimals), and Parent (a truncated parentTaskId, shown only for subtasks).
Status is an inline editor, not just a label: a dropdown that offers only the transitions the state machine permits from the current status (so it never lets you pick a move the server would reject), writes through PATCH /api/board/:taskId, and updates optimistically, rolling back and toasting if the write is refused, with the message naming the cause (an illegal transition vs. the verification gate). A committed change also moves the card to its new column on the board immediately rather than waiting for the five-second poll; it goes through the same shared commit path as drag-and-drop, so a read already in flight can’t snap the card back. Releasing a task to To do additionally clears its assignee, runtime, and stored verdict, so the card’s verification badge disappears and its runtime badge falls back to openclaw, matching what the server writes. Terminal tasks (done / cancelled) have no legal moves, so the control locks.
When a → done is refused specifically by the verification gate (the task carries a non-promotable verdict), the editor doesn’t dead-end: it offers a “Complete anyway” confirmation that re-submits with the server’s humanOverride. That’s the supported path for a human shipping despite a non-promotable verdict — and, like on the server, the override is recorded in the audit log. An illegal transition can’t be overridden this way (the override only bypasses the verification gate, not the state machine). This lives in the shared status-mutation path, so it works the same whether you change status from this drawer or by dragging a card to the Done column.
Verification
The stored verification verdict, if any. When present, it shows the verdict pill (pass / fail / completed_with_debt), the reviewer that produced it (runtime and model, surfaced so you can judge a same-model review’s independence caveat), any debt notes, and any critic findings (severity + title). When the task has no verdict it reads “No verification verdict yet”; unverified is not failing; an un-run gate does not block a task.
Workspace
The per-task git worktree detail, read fromGET /api/board/:taskId/workspace/detail:
- Branch (
clawboo/task-<id>) and the absolute Worktree path. - A Diff summary (
N files, +insertions −deletions). - System-of-record files:
TASK.md,task-progress.md,DECISIONS.json,init.sh,VERIFICATION.md,AGENT_HANDOFF.json(only those present), each as a collapsible disclosure showing its contents. - The unified diff against the branch-point baseline (the SoR bookkeeping files are excluded from it).
Execution ledger
Every spawned run for the task (GET /api/board/:taskId/executions), oldest first. Each row shows the executor (executorType), the run’s status, its cost, and its token counts (input↓ output↑). When a run carries an error, that failure reason is shown inline beneath the row; this is where a silently-failed delegate surfaces its reason.
Activity
A live terminal (ActivityTerminal) scoped to this task, the streaming tool-call / tool-result / error feed for the task’s runs. It tails the observability event log, so you can watch a run progress in real time. See Observability.
Comments
The task’s comments (discussion and system notes), each prefixed by itsauthorType. The agent report-up summary that a child writes when it finishes a delegation lands here as a comment.
Lineage / deps
The task’s ancestor chain (the parent-task lineage from the recursive-CTEancestors read), rendered as a chain of short ids (a1b2c3d4 → …). A top-level task reads “Top-level task (no ancestors).”
The chat-fused board
In group chat the board is not a separate tab; task cards are interleaved directly into the conversation timeline. When the leader delegates, that delegation becomes a board task, and aBoardTaskCard appears inline at the moment the task was created.
How it works:
- Projection store.
GroupChatPanelrenders cards from a read-only board projection store (useBoardStore), not from the chat transcript. On opening a team it loads the authoritative snapshot viaboardClient.listTasks(teamId)(aGET /api/board?teamId=…read), so the cards survive a page refresh. The orchestrator’s client-derived change-feed then applies live mutations (applyChange) to the same store, merged last-write-wins byupdatedAt. - Interleaving by
createdAt. Each non-cancelledboard task is placed into the timeline at itscreatedAttimestamp, alongside the chat blocks and any live streaming cards. So a task card appears in causal position, right where the delegation happened, and is not appended to the bottom. - Live status. The
BoardTaskCardshows the task title, a status pill (Queued → Working → Review → Done / Blocked), and the assignee’s avatar + name. As the board change-feed flips the task’s status, the card’s pill updates in place. A completed (done) card also shows the report-up summary; because the summary is a board comment (not a task-row field), a card reloaded after a refresh fetches it lazily fromGET /api/board/:taskId.
The chat-fused board cards and the standalone Board panel read the same canonical board. The panel is the cross-team operator view; the inline cards are the per-team narration. Neither is a write path back to the board; a chat message describes a decision; the board mutation is the decision.
Verify it worked
- Open Board. The header shows
{N} tasks, and tasks sit in the column matching their status. Click a card and confirm the drawer’s Overview status matches the card’s column. - In a team’s group chat, delegate a piece of work and watch a
BoardTaskCardappear inline with a Working pill, then flip to Done with a summary when the run completes. - Refresh the page; the inline cards reload from
GET /api/board?teamId=…(refresh-survival), and the panel re-polls. Both show the same task state. - For the raw data, fetch it directly:
Troubleshooting
“Couldn’t load the board.” The first
GET /api/board failed (server not up, or a transient error). Use the Retry link. If it persists, confirm the dashboard is running and reachable on its API port (default 18790).Related
- The board, the state machine, atomic claim, dependency chains, and reconciliation
- Board API, full request/response shapes for every board route
- Verification, builder≠judge, the deterministic gate + critic,
completed_with_debt - Worktrees and handoff, the per-task system-of-record behind the Workspace tab
- Delegation and orchestration, how delegations become board tasks
- Group chat, where the chat-fused board cards appear
- Observability, the event log behind the Activity terminal