Skip to content

feat(tui): opt-in cmux tab auto-rename reflecting loop state - #102

Open
jitokim wants to merge 1 commit into
mainfrom
feat/cmux-tab-rename
Open

feat(tui): opt-in cmux tab auto-rename reflecting loop state#102
jitokim wants to merge 1 commit into
mainfrom
feat/cmux-tab-rename

Conversation

@jitokim

@jitokim jitokim commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

The captain runs many cmux tabs and renames each by hand to the task name (his workflow, step 4). fleetops already knows each loop's state, goal, and — since v0.9.0 — what subagent it's delegating to. So it can write that to the cmux tab strip, killing the manual step. This is the first concrete step of the pivot: "fleetops goes to where the captain already looks (the tab strip)" rather than "make the captain open fleetops." (Full rationale: .notes/pivot.md.)

First slice — opt-in, cmux-only, fail-closed

  • --rename-tabs flag, default OFF. Observation stays pure unless opted in.
  • New optional control.TabTitler interface (mirrors TerminalOpener/TTYLocator), implemented by cmuxController only: cmux rename-tab --surface <ref> -- <title> (same-workspace; title positional after --). Exec goes through an injectable cmuxTabRunner seam defaulting to runWithTimeout (5s bound) — unit-tested without a live cmux, and a wedged cmux can never hang the 3s tick.
  • Title composer (pure): glyph + state token (StateString, includes stall slug) + short DisplayLabel (~18 cols). Delegation wins: ▸deleg code-reviewer. Examples: ◆GATE auth-mw · ⏸STALL rate-limit fx · ✗DRIFT auth-mw.
  • Presentation-sync driver on the scan tick: debounced (per-session last-title ledger, advanced only on a confirmed write — ambiguous/failed writes retry), and only for unambiguously-mapped cmux loops (reuses the actuation ambiguity refusal — ambiguous ⇒ skip, never rename a guessed tab).
  • Honesty: delegation is matched only against claude.formatDelegating's authoritative boundaries, so a raw tail literally starting with "delegating…" can't fabricate a delegation on the tab.

Design decisions

  • Refactored ResolveActuationTarget (extracted tierOneAAcross/tierOneBAcross) so tab-title resolution reuses the exact tier-1a/1b locate + ambiguity rule instead of reimplementing it. Behavior-preserving — all 14 pre-existing ResolveActuationTarget tests unchanged and green (independently verified).
  • Not routed through internal/control/actuate: a tab rename writes terminal chrome, not a keystroke into the session — it has no Delivered/Tier2/DeliveryUnknown outcome space, so folding it into that Verdict/Dispatch seam would violate its switch-totality design. It borrows that seam's discipline (ambiguity refusal, bounded exec), not its types.

테스트 결과

go test ./... -race: 20/20 packages ✅

New tests: cmux argv/error propagation + default-seam-is-bounded, resolver ambiguity/tty/non-cmux/no-match, composer table (per state + truncation + delegation precedence + prose-negative), driver gate-off/debounce/mixed-batch. go vet / gofmt clean.

Review trail

Design (architect, pivot §5.1) → implement → developer self-run deep review (fixed honesty W1: prose can't fake delegation) → independent quality gate: PASSED, actuation refactor verified behavior-preserving against untouched test suite, Critical 0.


⚠️ Merge gate — live cmux verification required

This box has no cmux binary, so every test asserts what fleetops builds, not what cmux accepts. Before merging, confirm on a machine with cmux:

  1. cmux rename-tab --help — the subcommand exists with --surface <ref> + positional title after --.
  2. Omitting --window scopes to the caller's workspace.
  3. A bad surface ref exits non-zero (the skip-on-error path assumes it).

Then run fleetops --rename-tabs and watch a tab update. Until that's confirmed, do not merge (terminal write on sessions fleetops didn't spawn).

Out of v1 (follow-ups)

Cross-workspace rename (needs workspace: ref capture), tmux/iTerm2/orca titlers (same interface), restore-on-exit (cmux has no clear-to-default today).

🤖 Generated with Claude Code

The captain runs many cmux tabs and renames each by hand to the task. fleetops
already knows each loop's state, goal, and (since v0.9.0) what it's delegating to
a subagent — so it can write that to the cmux tab strip, killing the manual step.
This is "fleetops goes to where the captain already looks (the tab strip)" rather
than "make the captain open fleetops" (see .notes/pivot.md).

First slice — opt-in, cmux-only, fail-closed:

- `--rename-tabs` flag, default OFF. Observation stays pure unless opted in.
- New optional `control.TabTitler` interface (mirrors TerminalOpener/TTYLocator),
  implemented by cmuxController only: `cmux rename-tab --surface <ref> -- <title>`
  (same-workspace; title positional after `--`). The exec goes through an
  injectable `cmuxTabRunner` seam defaulting to runWithTimeout (5s bound), so it
  is unit-tested without a live cmux and a wedged cmux can never hang a tick.
- Title composer (pure): glyph + state token (StateString, includes stall slug) +
  short DisplayLabel truncated to ~18 cols; delegation wins ("▸deleg code-reviewer").
- Presentation-sync driver on the scan tick: debounced (per-session last-title
  ledger, advanced only on a CONFIRMED write — ambiguous/failed writes retry next
  tick), and only for unambiguously-mapped cmux loops (reuses the actuation
  ambiguity refusal — ambiguous ⇒ skip, never rename a guessed tab).
- Honesty: delegation is detected only against claude.formatDelegating's
  authoritative boundaries, so a raw tail literally starting with "delegating…"
  can't fabricate a delegation on the tab.

ResolveActuationTarget was refactored (extracted tierOneAAcross/tierOneBAcross) so
tab-title resolution reuses the exact tier-1a/1b locate + ambiguity rule instead of
reimplementing it — behavior-preserving (all pre-existing ResolveActuationTarget
tests unchanged and green). Not routed through internal/control/actuate: a tab
rename writes terminal chrome, not a keystroke into the session.

Tests: go test ./... -race green (20 pkgs); new tests cover argv/error, resolver
ambiguity/tty/non-cmux, composer table, driver gate/debounce/mixed-batch.

NOT YET VERIFIED against a live cmux binary (none on this box): that `rename-tab`
exists with `--surface <ref>` + positional title, that omitting `--window` scopes
to the caller's workspace, and that a bad surface ref exits non-zero. This is the
merge gate — confirm with `cmux rename-tab --help` before merging.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Signed-off-by: jitokim <pigberger70@gmail.com>
@github-actions github-actions Bot added area/cmd CLI entrypoint and command wiring area/control Terminal multiplexer actuation backends area/tui Terminal UI labels Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cmd CLI entrypoint and command wiring area/control Terminal multiplexer actuation backends area/tui Terminal UI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant