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:
2026-09-12 07:26:03 -05:00
co-authored by Claude Fable 5.1
parent 1993039c76
commit b9f59a5903
10 changed files with 1003 additions and 15 deletions
+82
View File
@@ -0,0 +1,82 @@
# control-board
Step 1 of the control board MVP (`docs/plans/2026-09-12_control-board-mvp.md`).
This package scans your running pi agent sessions and writes one small JSON
status file per agent, plus one summary file, so a later web page can show
them all in one place. It reads pi session logs and checks tmux liveness. It
does not launch, stop, or talk to any agent. Board files are derived and
rewritable; they are not run records and are not evidence.
## States
| 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. |
## Command
```
node src/cli.mjs scan [--config PATH] [--repo PATH] [--fleet PATH|none] [--liveness tmux|assume-alive] [--print]
```
- `--config PATH` — path to the system config file. Defaults to
`~/.config/mosaic-dev/config.json`. This file must exist and name an
absolute `dataRoot`, or the scanner refuses to run.
- `--repo PATH` — path to a project checkout to scan for repo agents
(`.pi/state/<agent>/sessions`). Defaults to the current directory.
- `--fleet PATH|none` — path to the fleet agents directory
(`<fleet>/<agent>/.pi/agent/sessions`, tmux socket `mosaic-fleet`).
Defaults to `~/.mosaic/fleet/agents`. Pass `none` to skip fleet agents.
- `--liveness tmux|assume-alive` — how to decide if an agent is alive.
`tmux` (default) checks the real tmux session. `assume-alive` treats
every agent as alive, useful for tests or environments without tmux.
- `--print` — also print a one-line-per-agent table to stdout.
## Exit codes
- `0` — scan completed and status files were written.
- `2` — refused: bad config, missing/invalid `dataRoot`, or bad arguments.
The message on stderr says why.
## Tests
```
node --test packages/control-board/tests/
```
## Output layout
```
<dataRoot>/board/
index.json # summary: counts, waiting-on-you list, all records
sessions/
<project>/
<agent>.json # one status record per agent
```
## Example status record
```json
{
"agent": "darkwing",
"project": "mosaic-stack",
"state": "waiting",
"waitingOnYou": true,
"alive": true,
"tmux": { "socket": null, "session": "darkwing" },
"sessionFile": "/mnt/storage/src/mosaic-stack/.pi/state/darkwing/sessions/2026-09-12.jsonl",
"sessionId": "01a06e48-0718-71f2-a889-c263c4800fb9",
"cwd": "/mnt/storage/src/mosaic-stack",
"lastActivity": "2026-09-12T15:04:33.000Z",
"ageSeconds": 42,
"lastAssistantText": "Ready for the next step whenever you are.",
"lastError": null,
"skippedLines": 0,
"scannedAt": "2026-09-12T15:05:15.000Z"
}
```