A TUI that runs multiple Claude Code workers in parallel across git worktrees. Give it GitHub issues or a task DAG — it creates worktrees, launches Claude in tmux windows, tracks progress, reviews PRs, auto-merges, rebases, and self-heals crashed workers.
- Claude Code CLI (
claude) tmux/git/gh(GitHub CLI)- Rust toolchain (
cargo)
cargo install --path .The binary installs to ~/.cargo/bin/cwo.
cd your-repo
cwo init # generates cwo.toml with auto-detected settings
cwo init -i # interactive — prompts for each value
# Edit cwo.toml: add issues or tasks, then:
cwoList specific GitHub issues to work on:
session = "my-workers"
repo = "owner/repo"
repo_root = "/path/to/repo"
issues = [347, 348, 349]CWO fetches each issue, creates a worktree + branch, and launches Claude with the issue spec. On startup, a confirmation modal lets you review and select which pending issues to launch.
Define tasks with dependency ordering:
[[tasks]]
name = "api"
prompt = "Implement the REST API..."
[[tasks]]
name = "frontend"
prompt = "Build the React frontend..."
depends_on = ["api"]Tasks launch automatically when their dependencies complete. Use :dag status and :dag reset in the TUI.
Auto-extract tasks from a GitHub discussion issue:
run_builder = true
discussion_issue = 1CWO reads the discussion, calls Claude to extract implementable tasks, files GitHub issues, and launches workers — fully autonomous.
Fully autonomous issue processing — CWO picks open issues, prioritizes them, launches workers, merges PRs, resolves conflicts, and cycles through batches:
autopilot = true
autopilot_batch_size = 10
autopilot_labels = ["bug", "good first issue"]
autopilot_exclude_labels = ["wontfix", "discussion"]Each cycle: fetch open issues → analyze with Claude (priority, actionability, file areas) → select a conflict-minimizing batch → launch workers → monitor → merge PRs → resolve conflicts via tmux → repeat. Toggle on/off at runtime with A.
┌ Claude Worktree Orchestrator ──────────────────────────────────────────────────────┐
│ Session: my-workers │ Workers: 5 │ Active: 3 │ Idle: 1 │ PRs: 2 │ Merged: 5 │
├────────────────────────────────────────────────────────────────────────────────────┤
│ WORKER PHASE STATE LAST OUTPUT │
│ ▶ issue-326 [feat] ●→○ CODING 🟢 working Analyzing src/main.rs │
│ issue-327 [feat] ●→● PR READY ✅ complete Created pull request #42 │
│ issue-328 [feat] ●→○ PAUSED 🟡 waiting Would you like to proceed? │
│ t-api ●→○ CODING 🟢 working Writing endpoints... │
│ t-frontend ○→○ WAITING 🔗 waiting waiting on: api │
├────────────────────────────────────────────────────────────────────────────────────┤
│ s send t tmux i int x close b bcast m merge │ p prompt P direct n job N plan│
│ a action A autopilot U update d detail o output v pr l log c cfg ? q quit │
└────────────────────────────────────────────────────────────────────────────────────┘
| Key | Action |
|---|---|
j/k |
Navigate workers |
d/Enter |
Detail view — full pane scrollback + review notes |
o |
Output preview — last 40 clean lines in a compact popup |
s |
Send message to selected worker's Claude |
i |
Interrupt (Ctrl-C) selected worker |
b |
Broadcast to all idle workers |
n |
Launch worker for a GitHub issue number |
N |
Launch worker in plan mode (Claude plans, then waits) |
P |
Direct prompt — launch worker with raw text |
p |
Smart prompt — Claude extracts tasks, files issues |
m |
Merge all clean PRs |
M |
Merge selected worker's PR |
v |
Open PR in browser |
t |
Switch to selected worker's tmux window |
x |
Close selected worker (kill window + remove worktree) |
X |
Close all finished workers |
c |
Settings (live config editor) |
A |
Autopilot config |
a |
Run custom action on selected worker |
U |
Self-update (cargo install) |
l |
Toggle log panel |
r |
Force refresh |
: |
Command mode |
? |
Help |
q |
Quit |
In the launch confirm dialog (n/N), Tab focuses the branch or base-branch field for editing. When the branch field is focused, r regenerates the name with AI.
| Command | Description |
|---|---|
merge all |
Merge all clean PRs |
merge pr 42 |
Merge specific PR |
rebase all |
Fetch + rebase all workers |
broadcast <msg> |
Send to all idle Claude windows |
stats |
Session stats (merged, failed, avg time) |
usage |
Feature usage ranked by frequency |
dag status |
Show DAG completion state |
dag reset |
Reset DAG — re-launch all tasks |
All config in cwo.toml. Run cwo init to generate one.
| Field | Default | Description |
|---|---|---|
session |
— | Tmux session name |
repo |
— | GitHub repo (owner/name) |
repo_root |
— | Absolute path to git repo |
worktree_dir |
.claude/worktrees |
Worktree base dir (relative to repo_root) |
branch_prefix |
feature/issue- |
Prefix for created feature branches |
window_prefix |
issue- |
Tmux window name prefix for issue workers |
max_concurrent |
3 |
Max simultaneous workers |
issues |
[] |
GitHub issue numbers to offer on startup |
claude_flags |
["--dangerously-skip-permissions"] |
Flags for claude CLI |
post_worktree_create |
[] |
Commands to run in each new worktree after creation (e.g. ["mise trust", "pnpm install"]) |
| Field | Default | Description |
|---|---|---|
merge_policy |
"auto" |
"auto" / "review_then_merge" / "manual" |
auto_review |
true |
Spawn AI reviewers for new PRs |
review_timeout_secs |
600 |
Merge anyway after timeout (0 = wait forever) |
| Field | Default | Description |
|---|---|---|
auto_relaunch |
true |
Relaunch crashed workers |
max_relaunch_attempts |
3 |
Give up after N relaunches |
stale_timeout_secs |
300 |
Mark stale if no output change (0 = disabled); idle workers are exempt |
| Field | Default | Description |
|---|---|---|
autopilot |
false |
Enable autopilot mode |
autopilot_batch_size |
10 |
Max issues to analyze per batch |
autopilot_batch_delay_secs |
60 |
Delay between batches |
autopilot_labels |
[] |
Only process issues with these labels |
autopilot_exclude_labels |
[] |
Skip issues with these labels |
[[actions]]
name = "Add label"
command = "gh pr edit {pr_num} --repo {repo} --add-label preview"
confirm = true
[[actions]]
name = "Run tests"
command = "cd {worktree} && make test"
confirm = falseVariables: {repo}, {issue_num}, {pr_num}, {branch}, {worktree}, {window_name}.
Session state is stored per-project at ~/.local/share/cwo/sessions/<hash>/. This includes runtime config overrides, DAG state, backoff timers, review markers, and command history. Close CWO, reopen later — settings and history persist. Multiple CWO instances on different repos don't collide.
Feature usage is tracked locally in {repo_root}/.claude/cwo-usage.jsonl. Use :usage in the TUI to see a ranked summary of which features you use most.
Ephemeral launcher scripts stay in /tmp.
Issue/Task → worktree + branch → post_worktree_create hooks
→ Claude in tmux window (shell starts in worktree dir)
→ implements → commits → pushes → opens PR
→ reviewer (if auto_review) → APPROVED / CHANGES_REQUESTED
→ CLEAN → rebase merge → delete branch → cleanup
→ BEHIND → rebase + push → merge
→ DIRTY → AI conflict resolver
→ crash → auto-relaunch with git context
| State | Meaning |
|---|---|
🟢 working |
Claude is actively running/thinking |
🟡 waiting |
Claude at prompt or plan-mode approval screen |
🔴 shell exited |
Claude exited, bare shell remains |
✅ complete |
PR created |
💀 stale |
No output change for stale_timeout_secs (active workers only) |
❌ failed |
Max relaunches exceeded |
⚠️ conflict |
Rebase conflict needs resolution |
queued |
Waiting to launch (at max_concurrent cap) |
🔗 waiting on deps |
DAG dependencies not yet met |
🔍 checking |
AI probe running in split pane |
When run without a terminal (e.g. from another Claude instance or CI), CWO automatically re-executes itself inside a tmux session named cwo. Attach with tmux attach -t cwo.
