AINA visible-board operating playbook

How the aina-intelligence-os session (2026-08-04, Claude Fable session 2c9b77d8) stood up a

founder-visible program board with a live Cloudflare page, and the operating rhythm that keeps it

true. Give this file to any session that should run the same way.

Reference implementation: aina-intelligence-ostools/flow_board_html.py,

ops/board-activity.json, ops/dispatch/, live at https://aina-flow-board.pages.dev


Prerequisites

1. flow-next plugin installed in Claude Code (flowctl lives at ~/.claude/plugins/cache/flow-next/flow-next/<version>/bin/flowctl).

2. Wrangler authenticated on the Mac (npx wrangler whoami) with Cloudflare Pages access.

3. A git repo for the program (board state and renderer are committed; the board is code).

4. For build lanes: VDS ssh (ssh -o BatchMode=yes aina-vds-ts) with codex CLI available.

5. Linear access for milestone write-backs.

Step 0 — Verify flow-next is INSTALLED, not just loaded (Donna's 2026-08-01 finding)

"Loaded" ≠ "installed". An installed repo has ALL of:

(that block is the agent rail — without it, nothing instructs future sessions to keep writing

board state, and the board silently goes stale)

Install commands (rail write to CLAUDE.md/AGENTS.md is a founder hard gate — show the block

text and get approval first):


FC=~/.claude/plugins/cache/flow-next/flow-next/3.4.5/bin/flowctl
T=~/.claude/plugins/cache/flow-next/flow-next/3.4.5/codex/skills/flow-next-setup/templates
$FC setup-block apply --file CLAUDE.md --template $T/claude-md-snippet-plugin.md --json
$FC setup-block apply --file AGENTS.md --template $T/agents-md-snippet.md --json
$FC setup-mode set plugin --json   # refuses until the rail exists — that's the point

Step 1 — Plan: anms-locked spec on ONE board

1. Mission + non-negotiable doctrine live in .flow/STRATEGY.md (the anms canon lock — founder decisions, model assignments, hard exclusions). One mission, never a second plan file.

2. One spec per milestone; slices are the spec's ordered tasks:


$FC spec create --title "M-NAME: what this milestone delivers" --json
$FC spec set-plan <id> --file plan.md      # canon block + numbered slices, acceptance in the slice text
$FC task create --spec <id> --title "S1: ..." [--deps <prev-task-id>]

3. Falsify the plan before building (mandatory): dispatch an independent adversarial review on a DIFFERENT engine (we use gpt-5.6-terra) with a non-leading brief ("find what is wrong, not endorse"). Apply every accepted finding to the specs BEFORE the first build lane. Our round 1 returned BLOCK with 7 findings — all real.

Step 2 — Stand up the live board (Cloudflare Pages)

0. Enable flow-next's own HTML artifact mode first (shipped with the plugin; we missed it initially because the install was incomplete): flowctl config set artifacts.html.enabled true. With it on, the capture/plan/make-pr skills generate a rich per-spec review document at .flow/artifacts/<spec-id>/spec.html (and pr.html per PR) following the plugin's own design contract (references/html-artifacts.md — "render lens, not record", self-contained single file, self-check grep before publishing). These per-spec lenses are the deep-dive layer; the board page below is the live program overview — deploy the lenses alongside the board (cp -R .flow/artifacts <deploy-dir>/artifacts) and link spec titles to them.

1. Renderer: a small script (tools/flow_board_html.py) that emits one static index.html. Critical lesson: read spec/task status from flowctl specs --json / flowctl tasks --json — NEVER from the .flow/specs|tasks/*.json files (those are creation snapshots; the founder caught the stale-status bug live). Stamp generated-at + source commit on the page.

2. Include ops/board-activity.json — a hand-appended lane-activity feed. Task checkboxes move slowly; the feed is what makes the page feel alive between status flips.

3. Auto-refresh meta tag: 600s (founder-tuned; 120s was too aggressive).

4. Deploy:


npx wrangler pages project create <board-project> --production-branch main   # once
python3 tools/flow_board_html.py /tmp/flow-board
npx wrangler pages deploy /tmp/flow-board --project-name=<board-project> --commit-dirty=true
curl -s https://<board-project>.pages.dev/ | grep "generated"   # fetch receipt — always verify

5. One-link hub + VDS-owned auto-publish (Mac-independent): the board page carries a Links section (spec lenses, Linear issue, active PR, reconciliation ledger, RUNLOG, this playbook served at /playbook.html) so the founder needs exactly one URL. Publishing runs ON THE VDS — founder requirement: nothing depends on the Mac being online. A VDS cron job (*/10, tools/flow_board_publish_vds.sh) pulls main, renders from the committed git tree (no flowctl), and redeploys via the VDS's own wrangler ONLY when content changed (timestamp-stripped hash compare), logging to /srv/aina/ops/flow-board-publish.log. Sessions (which may run over SSH) just commit + push board state; the VDS does the rest. Integration with the pkm-drop → pkmlive surface is the intended next hop once that pipeline lands — the board docs are all committed files, so pkm-drop can pick them up directly.

