Single-pane attention router for interactive AI coding agents: surfaces whichever session is blocked waiting on you, so you answer or skip from one place.
Find a file
jedarden e2dfbcf33e feat(tb-lg44): add automated test execution script
Add bin/run-tmux-detector-metrics.sh script that:
- Runs tmux detector acceptance test repeatedly
- Accepts iterations parameter (default 5)
- Captures pass/fail status, execution time, and failure analysis
- Outputs structured CSV results for later analysis
- Is idempotent with timestamped result files

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-02 16:58:54 -04:00
.beads feat(trail-boss): phase 6 complete - all 7 acceptance scenarios passing 2026-05-30 12:55:37 -04:00
.claude feat(trail-boss): phase 6 complete - all 7 acceptance scenarios passing 2026-05-30 12:55:37 -04:00
.marathon docs(marathon): update Current state — phases 1–5 complete, phase 6 next 2026-05-25 22:57:57 -04:00
bin feat(tb-lg44): add automated test execution script 2026-07-02 16:58:54 -04:00
daemon feat(tmux-detector): implement automatic poller with @tb- prefix opt-in 2026-07-02 09:47:31 -04:00
docs docs(tb-25t): mark Open question 1 as RESOLVED with tmux detector verdict 2026-07-02 11:33:27 -04:00
notes docs(tb-67rg): investigate starvation alert - document false positive 2026-07-02 15:12:43 -04:00
tui feat(tui): commit Phase 8/9 source files 2026-07-02 07:57:11 -04:00
.gitignore feat(tui): commit Phase 8/9 source files 2026-07-02 07:57:11 -04:00
.needle-predispatch-sha docs: update README to reflect TUI build process 2026-07-02 08:25:44 -04:00
CLAUDE.md docs: update plan.md and README to match shipped Phase 8/9 state 2026-07-02 08:59:53 -04:00
package.json feat(trail-boss): commit phase 3 daemon code (previously untracked) 2026-05-25 22:57:51 -04:00
PROGRESS.md feat(tui): commit Phase 8/9 source files 2026-07-02 07:57:11 -04:00
README.md docs: update plan.md and README to match shipped Phase 8/9 state 2026-07-02 08:59:53 -04:00
test-daemon-phase3.sh feat(trail-boss): commit phase 3 daemon code (previously untracked) 2026-05-25 22:57:51 -04:00
test-daemon.sh feat(trail-boss): commit phase 3 daemon code (previously untracked) 2026-05-25 22:57:51 -04:00
test-invariants.sh feat(security): tighten ingest trust boundary and add invariant tests 2026-07-02 09:03:55 -04:00
test-navigation.sh feat(trail-boss): phase 4 - Navigation command 2026-05-25 22:18:01 -04:00
test-presentation.sh feat(trail-boss): phase 5 - Presentation layer 2026-05-25 22:26:17 -04:00
test-tmux-detector.sh test(tb-3pt): complete tmux detector acceptance testing 2026-07-02 12:16:57 -04:00
test-walking-skeleton.sh feat(reconcile): implement stuck-direction reconcile for dropped Stop events 2026-07-02 08:45:26 -04:00
tmux.conf feat(tui): commit Phase 8/9 source files 2026-07-02 07:57:11 -04:00

Trail Boss

Single-pane attention router for interactive AI coding agents. When you run multiple Claude Code (or other AI coding CLI) sessions in parallel tmux panes, Trail Boss surfaces the ones waiting on you — a FIFO queue of stuck sessions — and jumps you directly to them with a keystroke.


The problem

Running many agent sessions in tmux means manually cycling windows to find the one that needs you. Each stalled session — hitting a permission gate, asking a question, or finishing its turn — sits blocked until you notice it. With five or ten parallel sessions, most of your attention goes to finding the stuck one, not answering it.

Trail Boss eliminates the cycling. Every session that stalls raises its hand automatically. You see one prioritized queue, respond in the live pane, and move on.

Human on the loop, not in it. The happy path never touches you. Only stalled work routes to you; you process the exception and it goes back on the wire.


How it works

Trail Boss integrates with Claude Code via hooks and tmux pane tracking:

  1. Hook emitter — Claude Code fires Stop and PermissionRequest hooks whenever a session blocks. The emitter script (trailboss-emit.sh) POSTs each event to the daemon with the current $TMUX_PANE ID.

  2. Daemon (Bun + SQLite, localhost:4000) — Maintains a session registry and FIFO queue. Sessions enter the queue on Stop/PermissionRequest and leave when UserPromptSubmit fires (you typed something in the pane) or when the reconcile loop detects the transcript advanced on its own.

  3. TUI (Go + Bubble Tea) — Split-panel view: queue list on the left, session detail on the right. Auto-refreshes every 3 seconds. Press Enter to jump to the head pane, s to skip it (30 s cooldown before it re-surfaces).

  4. Live preview — A tmux capture-pane preview of the selected session updates in a pane below the TUI as you navigate the queue.

┌─ Trail Boss ─────────────────── 3 stuck ──┐ ┌─ Detail ───────────────────────────────┐
│ ▶ alpha    permission   2m14s              │ │ Wants to run:                          │
│   bravo    stopped      0m48s              │ │ terraform apply -target=module.lb      │
│   delta    stopped      0m11s              │ │                                        │
│                                            │ │ CWD: ~/infra/modules                   │
│ [enter] jump  [s] skip  [r] refresh  [?]  │ │ stuck 2m14s ago                        │
└────────────────────────────────────────────┘ └────────────────────────────────────────┘

Architecture

Claude Code session (tmux pane)
    │  Stop / PermissionRequest hook
    ▼
