Skip to content

feat(bin): orchestrator dashboard layout with read-only worker watch panes#110

Open
MerpGoaterman wants to merge 3 commits into
kunchenguid:mainfrom
MerpGoaterman:fm/orchestrator-worker-layout-k9
Open

feat(bin): orchestrator dashboard layout with read-only worker watch panes#110
MerpGoaterman wants to merge 3 commits into
kunchenguid:mainfrom
MerpGoaterman:fm/orchestrator-worker-layout-k9

Conversation

@MerpGoaterman

Copy link
Copy Markdown

Intent

Terminal orchestrator dashboard for firstmate (bin/fm-layout.sh): arranges the firstmate tmux window into a left command column (orchestrator chat top 2/3, terse active-worker summary bottom 1/3) and a right column of three stacked worker watch slots that are deliberately READ-ONLY capture-pane mirrors of live worker windows so workers keep running untouched and the orchestrator pane is never obscured. Deliberate design choices a reviewer should not flag as bugs: read-only mirroring instead of join-pane; discovery from state/*.meta with secondmate/stale windows intentionally excluded; mouse/right-click reassignment provided only as an opt-in, explicitly-documented best-effort path because tmux key tables are server-global (keyboard picker is the supported baseline); arrange refuses worker windows and unexpected panes rather than destroying them; keybindings opt-in and runtime-only, never editing ~/.tmux.conf; AGENTS.md prose intentionally left unchanged to avoid overlap with in-flight PR #105. Covered by tests/fm-layout.test.sh on a private tmux socket; documented in docs/orchestrator-layout.md.

What Changed

  • Add bin/fm-layout.sh (plus fm-layout-lib.sh, fm-layout-pick.sh, fm-watch-pane.sh) to arrange the firstmate tmux window into a left command column (orchestrator chat over a terse active-worker summary) and a right column of three stacked, read-only capture-pane mirrors of live worker windows, with workers discovered from state/*.meta (secondmate and stale windows excluded) and an opt-in keyboard/mouse slot reassignment picker.
  • Make arrange non-destructive: it refuses worker windows and unexpected panes rather than tearing them down, keybindings are runtime-only and never edit ~/.tmux.conf.
  • Use a portable while IFS= read -r worker loop instead of the bash 4+ mapfile so the picker works on macOS bash 3.2, and document the tmux 3.1 minimum (percentage split-window -l) requirement.
  • Add tests/fm-layout.test.sh (7 cases on a private tmux socket) and docs/orchestrator-layout.md, with supporting entries in README.md, docs/configuration.md, and docs/scripts.md.

Risk Assessment

✅ Low: Additive, well-bounded read-only tmux dashboard tooling with real-tmux test coverage; the prior bash-3.2 portability bug is fixed and the only remaining items are minor robustness/cosmetic edge cases.

Testing

Ran the existing suite (tests/fm-layout.test.sh, 7/7 green) and additionally exercised fm-layout.sh end-to-end against a real tmux 3.6b server on a private socket with three fake live workers plus a secondmate and a stale meta: discovery listed only the three real workers, arrange produced the intended left command column (orchestrator 2/3 + worker summary 1/3) beside three stacked read-only watch panes that mirrored each live worker, re-arrange stayed idempotent without killing workers, and arrange refused a worker window without --force. Visual evidence is reviewer-visible as captured tmux pane text and a stitched composite of the full dashboard (terminal TUI, so the surface is text - no browser/HTML rendering applies). Overall result: pass, no findings.

  • Evidence: Composite dashboard view (what the captain sees) (local file: /var/folders/nt/qwfnn1kn15bcm70g15cygtkw0000gn/T/no-mistakes-evidence/01KW5HJ1HKH0VMW40W0C09BCS2/00-dashboard-composite.txt)
Evidence: Dashboard pane geometry (left 1/3 command column + right 2/3 three stacked slots)

%0 role=orchestrator title="orchestrator" 67x32 @0,1 active=1 %8 role=summary title="workers" 67x16 @0,34 active=0 %5 role=slot:1 title="watch 1" 132x15 @68,1 active=0 %6 role=slot:2 title="watch 2" 132x16 @68,17 active=0 %7 role=slot:3 title="watch 3" 132x16 @68,34 active=0

%0 role=orchestrator title="orchestrator" 67x32 @0,1 active=1
%8 role=summary title="workers" 67x16 @0,34 active=0
%5 role=slot:1 title="watch 1" 132x15 @68,1 active=0
%6 role=slot:2 title="watch 2" 132x16 @68,17 active=0
%7 role=slot:3 title="watch 3" 132x16 @68,34 active=0
Evidence: Worker discovery: only live non-secondmate workers (secondmate + stale meta excluded)

1 fm:fm-add-export-csv-q7 reportkit add export csv 2 fm:fm-fix-login-k3 webapp fix login 3 fm:fm-repro-crash-on-startup-z2 mobileapp repro crash on startup

1	fm:fm-add-export-csv-q7	reportkit	add export csv
2	fm:fm-fix-login-k3	webapp	fix login
3	fm:fm-repro-crash-on-startup-z2	mobileapp	repro crash on startup
- Evidence: Watch slot 1 read-only mirror of live worker pane (local file: /var/folders/nt/qwfnn1kn15bcm70g15cygtkw0000gn/T/no-mistakes-evidence/01KW5HJ1HKH0VMW40W0C09BCS2/pane-slot-1.txt) - Evidence: Terse active-worker summary pane (bullets) (local file: /var/folders/nt/qwfnn1kn15bcm70g15cygtkw0000gn/T/no-mistakes-evidence/01KW5HJ1HKH0VMW40W0C09BCS2/pane-summary.txt)
Evidence: Idempotency + safety refusal

panes after re-arrange: 5 (expect 5) worker windows still alive: 4 (expect 4: 3 workers + 1 secondmate) -- fm-layout: 'fm-fix-login-k3' looks like a worker window; refusing to arrange it (pass --force to override)

panes after re-arrange: 5 (expect 5)
worker windows still alive: 4 (expect 4: 3 workers + 1 secondmate)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 2 infos
  • ⚠️ bin/fm-layout-pick.sh:27 - fm-layout-pick.sh uses mapfile -t WORKERS, a bash 4+ builtin, but the shebang resolves to bash 3.2.57 on this macOS host (confirmed). Under 3.2 mapfile is undefined, leaving WORKERS empty, so the keyboard picker - the documented supported baseline selector - always shows 'no active workers' and can never reassign a slot. Every other bin/ script avoids mapfile and uses while-read loops; replace it with a portable while IFS= read -r line loop to match.
  • ℹ️ bin/fm-layout.sh:210 - split-window -l 66% / -l 33% use the percentage form of -l, which tmux only supports from 3.1 onward (older tmux required -p). On tmux < 3.1 arrange fails. Document this as a minimum-version requirement.

🔧 Fix: fix(layout): portable worker picker on bash 3.2, document tmux 3.1 requirement
2 infos still open:

  • ℹ️ bin/fm-layout.sh:219 - In cmd_arrange, the @fm_role tags are applied only after all four split-window calls succeed. If any split fails partway (e.g. on tmux < 3.1 where -l 66% is unsupported, or a transient tmux error), set -e aborts leaving one or more untagged viewer panes in the window. A subsequent arrange then tears down only role-tagged panes, finds the untagged leftovers as 'unexpected pane(s)', and refuses without --force — so a partially-built dashboard can only be recovered with --force. Tagging each pane with its @fm_role immediately after it is created would make re-arrange self-heal a partial build.
  • ℹ️ bin/fm-watch-pane.sh:34 - fit() truncates by byte length, and the header lines passed through it include ANSI escape sequences (BOLD/DIM and the trailing RST reset) that count toward the width budget. On a narrow watch pane, a long worker header can be cut before its \033[0m reset, leaking bold/dim attributes onto following lines. The header is also truncated earlier than its visible content warrants because the ~20 escape bytes are billed against the column count. This is an acknowledged best-effort byte-wise tradeoff per the function comment; flagging only as a visual edge case.
✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-layout.test.sh — all 7 cases pass on a private tmux socket
  • End-to-end demo on a private tmux server: fm-layout.sh workers (discovery excluded secondmate + stale meta)
  • fm-layout.sh arrange --window &lt;orch&gt; then captured pane geometry and per-pane content (orchestrator/summary/slot:1-3)
  • Verified read-only worker mirroring: each watch pane reflected its live worker's pane content; summary rendered terse • repo - label bullets
  • Idempotency: re-ran arrange, confirmed 5 panes and all 4 worker windows still alive/untouched
  • Safety: arrange --window &lt;worker&gt; refused without --force (exit 1)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…panes

Add fm-layout.sh to arrange the firstmate window into a left command column
(orchestrator chat top 2/3, terse active-worker summary bottom 1/3) and a right
2/3 column of three stacked worker watch slots. Watch slots are read-only
capture-pane mirrors of live worker windows, so workers keep running untouched;
the orchestrator pane stays focused and is never replaced or obscured.

Workers are discovered from state/*.meta (live windows only; secondmates and
stale metas excluded) with a terse repo + feature label. Slots autofill from the
first active workers and any worker can be swapped into any slot via a reliable
keyboard picker popup (fm-layout-pick.sh); right-click reassignment is offered as
an opt-in, documented best-effort path given tmux's server-global key tables.

arrange is safe to re-run: it rebuilds only its own viewer panes, never kills a
worker or unrecognized pane, refuses worker windows and windows with unexpected
panes, and never spawns work to fill a slot. Keybindings are opt-in and
runtime-only (never ~/.tmux.conf).

Covered by tests/fm-layout.test.sh (real tmux on a private socket): discovery,
label truncation, assign/clear/reject, geometry, idempotent re-run, refusals, and
rendered summary/mirror content.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant