Problem
The orchestrator-owned pipeline spec intentionally stops at in_review:
"Success means in_review, not done. done is a human decision."
However, the minimal implementation provides no tooling for the human to complete this loop. Today, a reviewer who wants to approve or reject an issue must:
- Manually inspect the workspace and run records
- Edit JSON files by hand (
summary.json, decision.json)
- Use
git directly to merge or discard work
- Run ad-hoc scripts to move the issue state on the board
This is a chore. Adding a small CLI surface for review operations makes the human gate ergonomic and closes the lifecycle gap.
Goals
- Add a
contrabass board subcommand group for human review operations
- Provide read-only inspection commands (list, show)
- Provide state-transition commands (approve, reject, retry)
- Operate on both the local board and (eventually) external trackers via the
IssueTracker interface
- Keep the CLI simple — no interactive prompts, just flags and args
Non-Goals
- Interactive TUI for review (the Bubble Tea TUI already shows the review queue)
- Automatic merge / push to origin (the human decides when and how to merge)
- Code review diff rendering in the terminal (use
git diff or your editor)
- Email / Slack notifications
Command Specification
contrabass board list [flags]
List issues by state.
# List all issues in review
contrabass board list --state in_review
# List all issues
contrabass board list --all
# List with retry queue
contrabass board list --state retry_queued
Output format (tabular, terminal-friendly):
ID STATE TITLE BRANCH ATTEMPTS READY
CB-1 in_review Fix login bug opencode/CB-1 2 12m ago
CB-2 retry_queued Add OAuth flow - 3 -
CB-3 todo Refactor auth middleware - - -
Flags:
--state — filter by state (todo, in_progress, retry_queued, in_review, done)
--all — show all states
--config — path to WORKFLOW.md (reuses existing global flag)
contrabass board show <issue-id>
Display the full review package for an issue.
contrabass board show CB-1
Output:
Issue: CB-1
Title: Fix login bug
State: in_review
Branch: opencode/CB-1
Workspace: /path/to/.worktrees/CB-1
Attempts: 2
Ready: 12m ago
Stages:
✓ plan (attempt #1, 2m 15s)
✓ execute (attempt #1, 5m 30s, commit: a1b2c3d)
✓ verify (attempt #2, 3m 10s)
Review handoff:
All stages completed for CB-1.
Workspace: /path/to/.worktrees/CB-1
Branch: opencode/CB-1
Run records:
.contrabass/projects/<project>/runs/CB-1/
This command reads from:
internal/tracker/local.go (or whichever tracker is configured) for issue metadata
internal/diagnostics/recorder.go for attempt history, stage results, and handoff notes
- Git state in the workspace for branch/commit info
contrabass board approve <issue-id> [flags]
Approve an issue and mark it as done.
contrabass board approve CB-1
contrabass board approve CB-1 --message "LGTM, merged manually"
Actions:
- Fetch the issue from the tracker
- Verify it is in
in_review state (fail fast otherwise)
- Write a
review/decision.json artifact via the diagnostics recorder:
{
"decision": "approved",
"reviewed_by": "human",
"reviewed_at": "2026-04-25T12:00:00Z",
"notes": "LGTM, merged manually",
"follow_up_state": "done"
}
- Update the tracker state to
done
- Print confirmation with workspace path and branch name (reminding the user to merge if they haven't)
Flags:
--message — optional review note
contrabass board reject <issue-id> [flags]
Reject an issue and return it to todo.
contrabass board reject CB-1
contrabass board reject CB-1 --message "Needs tests for edge cases"
Actions:
- Fetch the issue
- Verify it is in
in_review state
- Write
review/decision.json with "decision": "rejected"
- Update tracker state to
todo
- Optionally clean up the workspace? No — the human may want to inspect the rejected work. Print the workspace path instead.
Flags:
--message — required? No, but strongly encouraged. Empty string is allowed.
contrabass board retry <issue-id>
Manually retry a failed or rejected issue immediately.
contrabass board retry CB-1
Actions:
- Fetch the issue
- Verify it is in
retry_queued or todo state
- Update tracker state to
todo (ensures orchestrator will pick it up on next poll)
- Print confirmation
This is a convenience command for "I fixed the environment, retry this now" without waiting for backoff.
Implementation Plan
Phase 1: Core command scaffolding
- Add
cobra (or stick with flag if you want to keep deps minimal)
- The reference Contrabass uses
spf13/cobra for subcommands. Adding it is reasonable.
- Create
cmd/contrabass/board.go with the subcommand definitions
- Wire the same config → tracker → recorder initialization that
main.go already does
Phase 2: Read commands (list, show)
list: Query tracker, format as table using text/tabwriter
show: Query tracker + recorder, format multi-line output
Phase 3: Write commands (approve, reject, retry)
approve / reject: Validate state, write decision artifact, update tracker
retry: Validate state, force to todo
Data Access
The board commands need access to:
IssueTracker — for fetching and updating issues
diagnostics.Recorder — for reading attempt history and writing decisions
config.Config — for board directories and workspace paths
Refactor cmd/contrabass/main.go to extract a shared setup() function that returns (cfg, tracker, workspace, recorder) so both run() and the board commands can reuse it.
Edge Cases & Error Handling
| Scenario |
Behavior |
Approve an issue not in in_review |
Error: "CB-1 is in state 'todo', expected 'in_review'" |
| Reject with no message |
Warn: "No rejection note provided. Consider adding --message." |
| Show an issue that has no run records |
Print issue metadata, omit attempts/stages sections |
Board command with missing WORKFLOW.md |
Same error behavior as main orchestrator |
| Tracker returns error on state update |
Surface error, do not write partial decision artifact |
Existing Reference
The reference Contrabass has cmd/contrabass/board.go which implements contrabass board subcommands with Cobra. It supports list, show, create, move, comment, delete, sync, and reset. Use it for command structure inspiration, but keep the minimal version focused only on review lifecycle commands.
See also:
docs/references/contrabass/cmd/contrabass/board.go
docs/references/contrabass/cmd/contrabass/team_board.go (team-scoped board ops)
Files to Create / Modify
- Create:
cmd/contrabass/board.go — Cobra subcommands (list, show, approve, reject, retry)
- Create:
cmd/contrabass/board_test.go — unit tests with mock tracker and in-memory recorder
- Modify:
cmd/contrabass/main.go — extract shared setup into buildDeps() helper; add cobra root command
- Modify:
internal/diagnostics/stages.go — ensure RecordReviewDecision is exported and usable from CLI
Acceptance Criteria
Problem
The orchestrator-owned pipeline spec intentionally stops at
in_review:However, the minimal implementation provides no tooling for the human to complete this loop. Today, a reviewer who wants to approve or reject an issue must:
summary.json,decision.json)gitdirectly to merge or discard workThis is a chore. Adding a small CLI surface for review operations makes the human gate ergonomic and closes the lifecycle gap.
Goals
contrabass boardsubcommand group for human review operationsIssueTrackerinterfaceNon-Goals
git diffor your editor)Command Specification
contrabass board list [flags]List issues by state.
Output format (tabular, terminal-friendly):
Flags:
--state— filter by state (todo,in_progress,retry_queued,in_review,done)--all— show all states--config— path toWORKFLOW.md(reuses existing global flag)contrabass board show <issue-id>Display the full review package for an issue.
Output:
This command reads from:
internal/tracker/local.go(or whichever tracker is configured) for issue metadatainternal/diagnostics/recorder.gofor attempt history, stage results, and handoff notescontrabass board approve <issue-id> [flags]Approve an issue and mark it as
done.contrabass board approve CB-1 contrabass board approve CB-1 --message "LGTM, merged manually"Actions:
in_reviewstate (fail fast otherwise)review/decision.jsonartifact via the diagnostics recorder:{ "decision": "approved", "reviewed_by": "human", "reviewed_at": "2026-04-25T12:00:00Z", "notes": "LGTM, merged manually", "follow_up_state": "done" }doneFlags:
--message— optional review notecontrabass board reject <issue-id> [flags]Reject an issue and return it to
todo.contrabass board reject CB-1 contrabass board reject CB-1 --message "Needs tests for edge cases"Actions:
in_reviewstatereview/decision.jsonwith"decision": "rejected"todoFlags:
--message— required? No, but strongly encouraged. Empty string is allowed.contrabass board retry <issue-id>Manually retry a failed or rejected issue immediately.
Actions:
retry_queuedortodostatetodo(ensures orchestrator will pick it up on next poll)This is a convenience command for "I fixed the environment, retry this now" without waiting for backoff.
Implementation Plan
Phase 1: Core command scaffolding
cobra(or stick withflagif you want to keep deps minimal)spf13/cobrafor subcommands. Adding it is reasonable.cmd/contrabass/board.gowith the subcommand definitionsmain.goalready doesPhase 2: Read commands (
list,show)list: Query tracker, format as table usingtext/tabwritershow: Query tracker + recorder, format multi-line outputPhase 3: Write commands (
approve,reject,retry)approve/reject: Validate state, write decision artifact, update trackerretry: Validate state, force totodoData Access
The board commands need access to:
IssueTracker— for fetching and updating issuesdiagnostics.Recorder— for reading attempt history and writing decisionsconfig.Config— for board directories and workspace pathsRefactor
cmd/contrabass/main.goto extract a sharedsetup()function that returns(cfg, tracker, workspace, recorder)so bothrun()and the board commands can reuse it.Edge Cases & Error Handling
in_reviewWORKFLOW.mdExisting Reference
The reference Contrabass has
cmd/contrabass/board.gowhich implementscontrabass boardsubcommands with Cobra. It supportslist,show,create,move,comment,delete,sync, andreset. Use it for command structure inspiration, but keep the minimal version focused only on review lifecycle commands.See also:
docs/references/contrabass/cmd/contrabass/board.godocs/references/contrabass/cmd/contrabass/team_board.go(team-scoped board ops)Files to Create / Modify
cmd/contrabass/board.go— Cobra subcommands (list,show,approve,reject,retry)cmd/contrabass/board_test.go— unit tests with mock tracker and in-memory recordercmd/contrabass/main.go— extract shared setup intobuildDeps()helper; addcobraroot commandinternal/diagnostics/stages.go— ensureRecordReviewDecisionis exported and usable from CLIAcceptance Criteria
contrabass board list --state in_reviewshows only issues awaiting reviewcontrabass board show CB-1displays stage completion, branch, workspace, and handoff textcontrabass board approve CB-1writesreview/decision.jsonand moves issue todonecontrabass board reject CB-1writesreview/decision.jsonand moves issue totodocontrabass board retry CB-1moves aretry_queuedissue back totodogo test ./cmd/contrabass/...passes with mock tracker coverage