Add control board status scanner and MVP plan (#1503)
Step 1 of the control board MVP (decision MOSAIC-STACK-D-001): a plan page, Gitea #1503, and packages/control-board, which reads each agent's newest pi session log plus tmux liveness and writes one status file per agent under <dataRoot>/board/. 23/23 tests; independent review approved after three fixes (length stopReason as error, unknown liveness state, secrets-boundary test). CURRENT.md now points at step 2, the page. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
@@ -209,3 +209,6 @@ are never rewritten or removed; corrections are new entries.
|
||||
- 2026-09-12 — jarvis (Claude Code; owner-directed takeover of darkwing pi session 01a07cfa) — Recovered #1500 state from the session log; demo test reran 2/2 on 5abbabb7; issue open, remote refactor still 5abbabb7. Diagnosed owner demo failure: alacritty bash pid 2444405 (started 2026-09-07 14:26 UTC, before cutover) has cwd inode in the retired v1 copy; logical pwd printed the canonical path, HEAD read 5d277000, and a 2026-09-12 git pull fast-forwarded that copy to next 2101c9b4 (fred, #1502). No repository changes, commit or push; darkwing pi (pid 45527) left running.
|
||||
|
||||
- 2026-09-12 — jarvis (Claude Code, darkwing takeover) — #1500 owner acceptance recorded (Jason demo 2/2 at 5abbabb7) and issue closed via scripts/gitea-api.sh (comment 26007; Mosaic issue-close wrapper refused on seat token, fail-closed). Records-only commit; CURRENT next action is MVP re-plan against MOSAIC-STACK-D-001.
|
||||
- 2026-09-12 — dewey (Claude Code; owner-directed takeover of dewey pi session 01a08111) — Resumed WUI Phase 2 from agents/dewey/work/wui/TASKS.md: D01 source-linked feature inventory, then D02-D05 five dashboard mockups and comparison page, folding in MOSAIC-STACK-D-001 control board as the landing view. Prototype files only under agents/dewey/work/wui; no v1 inspection, backend, credentials, commit or push.
|
||||
|
||||
- 2026-09-12 — jarvis (Claude Code, coordinator) — Control board MVP step 1 (#1503, D-001): plan page, ticket, `packages/control-board` scanner + CLI, 23/23 tests, live scan 42 sessions/18 waiting on Jason; independent review CHANGES REQUIRED then APPROVED after three fixes (length→error, unknown liveness state, secrets-boundary test). Receipt docs/plans/reviews/2026-09-12_control-board-step1-review.md. CURRENT next action: step 2, the page.
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
# Control board MVP — plan
|
||||
|
||||
Tracking: Gitea issue #1503 (https://git.mosaicstack.dev/mosaicstack/stack/issues/1503)
|
||||
|
||||
## Why
|
||||
|
||||
Jason is building blind. He has many agent sessions running across projects
|
||||
and no single place to see what they are doing or who is waiting on him.
|
||||
This plan replaces the registry line as the next thing to build. Registry
|
||||
increment 3 stays parked; it does not resume by inertia. Decision record:
|
||||
`MOSAIC-STACK-D-001` (Jason, 2026-09-12).
|
||||
|
||||
## What "done" looks like for the MVP
|
||||
|
||||
One web page lists my running agent sessions across projects, shows each
|
||||
one's current status, and flags which ones are waiting on me.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Jason opens one page and sees every live pi agent, grouped by project.
|
||||
- Each agent shows a state in plain words (working, waiting, error,
|
||||
offline, idle, unknown).
|
||||
- A "waiting on you" section sits at the top of the page.
|
||||
- The page refreshes itself. Jason does not have to reload it by hand.
|
||||
- Every state on the page comes from a status file written by the scanner,
|
||||
not from a guess made in the page itself.
|
||||
|
||||
## Three steps
|
||||
|
||||
### Step 1 (today): plan, ticket, scanner
|
||||
|
||||
- Write this plan and open the Gitea ticket.
|
||||
- Build the status scanner script with tests. Running it writes one status
|
||||
file per agent under `<dataRoot>/board/`.
|
||||
- This step does not touch any page or launcher. It only produces files.
|
||||
|
||||
### Step 2: the web page
|
||||
|
||||
- Build a page that reads the status files the scanner writes and shows
|
||||
them grouped by project, with the waiting-on-you section on top.
|
||||
- The page refreshes itself on a short timer. The small local server behind
|
||||
it may re-run the scanner on each refresh so the files stay fresh. No
|
||||
separate daemon is needed for this step.
|
||||
|
||||
### Step 3: daily use and fixes
|
||||
|
||||
- Jason uses the page every day for real work.
|
||||
- He says what is wrong or missing.
|
||||
- Fix that one thing, then repeat. No new scope beyond what he actually hits.
|
||||
|
||||
## How the scanner decides state
|
||||
|
||||
The scanner reads the newest pi session log for each agent, plus whether
|
||||
the agent's tmux session is still alive. It does not guess; it only reports
|
||||
what the log and tmux say.
|
||||
|
||||
| State | Plain-words meaning |
|
||||
|---------|----------------------|
|
||||
| working | The agent is in the middle of a turn: thinking or running a tool. |
|
||||
| waiting | The agent finished its turn. It is your move now. |
|
||||
| error | The agent's last turn ended in an error, was aborted, or was cut off. Go look at it. |
|
||||
| offline | There is no live tmux session for this agent right now. |
|
||||
| idle | The agent is live but has not had a conversation yet. |
|
||||
| unknown | The scanner could not ask tmux (missing or not answering). It does not assume the agent is alive. |
|
||||
|
||||
Two kinds of agents are scanned today:
|
||||
|
||||
- Repo agents: session logs live under `.pi/state/<agent>/sessions` in a
|
||||
project checkout, on the default tmux socket.
|
||||
- Fleet agents: session logs live under
|
||||
`~/.mosaic/fleet/agents/<agent>/.pi/agent/sessions`, on the tmux socket
|
||||
named `mosaic-fleet`.
|
||||
|
||||
## Where files go
|
||||
|
||||
- One file per agent: `<dataRoot>/board/sessions/<project>/<agent>.json`
|
||||
- One summary file for the whole board: `<dataRoot>/board/index.json`
|
||||
- `dataRoot` comes from `~/.config/mosaic-dev/config.json`. If that config
|
||||
is missing or broken, the scanner refuses to run. It does not guess a
|
||||
fallback location.
|
||||
|
||||
Board files are derived. They can be deleted and rebuilt at any time by
|
||||
running the scanner again. They are NOT run records and they are not
|
||||
evidence under the repository's write-once rules.
|
||||
|
||||
## Command
|
||||
|
||||
```
|
||||
node packages/control-board/src/cli.mjs scan --print
|
||||
```
|
||||
|
||||
Tests:
|
||||
|
||||
```
|
||||
node --test packages/control-board/tests/
|
||||
```
|
||||
|
||||
## Boundaries
|
||||
|
||||
- No changes to any launcher script.
|
||||
- No new files at the repository root.
|
||||
- No secrets read, stored, or printed.
|
||||
- No daemon yet. In step 1 the scanner is run by hand. In step 2 the page
|
||||
may trigger it on refresh; nothing runs it on a schedule.
|
||||
- No changes to `packages/mosaic`.
|
||||
- This plan does not authorize push or merge beyond whatever the existing
|
||||
refactor-branch plan already allows.
|
||||
+16
-15
@@ -7,22 +7,23 @@ update this file to the next action). No ambiguity, no re-planning.
|
||||
|
||||
## Next action
|
||||
|
||||
Jason accepted the #1500 fixture-only increment on 2026-09-12 by running the
|
||||
two-test demonstration himself on the canonical checkout at 5abbabb7 (2/2 pass);
|
||||
receipt `docs/plans/reviews/2026-09-12_m20-increment2-owner-acceptance.md`.
|
||||
#1500 is closed. No increment 3, launcher integration, production refresh or
|
||||
deployment is authorized by that acceptance; the headless identity-env leak
|
||||
remains a separate intake owned by Darkwing.
|
||||
Jason decided on 2026-09-12 (MOSAIC-STACK-D-001) that the MVP is the control
|
||||
board: one web page listing running agent sessions across projects, showing each
|
||||
one's status, and flagging which ones are waiting on him. Plan page:
|
||||
`docs/plans/2026-09-12_control-board-mvp.md`. Tracking: #1503. Step 1 (status
|
||||
scanner `packages/control-board`, plan page, ticket) is done in this checkout;
|
||||
running `node packages/control-board/src/cli.mjs scan --print` writes one status
|
||||
file per agent under `<dataRoot>/board/`. The registry line (increment 3,
|
||||
headless identity-env leak) stays parked; #1500 is closed.
|
||||
|
||||
Next action: re-plan against Jason's 2026-09-12 MVP decision MOSAIC-STACK-D-001
|
||||
(control board: one page listing running agent sessions across projects with
|
||||
status and a "waiting on you" section, deliberately smaller than the current
|
||||
registry line). Present Jason a concrete plan that reconciles the registry
|
||||
queue (increment 3 candidates, identity-env fix) with that MVP, with a
|
||||
recommendation and acceptance evidence, before starting any new implementation.
|
||||
Owner of this planning action: the active coordinator session (jarvis, Claude
|
||||
Code, taking over darkwing's pi session). The registry queue does not resume by
|
||||
inertia.
|
||||
Next action: step 2 of #1503 — the web page. One local page that reads
|
||||
`<dataRoot>/board/index.json`, groups sessions by project, shows the plain-word
|
||||
state per agent, puts a "waiting on you" section at the top, and refreshes
|
||||
itself (re-running the scanner on each refresh is acceptable). Reuse Dewey's
|
||||
control-board mockups under `agents/dewey/work/wui/` for layout where they fit.
|
||||
Acceptance: Jason opens the page in a browser and sees the same rows the
|
||||
`--print` output shows, with no manual steps beyond starting the page. No auth,
|
||||
no hooks/plugins, no comms, no launcher changes, no new root files.
|
||||
|
||||
## Completed checkpoint: #1500 increment 2 (historical)
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Control board MVP step 1: implementation and review receipt
|
||||
|
||||
Date: 2026-09-12. Recorded by jarvis (Claude Code, coordinator). Tracking: #1503.
|
||||
Plan: `docs/plans/2026-09-12_control-board-mvp.md`. Decision: MOSAIC-STACK-D-001.
|
||||
|
||||
## What was built
|
||||
|
||||
`packages/control-board/` (ESM, no dependencies, node >= 24): `src/scan.mjs`
|
||||
reads each agent's newest pi session log plus tmux liveness and writes one
|
||||
status file per agent under `<dataRoot>/board/sessions/<project>/<agent>.json`
|
||||
and a summary `index.json`. `src/cli.mjs` wraps it (`scan --print`). Config is
|
||||
read fail-closed from `~/.config/mosaic-dev/config.json`. Board files are
|
||||
derived and rewritable; they are not run records.
|
||||
|
||||
## Tests
|
||||
|
||||
`node --test packages/control-board/tests/` — 23 tests, 23 pass, 0 fail.
|
||||
`node --test packages/mosaic/tests/` still 69/69 (untouched, checked for drift).
|
||||
|
||||
## Live run
|
||||
|
||||
`node packages/control-board/src/cli.mjs scan --print` on this host: 42 sessions
|
||||
(4 repo agents, 38 fleet agents); 15 waiting, 3 error (all three are pi
|
||||
usage-limit 429 errors on 2026-09-11), 24 offline, 0 working, 0 idle, 0 unknown;
|
||||
18 flagged waiting on Jason. Spot checks: `arena-100` offline matched
|
||||
`tmux -L mosaic-fleet has-session` refusing; the error rows matched the raw
|
||||
`stopReason: "error"` entries.
|
||||
|
||||
## Independent review
|
||||
|
||||
Reviewer: in-session code-review agent (Claude Sonnet), read-only, with access to
|
||||
the installed pi runtime for stopReason verification. First verdict: CHANGES
|
||||
REQUIRED with three findings, all fixed in the same pass:
|
||||
|
||||
1. pi emits `stopReason: "length"` when a response is cut off; it fell through to
|
||||
"working". Now mapped to "error".
|
||||
2. A tmux check that could not run (`null`) was treated as alive. Now reported as
|
||||
a distinct "unknown" state, never counted as waiting on you.
|
||||
3. No test pinned the rule that the scanner only walks inside the given sessions
|
||||
directory (fleet auth symlinks sit beside it). Added a sibling-secrets test.
|
||||
|
||||
Second verdict: APPROVED. The reviewer also noted one imprecision in my change
|
||||
summary (a lastError test I described as new in the fix round had been added just
|
||||
before the round); recorded here for honesty.
|
||||
|
||||
## Boundaries kept
|
||||
|
||||
No launcher changes, no new root files, no secrets read or printed, no changes to
|
||||
`packages/mosaic`, no daemon, no web page yet. Next action (CURRENT.md): step 2,
|
||||
the page.
|
||||
Reference in New Issue
Block a user