Self-blocking dependency on tb-1me prevented Pluck from claiming any beads.
Removed the circular dependency and documented the root cause and fix.
Bead-Id: tb-1zrf
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause: bead-worker workflow tried to call Bash() directly from
workflow script, but workflows run in pure JS context without tool access.
Fixed by wrapping bash commands in agent() calls with structured output.
Bead-Id: tb-1x0l
Investigation revealed that the 'starvation' was a false alarm.
All 9 open beads have special labels (deferred, split-child, umbrella)
that are intentionally filtered by br claim. The system is working
as designed - 0 beads are actually claimable.
Bead-Id: tb-2pvm
- Verified test-tmux-detector.sh is executable and functional
- Confirmed test-wrapper.sh captures output, timing, and exit status
- Validated JSON summary parsing for automated execution
- Documented known test isolation issue (tmux socket path)
Mark the tmux detector viability question as RESOLVED (2026-07-02):
- Moved from 'Open' to 'Resolved (recorded so they don't get re-litigated)'
- Added resolution summary with date stamp
- Linked to full findings in docs/notes/decisions.md
- Documented implementation status and enabling instructions
The tmux detector (daemon/tmux-detector.ts) is confirmed viable as a
harness-agnostic fallback for future coding harnesses without hooks.
Co-Authored-By: Claude <noreply@anthropic.com>
Per plan Phase 7 exit criteria, the tmux detector must ship with an
acceptance scenario test validating:
- A scripted non-Claude pane goes quiet -> appears in queue with reason 'stopped'
- Typing into it -> dequeues
The test script:
- Creates a throwaway tmux server with isolated socket (never touches user panes)
- Sets up a test pane with @tb- prefix opt-in
- Waits for stuck detection (quiet threshold + poll interval)
- Verifies the session appears in GET /queue with correct fields:
- session_id format (tmux-*)
- reason: "stopped"
- message field present
- Sends input to trigger unstuck
- Verifies the session is dequeued (queue empty)
- Cleans up via trap EXIT even on failure
This satisfies the Phase 7 requirement that the tmux detector ships
with a passing acceptance scenario test.
Co-Authored-By: Claude <noreply@anthropic.com>
Implements the tmux detector poller module based on the design in
docs/notes/tmux-detector-design.md.
Features:
- Auto-discovers opted-in panes via @tb- prefix in window title
- Polls every 2s (configurable via TRAILBOSS_POLL_INTERVAL_MS)
- Detects stuck sessions: quiet for 30s with prompt-like last line
- Detects unstuck: any output change after being stuck
- Emits normalized events to /event/normalized endpoint
- Synthetic session IDs: tmux-%446-{timestamp}
- Graceful shutdown with SIGINT/SIGTERM handling
Configuration:
- TRAILBOSS_POLL_INTERVAL_MS (default: 2000)
- TRAILBOSS_QUIET_THRESHOLD_MS (default: 30000)
- TRAILBOSS_OPT_IN_PREFIX (default: @tb-)
- TRAILBOSS_DAEMON_URL (default: http://127.0.0.1:4000/event/normalized)
Usage: bun run daemon/tmux-detector.ts
Co-Authored-By: Claude <noreply@anthropic.com>
Document the POST /event/normalized endpoint contract with:
- Complete endpoint specification (URL, method, request/response)
- All 4 event types with field descriptions and examples
- Derivation guide for sessionId, paneId, cwd, transcriptPath from harness context
- Implementation example for adapter authors
- Error handling and versioning guidance
This enables future adapter authors to integrate any coding harness
without reading the daemon source code.
- Remove CORS headers and OPTIONS preflight from daemon
- CORS was enabling cross-origin browser POSTs to loopback endpoint
- No legitimate consumer is a browser (emitter uses curl, TUI uses Go http)
Add invariant test script test-invariants.sh:
- Daemon listens on 127.0.0.1 only (loopback-only binding)
- No synthesized input: verify no tmux send-keys in daemon sources
- OPTIONS preflight is no longer honored (returns 404)
Validates trust boundary specified in docs/plan/plan.md section
'Failure modes & invariants'.
Co-Authored-By: Claude <noreply@anthropic.com>
- plan.md: mark Phase 8 as complete, remove (planned) marker
- plan.md: update PermissionRequest status from unverified to confirmed
(probe 2026-05-25 confirmed firing + payload with tool_name/tool_input)
- plan.md: mark Open question 2 (PermissionRequest specifics) as resolved
- plan.md: correct Phase 8 keyboard map (l/Tab focuses detail pane, not queue head)
- plan.md: mark Open question 5 (popup vs persistent window) as resolved
(both retained: popup for quick triage, TUI for sustained work)
- README: add SessionStart and SessionEnd to hook wiring snippet
(daemon also consumes these for registry and retirement)
- README: add trailboss-bootstrap and trailboss-watch to repository layout
(trailboss-watch noted as deprecated/superseded by TUI)
- CLAUDE.md: update Go version from 1.22+ to 1.24+ to match tui/go.mod
Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: tb-1jl
- plan.md: mark Phase 8 as complete, remove (planned) marker
- plan.md: update PermissionRequest status from unverified to confirmed
(probe 2026-05-25 confirmed firing + payload with tool_name/tool_input)
- plan.md: mark Open question 2 (PermissionRequest specifics) as resolved
- plan.md: correct Phase 8 keyboard map (l/Tab focuses detail pane, not queue head)
- plan.md: mark Open question 5 (popup vs persistent window) as resolved
(both retained: popup for quick triage, TUI for sustained work)
- README: add SessionStart and SessionEnd to hook wiring snippet
(daemon also consumes these for registry and retirement)
- README: add trailboss-bootstrap and trailboss-watch to repository layout
(trailboss-watch noted as deprecated/superseded by TUI)
- CLAUDE.md: update Go version from 1.22+ to 1.24+ to match tui/go.mod
Co-Authored-By: Claude <noreply@anthropic.com>
- Add reconcileStuckDirection() to scan transcripts and recover sessions that became stuck while daemon was down
- Add paneExists() to verify tmux pane still exists before enqueuing
- Add detectStuckFromTranscriptTail() to detect stuck state from transcript tail
- Add getSessionsNotInQueue() to DB layer for finding non-queued sessions
- Call reconcileStuckDirection() on daemon startup to recover dropped events
- Remove duplicate AS-4 test code
Acceptance criteria:
- Extended test-walking-skeleton.sh AS-4 to full plan scenario (daemon restart with transcript tail scan)
- All AS-1..AS-7 tests pass
- Session appears in /queue within one sweep after daemon restart
Co-Authored-By: Claude <noreply@anthropic.com>
- Change 'pre-built binary' language to 'build from tui/ with Go'
- Add explicit build step in installation instructions
- Note that trailboss-start auto-builds if binary is missing
- Update predispatch SHA
Bead-Id: tb-25j
Co-Authored-By: Claude <noreply@anthropic.com>
- Parse ISO-8601 timestamps via Date.parse(), handle both strings and numbers
- Recognize real entry shape: type='user'|'assistant' with nested message.role
- Ignore non-message lines (attachments, queue-operations, etc.)
- Remove duplicate TranscriptEntry interface (import was not exported)
- Add AS-8 test validating real-format JSONL behavior
- Update fixtures to use real Claude Code format
Fixes tb-67q
- Define Theme struct with all Dracula palette colors
- Auto-detect terminal color support (truecolor, 256-color, no-color)
- Implement graceful fallback for dumb terminals
- Fix model theme field type to use pointer
- Colors: stopped badge (#F1FA8C), permission badge (#FF5555), selected row (#BD93F9),
panel border (#6272A4), header bar (#282A36), status bar (#44475A),
metadata text (#AAAAAA), accent cyan (#8BE9FD), accent green (#50FA7B)
Closes tb-6cj
Rewrite README to reflect actual implementation (phases 1–9 complete,
all 7 acceptance scenarios passing). Previous README said "No
implementation yet" — replaced with accurate architecture overview,
setup instructions, TUI key reference, component table, and design
principles.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ran test-walking-skeleton.sh successfully
- All AS-1 through AS-7 pass end-to-end
- No code changes required - implementation was already complete
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "no implementation code exists" line was stale and would have misdirected
a fresh marathon session to re-implement from phase 1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
daemon/ (index.ts, types.ts, claude-adapter.ts, db.ts, reconcile.ts, schema.sql),
package.json, and test scripts were implemented but never staged. Phase 3 exit
criteria verified per PROGRESS.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implemented trailboss CLI with jump-next and skip commands that
navigate to panes returned by the daemon's /next endpoint.
- bin/trailboss: main CLI with jump-next, skip, popup stubs
- jump-next: queries /next, navigates via switch-client/select-window/select-pane
- skip: POSTs /skip, then jumps to new head
- test-navigation.sh: synthetic event test verifying exit criterion
Exit criterion passed: jump-next lands operator on pane returned by /next.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 1: Probed PermissionRequest hook, confirmed firing + payload shape.
Documented in docs/research/claude-code-mechanics.md.
Phase 2: Built trailboss-emit.sh that forwards hook payloads to collector
and injects $TMUX_PANE. Wired all hooks in .claude/settings.json.
Verified: stub collector logs POSTs with session_id, cwd, and pane_id.
Demonstrated bare curl drops $TMUX_PANE, proving wrapper required.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The launcher sourced env into its own process, but the loop runs in a separate
tmux shell that didn't inherit ANTHROPIC_BASE_URL/AUTH_TOKEN — so claude ran
unauthenticated ("Not logged in"). Source the env file inside the loop command
so the proxy/model config is present in the shell that launches claude.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The plan defined deliverables but no definition of done. Add a "Testing &
validation" section: a per-phase exit-criteria table, seven acceptance
scenarios (AS-1..AS-7, incl. reconcile self-correction, dropped-event
recovery, skip/cooldown, no-forced-focus-steal, pane reuse), a test harness
(synthetic event injection, throwaway-tmux isolation, transcript fixtures,
mock hook emitter, navigation assertion, invariant checks), and a quality
gate. Point the marathon instruction at these as the definition of done.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Model the setup on existing marathon instances (FORGE/AIVC/NEEDLE):
- .marathon/instruction.md — per-iteration autonomous prompt, plan-driven off
docs/plan/plan.md with the 7-phase order, settled invariants, and commit/push
loop protocol
- .marathon/launch-marathon.sh — self-contained `while true` loop piping the
instruction to `claude --print`, sourcing model/proxy config from an
untracked .marathon/env (keeps internal endpoints out of this public repo)
- .marathon/env.example — config template
- .gitignore — ignore .marathon/env, logs/, *-config/, and .beads/*.db
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a "Switching & keybindings" section: global prefix bindings that call the
daemon via run-shell — Next (jump to head-of-queue pane), Popup (display-popup
picker), Skip (tail+cooldown then advance) — plus a status-line segment.
Documents the prefix-not-bare-key constraint and why the jump is the keypress,
never automatic. Resolves open questions 3 and 4 down to polish.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- MEDIUM: reason enum stated as exactly {permission, stopped} (drop stray
"stopped/needs-next" third label)
- MEDIUM: specify oldest-READY-stuck-first — a cooldowned skipped item is not
eligible to be the head; advance to next ready item, else present empty
- MEDIUM: SubagentStop downgraded from "Confirmed" to "exists; not probed"
(probe only saw SessionStart/Stop)
- LOW: agent-inbox reuse reworded (Trail Boss actions are navigate-and-reply /
skip, not accept/edit/ignore); note permission_mode is display-only
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- HIGH: settings.json example wired PermissionRequest to a bare curl that drops
the env-only $TMUX_PANE; route all hooks through trailboss-emit.sh (which
injects $TMUX_PANE) and note SessionStart is not special
- MEDIUM: remove the stray trailboss-register.sh (contradicted "registry
self-heals on every emit"); single emitter script
- LOW: add struck-through SubagentStop row to plan detection table; clarify
disler's store is append-only (not "read-only")
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolve open questions from the design session:
- Stuck is stuck: no permission-vs-stopped priority; reason is display-only;
queue is a flat FIFO dead-letter queue (Stop AND PermissionRequest still
both required — permission blocks emit no Stop)
- Drop Notification entirely
- Auto-advance depletion loop: next stuck session loads on resolve/skip;
saturation is a non-issue by construction
- New primary open question: harness-coupled detection vs harness-agnostic
core, via a normalized stuck/unstuck adapter contract (switching is already
tmux-level/harness-agnostic)
- Reboot: operator re-invokes manually (no auto-resurrection in v1)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Emphasize that agents run autonomously and the human is engaged only by
exception — the failure-mode handler / dead-letter-queue processor for a fleet
of agents, not a gate on every step.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Single-pane attention router for interactive AI coding agents: stuck sessions
surface in one prioritized queue (most-stuck first) via Claude Code hooks, and
your reply is delivered back into the exact session.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>