Columns

The five-column Kanban board — how tasks move through backlog, todo, in_progress, review, and done.

Columns

Every task in Shelbi lives in exactly one of five columns. Position within a column is a priority integer (0 = top), kept contiguous by the storage layer.

┌──────────┐   ┌──────┐   ┌─────────────┐   ┌────────┐   ┌──────┐
│ backlog  │ → │ todo │ → │ in_progress │ → │ review │ → │ done │
└──────────┘   └──────┘   └─────────────┘   └────────┘   └──────┘
   you            you      orchestrator        poller      you
   (triage)       (promote)  (auto-dispatch)   (marker)   (accept)

The mover changes between columns. Each transition is an intentional handoff between you, the orchestrator, and the hub poller — and that ownership boundary is what keeps the workflow predictable.

Defined in crates/shelbi-core/src/model.rs as the Column enum.

The five columns

backlog

The orchestrator's inbox. Anything it creates from a natural-language request lands here. The user has not committed to running it yet.

Cards are markdown files at ~/.shelbi/projects/<name>/tasks/<id>.md with frontmatter and a body — the body is what the worker eventually sees as its initial prompt.

Who moves things in: the orchestrator (or you, via shelbi task add). Who moves things out: you, after triage.

todo

User-curated, ready for a worker to pick up. Order within todo is your priority order — the orchestrator dispatches from the top.

A task in todo is the start signal for auto-dispatch. As soon as this column changes (or a worker frees up), the orchestrator considers this column for routing.

Who moves things in: you. Who moves things out: the orchestrator (via shelbi task start).

in_progress

Assigned to a worker and running. The card's assigned_to field is set, its branch is set, and the worker's tmux pane is alive with the agent running the task.

A task is blocked (and skipped by auto-dispatch) while any id in depends_on is not yet done. The Kanban renders blocked cards with a 🔒 badge; they sit in todo until their dependencies clear.

Who moves things in: the orchestrator. Who moves things out: the hub poller, when it observes the worker's review marker.

review

The worker reported done. Its branch has commits ready for inspection. The card lands here automatically the moment the poller reads a non-empty review-ready marker from the worker's worktree (<worktree>/.claude/shelbi-review-ready) — no extra step on the worker's part. See the worker review marker section below.

The sidebar's — Ready for Review — list mirrors this column. Activating a row from there (or running shelbi review <id>) checks the branch out into the review pane and spawns a fresh Claude window pointed at the diff.

Who moves things in: the hub poller. Who moves things out: you, after accepting the diff.

done

Accepted. The task is finished from Shelbi's point of view; the branch has typically been squash-merged into main.

Done is a user signal — moving cards here means "I've reviewed and accepted this work." The orchestrator never makes this move on its own (except under specific authorized loops the user has opted into).

Who moves things in: you.

What each transition means

FromToMoverReason string
backlogtodoyouuser:cli, user:tui:…
todoin_progressorchestratoruser:cli:start, orchestrator:auto-dispatch worker=<name>
in_progressreviewhub pollerworker:review-marker
reviewdoneyouuser:cli, user:tui:…

Each move appends one line to ~/.shelbi/events.log:

2026-06-22T14:22:11+00:00 task=fix-login todo -> in_progress reason=orchestrator:auto-dispatch_worker=bravo
2026-06-22T14:24:03+00:00 task=fix-login in_progress -> review reason=worker:review-marker

The reason tag is how downstream consumers (mainly the orchestrator) tell user intent from automation. Always pass --reason when moving cards from the CLI — it costs nothing and makes the log far easier to reason about. See the events log for the full vocabulary.

Review-marker promotion

The in_progressreview transition does not need any active participant. The worker doesn't run a shelbi command. The orchestrator doesn't watch the worker's pane. Instead:

  1. The worker, when done, writes its task id into <worktree>/.claude/shelbi-review-ready. This instruction is part of the initial prompt every task ships with (see compose_prompt in crates/shelbi-orchestrator/src/worker.rs).
  2. The hub poller cats that file on every tick (locally for hub workers, via SSH for remote ones).
  3. If the file is non-empty and names a task that's in_progress for this worker, the poller moves the task to review, clears the marker, and appends task=<id> in_progress -> review reason=worker:review-marker to the events log.

The orchestrator hears about it through its shelbi events tail --follow feed and dispatches the next ready task to the now-free worker.

That this works without the worker holding any Shelbi-specific state is the point. The marker is the entire on-worker protocol — see the workers concept page for the rationale.

Why the user owns triage and accept

Two transitions are deliberately not automated:

  • backlogtodo is yours. The orchestrator creates whatever cards it likes from natural-language requests, but it can't decide which of them are worth doing right now, or in what order. That's a product decision — the orchestrator is the wrong agent to make it.
  • reviewdone is yours. Accepting a diff is the moment the human signs off on the work. Automating it would defeat the point of the review column.

Everything in between — assignment, branch setup, dispatch, completion detection — is automation. The user owns the intent boundaries; the system handles the mechanical middle.

(There is one carve-out: the orchestrator can be told, in writing, to auto-merge and move to done for specific multi-task loops the user has authorized. That's an explicit override of the default rule, not the default behavior.)

CLI reference

  • shelbi task add "Title" — create a card in backlog (the default).
  • shelbi task list / shelbi task show <id> — read the board.
  • shelbi task move <id> --to <column> [--reason <r>] — move between columns. Pass --reason so the event line is tagged.
  • shelbi task prio <id> --top|--up|--down|--bottom|--set N — reorder within a column.
  • shelbi task start <id> [--worker NAME] [--reason <r>] — assign and launch (this is what produces the todoin_progress transition).
  • shelbi review <id> — check the branch out into the review pane.

See also

  • Workers — what's on the receiving end of an in_progress assignment.
  • The events log — the shape of every task transition line.
  • The orchestrator — how todoin_progress actually gets decided.