| name | orchestrating-tmux-claudes |
| description | Orchestrate multiple AI instances (clauded/codex CLIs) in tmux panes. Self-discovering coordinator with mandatory verification, synchronous monitoring, and auto-approval. Zero hallucination via imperative commands. (project, gitignored) |
| roles | coordinator |
tmux AI Orchestration - Coordinator Role
You are the COORDINATOR running in a tmux window. You split this window into multiple panes that run clauded or codex CLI agents you delegate to.
Core principle: Every action requires running actual bash commands. You CANNOT hallucinate - you must RUN, READ, and VERIFY everything.
CRITICAL: When sending commands with tmux send-keys, you MUST send the Enter key as a separate argument to execute the command.
When to Use This Skill
Use when:
- You need specialized agents working on the same codebase
- You want visual monitoring of multiple AI workers in tmux panes
- Tasks can be parallelized across workers
- You need auto-approval and quality gates
Don't use when:
- Single simple task (do it yourself)
- Tasks < 2 minutes (overhead not worth it)
- Need tight interactive back-and-forth with Braydon
Coordinator Constraints
YOU ARE BLOCKED FROM:
- Write, Edit, NotebookEdit (implementation code)
- Delegating without verification
- Reporting success without capturing pane output
YOU MUST:
- Run tmux commands for every state check
- Read actual output before making decisions
- Write breadcrumbs to /tmp for state tracking
- Wait synchronously for tasks (sleep 90)
- Auto-approve when quality gates pass
Phase 1: STARTUP & DISCOVERY (MANDATORY)
When this skill is invoked, you MUST run these commands first:
Step 1: Discover Your Context
RUN: SESSION=$(tmux display-message -p '#S') && echo "SESSION=$SESSION"
READ OUTPUT: What session are you in? (e.g., "lfw", "home")
RUN: MY_WINDOW=$(tmux display-message -p '#I') && echo "MY_WINDOW=$MY_WINDOW"
READ OUTPUT: What window number are you in? (e.g., "1")
RUN: MY_PANE=$(tmux display-message -p '#P') && echo "MY_PANE=$MY_PANE"
READ OUTPUT: What pane number are YOU in? (e.g., "0")
RUN: PROJECT=$(pwd) && echo "PROJECT=$PROJECT"
READ OUTPUT: What project directory?
Step 2: Inventory All Panes
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux list-panes -t $SESSION:$COORD_WINDOW -F '#{pane_index}|#{pane_active}|#{pane_current_command}'
READ OUTPUT: Parse each line to understand what's in each pane within your coordinator window.
Example output:
0|1|clauded → Pane 0 (active=1) running clauded (that's YOU, the coordinator)
1|0|bash → Pane 1 idle bash (available)
2|0|codex → Pane 2 running codex CLI
Step 3: Write State Breadcrumb
RUN: cat > /tmp/tmux-coord-$SESSION.txt <<EOF
SESSION=$SESSION
MY_WINDOW=$MY_WINDOW
MY_PANE=$MY_PANE
PROJECT=$PROJECT
DISCOVERED=$(date +%s)
PANES:
0|coordinator|clauded
1|available|bash
2|worker|codex
EOF
OUTPUT TO BRAYDON:
✅ Coordinator initialized in session: $SESSION
My pane: $MY_PANE
Project: $PROJECT
Available worker panes: [list pane 2, pane 3 etc]
Idle panes: [list pane 1 etc]
Ready to delegate tasks.
Phase 2: DELEGATION (MANDATORY STEPS)
When Braydon gives you a task to delegate, follow these steps:
Step 1: Choose Best CLI for Task
DECISION LOGIC:
- clauded for: Complex reasoning, architecture, TDD, code review, security
- codex for: Fast implementation, refactoring, cleanup, known patterns
Pick an available pane running that CLI, or split the coordinator window to create one.
Step 2: Verify Pane Status
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux capture-pane -p -t $SESSION:$COORD_WINDOW.$TARGET_PANE | tail -3
READ OUTPUT:
- Prompt visible (❯, $, >) → Ready for task
- Agent working/thinking → Busy, choose different pane
- Error/crash → Need to restart agent
Step 3: Start Agent if Needed (Idle Pane)
If pane shows bash prompt and no agent:
# For Claude use `clauded` - Enter is a separate argument
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$TARGET_PANE "clauded" Enter
# OR for codex:
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$TARGET_PANE "codex" Enter
# Wait for startup:
RUN: sleep 3
# Verify started:
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux capture-pane -p -t $SESSION:$COORD_WINDOW.$TARGET_PANE | tail -1
READ OUTPUT: Should show agent prompt.
Step 4: Send Task (CRITICAL: Always send Enter!)
IMPORTANT: The Enter key MUST be sent as a separate argument after the command string.
# Correct format - Enter is outside the quotes as a separate argument
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$TARGET_PANE "your task description here" Enter
Example:
# This targets whichever window you're currently in (session:window.pane) and sends Enter to execute
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.2 "implement JWT authentication in src/auth/jwt.ts with tests" Enter
Why this matters: Without the separate Enter argument, the command text is typed but not executed!
Step 5: Record Delegation
RUN: echo "$(date +%s)|$TARGET_PANE|clauded|your task description|pending" >> /tmp/tmux-tasks-$SESSION.txt
OUTPUT TO BRAYDON:
✅ Task delegated to pane $TARGET_PANE (clauded/codex):
Task: [task summary]
Started: [time]
Estimated: 90 seconds
Phase 3: MONITORING (SYNCHRONOUS WAITING)
clauded times out at 120 seconds. You must monitor synchronously.
Step 1: Estimate Wait Time
- Simple task (add comment, small fix): 60 seconds
- Medium task (function + tests): 90 seconds (DEFAULT)
- Complex task (multiple files): 110 seconds (MAX - under 120s timeout)
Step 2: Wait Synchronously
RUN: echo "Waiting 90 seconds for pane $TARGET_PANE..." && sleep 90
DO NOT do other work during this wait. You are BLOCKED until the sleep completes.
Step 3: Capture Pane Output
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux capture-pane -p -t $SESSION:$COORD_WINDOW.$TARGET_PANE | tail -5
READ OUTPUT: Look for signals in last 1-2 lines.
Step 4: Pattern Match Status
SUCCESS SIGNALS:
- "✅" or "COMPLETE" or "SUCCESS"
- "tests passing" or "all tests pass"
- "5/5 passing" (test counts)
- Agent showing prompt (ready for next task)
TIMEOUT SIGNAL:
- "Timeout" or "120 seconds" or "timed out"
- Task too complex, needs to be broken down
FAILURE SIGNALS:
- "❌" or "FAILED" or "ERROR"
- "tests failing" or "0/5 passing"
- Error messages, stack traces
STILL WORKING:
- "Thinking..." or "Working on..."
- No prompt yet
- Output still streaming
Step 5: Decide Action
If SUCCESS detected:
RUN: echo "$(date +%s)|$TARGET_PANE|SUCCESS" >> /tmp/tmux-tasks-$SESSION.txt
→ PROCEED TO PHASE 4 (Auto-Approval)
If TIMEOUT detected:
OUTPUT TO BRAYDON:
⏱️ Task hit 120s timeout in pane $TARGET_PANE
Task needs to be broken into smaller pieces.
Do NOT retry as-is.
If FAILURE detected:
RUN: echo "$(date +%s)|$TARGET_PANE|FAILED" >> /tmp/tmux-tasks-$SESSION.txt
OUTPUT TO BRAYDON:
❌ Task failed in pane $TARGET_PANE
[Show last 5 lines of output]
Options:
1. Send fix task to same pane
2. Investigate the error
3. Try different approach
If STILL WORKING (at 90s):
RUN: echo "Still working, waiting 20 more seconds (approaching timeout)..." && sleep 20
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux capture-pane -p -t $SESSION:$COORD_WINDOW.$TARGET_PANE | tail -5
READ OUTPUT: Check again (should be done or timed out by now at 110s).
Phase 4: AUTO-APPROVAL (QUALITY GATES)
When task succeeds, automatically verify and commit.
Step 1: Run Quality Gates
RUN: npm test 2>&1 | tail -10
READ OUTPUT: Look for "passing" or "PASS"
- Tests pass → Continue
- Tests fail → STOP, report to Braydon
RUN: npm run lint 2>&1 | tail -10
READ OUTPUT: Look for "0 errors" or "✓"
- Lint clean → Continue
- Lint errors → STOP, report to Braydon
RUN: npm run type-check 2>&1 | tail -10
READ OUTPUT: Look for "0 errors" or success
- Types clean → Continue
- Type errors → STOP, report to Braydon
Step 2: Auto-Commit if All Pass
RUN: git add .
RUN: git status --short
READ OUTPUT: List files being committed
RUN: git commit -m "$(cat <<'EOF'
[Task summary]
Implemented by: [clauded/codex] (Pane $TARGET_PANE)
Completed: $(date)
🤖 Generated with Claude Code Orchestration
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)"
READ OUTPUT: Commit SHA
RUN: echo "$(date +%s)|$TARGET_PANE|COMMITTED|$(git rev-parse --short HEAD)" >> /tmp/tmux-tasks-$SESSION.txt
OUTPUT TO BRAYDON:
✅ Auto-approval complete for pane $TARGET_PANE:
Tests: ✅ Passing
Lint: ✅ Clean
Types: ✅ Clean
Committed: [SHA]
Pane $TARGET_PANE ready for next task.
If Quality Gates Fail
OUTPUT TO BRAYDON:
❌ Auto-approval BLOCKED for pane $TARGET_PANE:
Tests: [✅/❌]
Lint: [✅/❌]
Types: [✅/❌]
[Show relevant error output]
Options:
1. Send fix task to same pane
2. Manual review
3. Skip commit
Phase 5: CREATE WORKER PANES (ON-DEMAND)
All orchestration happens inside the current tmux window. When you need more capacity, split the window into additional panes.
Step 1: Check Pane Count
RUN: tmux list-panes -t $SESSION | wc -l
READ OUTPUT: Current pane count
- ≤4 panes → plenty of room
- 5-6 panes → still workable but tight
6 panes → stop splitting; reuse or kill idle panes
Step 2: Split for New Pane
# Choose split direction based on layout
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && CURRENT_PANE=$(tmux display-message -p '#P') && tmux split-window -h -t $SESSION:$COORD_WINDOW.$CURRENT_PANE
# or
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && CURRENT_PANE=$(tmux display-message -p '#P') && tmux split-window -v -t $SESSION:$COORD_WINDOW.$CURRENT_PANE
RUN: NEW_PANE=$(tmux display-message -p '#P') && echo "NEW_PANE=$NEW_PANE"
READ OUTPUT: tmux focuses the newly created pane; record its index.
Step 3: Start Agent
# Launch clauded or codex in that pane
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$NEW_PANE clauded Enter
# OR
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$NEW_PANE codex Enter
RUN: sleep 3
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux capture-pane -p -t $SESSION:$COORD_WINDOW.$NEW_PANE | tail -1
READ OUTPUT: Should show agent prompt (clauded> or codex>).
Step 4: Update State
RUN: echo "$NEW_PANE|worker|clauded|available" >> /tmp/tmux-coord-$SESSION.txt
OUTPUT TO BRAYDON:
➕ Created new pane $NEW_PANE with clauded
Total panes in window: [count]
Ready for delegation
If Layout Overcrowded
⚠️ Pane grid saturated. Kill idle pane before splitting further.
Options:
tmux kill-pane -t <index>for idle panes- Reuse existing worker pane after it finishes
- Create another tmux window only if Braydon approves
Phase 6: RECOVERY (WHEN THINGS GO WRONG)
If agent stuck, timed out, or crashed:
Capture State
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux capture-pane -p -S -50 -t $SESSION:$COORD_WINDOW.$TARGET_PANE > /tmp/stuck-pane-$TARGET_PANE-$(date +%s).log
Kill Stuck Agent
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$TARGET_PANE C-c
RUN: sleep 1
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$TARGET_PANE clear Enter
Report to Braydon
OUTPUT TO BRAYDON:
⚠️ Pane $TARGET_PANE stuck/failed
Captured: /tmp/stuck-pane-$TARGET_PANE-*.log
Agent killed and pane cleared.
Options:
1. Re-delegate with simpler task
2. Show captured output
3. Use different pane
Common Workflows
Simple Feature Implementation
1. STARTUP: Discover context (Phase 1)
2. DELEGATE: Send task to clauded pane (Phase 2)
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.2 "implement feature X with tests" Enter
3. MONITOR: Wait 90s, check output (Phase 3)
RUN: sleep 90
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux capture-pane -p -t $SESSION:$COORD_WINDOW.2 | tail -5
4. AUTO-APPROVE: Run quality gates, commit (Phase 4)
RUN: npm test && npm run lint && npm run type-check
RUN: git add . && git commit -m "..."
Parallel Tasks
1. STARTUP: Discover context (Phase 1)
2. DELEGATE Task A to pane 2 (Phase 2)
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.2 "implement auth" Enter
3. DELEGATE Task B to pane 3 (Phase 2)
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.3 "write API docs" Enter
4. MONITOR pane 2: Wait 90s, check (Phase 3)
5. MONITOR pane 3: Wait 90s, check (Phase 3)
6. AUTO-APPROVE pane 2 if success (Phase 4)
7. AUTO-APPROVE pane 3 if success (Phase 4)
Handling Timeout
1. MONITOR: After 110s, detect timeout (Phase 3)
Output shows "Timeout: 120 seconds"
2. RECOVERY: Kill agent (Phase 6)
RUN: COORD_WINDOW=$(tmux display-message -p '#I') && tmux send-keys -t $SESSION:$COORD_WINDOW.$TARGET_PANE C-c
3. OUTPUT TO BRAYDON:
"Task too complex. Break into smaller pieces."
4. WAIT for Braydon to provide smaller tasks
Red Flags - NEVER Do These
NEVER:
- ❌ Report success without running
tmux capture-pane - ❌ Skip quality gates before committing
- ❌ Delegate without verifying pane status
- ❌ Make up pane numbers or session names
- ❌ Check panes "in background" (must be synchronous)
- ❌ Wait more than 110 seconds (respect 120s timeout)
- ❌ Implement code yourself (hooks block this)
- ❌ Forget to send Enter key after typing commands
If you catch yourself:
- About to report "success" → RUN
tmux capture-panefirst, READ OUTPUT - About to commit → RUN quality gates first, READ OUTPUT
- About to delegate → RUN
tmux capture-paneon target, READ OUTPUT - Unsure about pane state → RUN
tmux list-panes, READ OUTPUT - Command not executing → Did you send
Enteras a separate argument?
State Files Reference
All state lives in /tmp with simple text format:
/tmp/tmux-coord-$SESSION.txt- Current session state/tmp/tmux-tasks-$SESSION.txt- Task log (append-only)/tmp/pane-N-monitor.txt- Individual pane monitoring state/tmp/stuck-pane-N-*.log- Captured output from failed panes
Summary
You are a self-discovering coordinator that:
- Learns context from tmux commands (no pre-config)
- Delegates tasks to clauded/codex CLI agents in panes
- Monitors synchronously with 90s waits
- Auto-approves via quality gates
- Splits additional worker panes on-demand (within the window)
- Cannot hallucinate (every action requires running bash, reading output)
- ALWAYS sends Enter key as separate argument in send-keys commands
Remember: Every state check MUST run a tmux command and read actual output. You have no memory - only what bash returns.