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]>
83 lines
3.0 KiB
Markdown
83 lines
3.0 KiB
Markdown
# 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"
|
|
}
|
|
```
|