.claude/trailboss-emit.sh  ─── POST /event ──►  daemon (Bun + SQLite, :4000)
                                                    │  reconcile loop (5 s)
                                                    │  GET /queue  /next  /skip
                                                    ▼
                                                TUI (Go + Bubble Tea)
                                                bin/trailboss-tui
                                                    │  tmux switch-client / select-pane
                                                    ▼
                                                Target pane (live Claude Code session)

Components

Component Language Purpose
daemon/ TypeScript (Bun) HTTP event ingestion, SQLite state, queue API
tui/ Go (Bubble Tea) Split-panel TUI dashboard
bin/trailboss Shell CLI: jump-next, skip, popup, return
bin/trailboss-tui Go binary TUI binary (build from tui/ with Go)
bin/trailboss-start Shell Launches daemon + TUI in a trail-boss tmux session
bin/trailboss-preview Shell Live pane capture loop for the split-view preview
bin/trailboss-status Shell tmux status-bar segment showing stuck count
.claude/trailboss-emit.sh Shell Hook emitter wired into Claude Code settings

Requirements

  • Bun — daemon runtime
  • tmux
  • Claude Code with hooks enabled
  • Go 1.24+ — for building the TUI

Setup

1. Install daemon dependencies

cd /path/to/trail-boss
bun install

2. Build the TUI

cd /path/to/trail-boss/tui
go build -o ../bin/trailboss-tui .

The bin/trailboss-start script will automatically build the TUI if the binary is missing.

3. Wire Claude Code hooks

Add to your project's .claude/settings.json:

{
  "hooks": {
    "Stop": [{
      "type": "command",
      "command": "/path/to/trail-boss/.claude/trailboss-emit.sh"
    }],
    "PermissionRequest": [{
      "type": "command",
      "command": "/path/to/trail-boss/.claude/trailboss-emit.sh"
    }],
    "UserPromptSubmit": [{
      "type": "command",
      "command": "/path/to/trail-boss/.claude/trailboss-emit.sh"
    }],
    "SessionStart": [{
      "type": "command",
      "command": "/path/to/trail-boss/.claude/trailboss-emit.sh"
    }],
    "SessionEnd": [{
      "type": "command",
      "command": "/path/to/trail-boss/.claude/trailboss-emit.sh"
    }]
  }
}

3. Start Trail Boss

bin/trailboss-start

This creates (or reuses) a trail-boss tmux session with two windows: daemon and dashboard. The dashboard shows the TUI on top (60%) and a live pane preview below (40%).

4. Navigate

From inside any tmux session:

Keybinding Action
prefix+Tab Jump to next stuck session
prefix+S Skip current head, jump to next
prefix+g Open queue picker popup
prefix+B Return to Trail Boss dashboard

Or source the provided tmux.conf to get these bindings:

tmux source-file /path/to/trail-boss/tmux.conf

5. Add to tmux status bar (optional)

set -g status-right "#(bin/trailboss-status) | %H:%M"

The segment shows ⚠ N when N sessions are stuck, blank otherwise.


TUI keys

Key Action
j / k Move cursor down / up
gg / G Jump to top / bottom
Ctrl+d / Ctrl+u Half-page down / up
Enter Jump to selected pane
s Skip selected session (30 s cooldown)
l / Tab Focus detail pane
J / K Scroll detail pane
19 Jump directly to queue position N
r Force refresh
? Toggle help overlay
q Quit

Repository layout

trail-boss/
├── daemon/
│   ├── index.ts          # HTTP server + event ingest endpoint
│   ├── claude-adapter.ts # Hook event normalization
│   ├── db.ts             # SQLite state layer
│   ├── reconcile.ts      # Transcript-advance reconcile loop
│   ├── schema.sql        # Database schema
│   └── types.ts          # Shared types
├── tui/
│   ├── main.go           # Entry point (AltScreen + mouse)
│   ├── model.go          # Bubble Tea model + split layout
│   ├── client.go         # Daemon HTTP client + tmux navigation
│   └── theme.go          # Dracula palette + dumb-terminal fallback
├── bin/
│   ├── trailboss         # CLI: jump-next, skip, popup, return
│   ├── trailboss-tui     # TUI binary (build from tui/ with Go)
│   ├── trailboss-start   # Session launcher
│   ├── trailboss-bootstrap # Initial setup script
│   ├── trailboss-popup   # Queue picker popup (box-drawing UI)
│   ├── trailboss-preview # Live pane capture loop
│   ├── trailboss-status  # tmux status segment
│   └── trailboss-watch   # (deprecated, superseded by TUI)
├── docs/
│   └── plan/plan.md      # Complete design spec
├── .claude/
│   └── trailboss-emit.sh # Hook emitter
└── tmux.conf             # Keybinding configuration

Status

Phases 19 complete. All 7 acceptance scenarios pass end-to-end.

What works:

  • Hook detection: Stop and PermissionRequest enqueue; UserPromptSubmit dequeues
  • FIFO ordering with skip cooldown (30 s before a skipped session re-surfaces)
  • Reconcile loop: sessions dequeue automatically when transcripts advance (even if UserPromptSubmit was missed because the daemon was temporarily down)
  • Self-healing registry: a session reappearing in a different pane re-registers
  • No forced focus-steal: resolving a session does not auto-switch you to another
  • TUI resolves pane IDs to human-readable tmux session names (alpha, bravo, etc.)

Upcoming: refinements from daily use.


Design principles

Stuck is stuck. Whether a session hit a permission gate or just finished its turn — both mean "blocked until you act." The queue treats them identically; reason is display-only metadata, never a routing input.

Navigator, not relay. Trail Boss routes your attention to the live session. You interact with the real CLI directly. It never injects replies or relays input.

Not a fleet spawner. Trail Boss does not launch, kill, or cost-optimize agents. It assumes sessions already exist and surfaces the stuck ones.


License

MIT