6. Honesty rules (from the Terra plan review): pre-existing/legacy board content is labeled "historical/unreconciled" until a reconciliation ledger (every old spec/task dispositioned as DONE-EVIDENCED / SUPERSEDED / CARRY-FORWARD / UNRESOLVED, each with a citation) is produced and applied; counts cover the active program only; a failed deploy is reported, never silently skipped.

Step 3 — Operating rhythm (the lane loop)

Roles: GPT-5.6 Luna High builds (and runs E2E) · GPT-5.6 Terra verifies (adversarial,

falsification briefs) · Claude leads — writes briefs, rules on findings, reads diffs itself,

lands. Builder ≠ verifier, always cross-model. No lane result trusted without reading it.

Per lane:

1. Brief to a file first: ops/dispatch/YYYY-MM-DD-NN-<engine>-<name>.md — objective, binding context docs, acceptance criteria IN the brief (loose specs cause multi-round fix loops), rules (zero real mutations, sign your work), and the exact report path.

2. Dispatch on the VDS, detached:


b64=$(base64 < ops/dispatch/<brief>.md)
ssh aina-vds-ts "echo $b64 | base64 -d > /srv/aina/ops/<program>/brief.md; \
  cd /srv/repos/<repo> && nohup ~/.npm-global/bin/codex exec -m <model> \
  -c model_reasoning_effort=\"high\" --skip-git-repo-check \"\$(cat /srv/aina/ops/<program>/brief.md)\" \
  > /srv/aina/ops/<program>/lane-NN.log 2>&1 & echo PID=\$!"

3. Watch the process exit, not the report file (lanes write reports mid-flight): ssh aina-vds-ts 'while kill -0 <PID> 2>/dev/null; do sleep 45; done' as a background task.

4. Health heuristic (Donna): a live lane log is 100KB+; a ~4KB log that "succeeded" is a silently dead lane.

5. Verifier verdict is a hard gate: BLOCK → fixup lane scoped to EXACTLY the findings, then re-review. Repeat until PASS (S1 took 3 rounds; every round found something real).

6. Land through the repo's PR gate at milestones, not per lane. Lead reads the cumulative diff itself before raising the PR.

Step 4 — Write-backs (every checkpoint, one motion)

The rule: if a surface (board/RUNLOG/Linear/docs) would disagree with reality after your action,

updating it is part of the action, not a follow-up.

Failure modes hit today (avoid re-learning)

FailureFix
Board stale, program ran off-boardStep 0 rail was missing — verify setup_mode before trusting any .flow board
Renderer showed done tasks as todoRenderer read .json snapshots; status truth is flowctl … --json only
Board "looked frozen" during lane roundsActivity feed (Step 2.2) — task checkboxes alone are not visibility
Lane died silently at exit 0Disk full (Mac AND VDS same day); check df when a lane dies mid-write; lanes must clean their worktrees even on failure
ssh dispatch hangs the sessionnohup … & inside the remote command + background watcher; never hold ssh open for a long lane
Review lane green but scope uncheckedAlways verify a checker's own scope/freshness (Donna's checker-scope failure class)

— claude-lead (claude-fable-5) · 2026-08-04 America/Toronto · session 2c9b77d8 ·

reference program: DAT-151 resume, aina-intelligence-os