Skip to content

feat(conductors): Mind + Cortex dashboards emit the state.json cockpit feed #418

Description

@Jammy2211

Overview

Brain, Heart, Hands and Memory now publish the v1 cockpit feed. The Mind task dashboard and the Cortex
science dashboard are different: their pages are rendered by Brain conductors (intake _intake.py
dashboard --apply writes PyAutoMind/dashboard.{md,html}; cortex _cortex.py dashboard/checkin
writes PyAutoCortex/dashboard.{md,html}), committed into those repos, and their pages_dashboard.yml
only copies dashboard.html into _site. So the emit lives in the Brain, and the two repos need the
file allowed through their guards and copied/validated in their workflows.

Both conductors already put PyAutoBrain/board/ on sys.path (intake ~L62, cortex L71), so
from _state import build_state, validate_state works with no new path hack (same as board/_board.py).

Design decisions

  • updated vs --check idempotence. census()["generated"] is date-only in both conductors and the
    contract needs a UTC time. Emit the real render time (datetime.now(UTC) → whole-second Z) and make
    the drift check compare state.json with updated normalised out (a _state_body() that loads the
    JSON, drops updated, re-dumps), exactly as _dashboard_body drops the generation stamp.
  • Never re-derive. Items carry the same copy payloads the dashboard rows already carry
    (/start_dev <path>, _registry_payload, _review_payload, checkin_payload, resume_payload).
  • Merge order. Mind and Cortex PRs first (guards + workflows, harmless with the file absent: cp
    guarded by [ -f state.json ]), then Brain (starts emitting). Otherwise the Mind self-heal would
    commit an unlisted root file and spawn_drift.yml / the ledger merge would go red.

PR A — PyAutoMind (feature/mind-cortex-state-feed)

  1. scripts/spawn.py MIND_RULES (~L113-118): add ("state.json", "DROP") beside dashboard.html;
    mirror in docs/pyautobrain/spawn_spec.md (rows 7b/7c). tests/test_spawn_template_contract.py
    keeps guarding.
  2. scripts/ledger_merge.py: add state.json to LEDGER_FILES (L80-92) and GENERATED_FILES (L249);
    extend tests/test_ledger_merge.py (a claude/** branch carrying it is still auto-mergeable; a conflict
    resolves to main's copy).
  3. .github/workflows/mind_ledger_merge.yml (~L245-248): add state.json to the explicit git add -A --
    list after the --apply dashboard re-render.
  4. .github/workflows/dashboard_refresh.yml: trigger paths + the git add dashboard.md dashboard.html
    (L237) gain state.json; the freshness --check already covers it once Brain's check does.
  5. .github/workflows/pages_dashboard.yml: trigger path + [ -f state.json ] && cp state.json _site/state.json;
    new step checking out PyAutoLabs/PyAutoBrain (path PyAutoBrain, like dashboard_refresh.yml) and
    running [ -f _site/state.json ] && python3 PyAutoBrain/board/_state.py _site/state.json ("Validate the
    cockpit feed against the Brain contract").

PR B — PyAutoCortex (feature/mind-cortex-state-feed)

  1. scripts/ledger_merge.py LEDGER_FILES (L79) += state.json (so cortex checkin --push and the
    ledger auto-merge accept it); tests/test_ledger_merge.py case.
  2. .github/workflows/dashboard_refresh.yml git add (L158) + trigger paths += state.json.
  3. .github/workflows/pages_dashboard.yml: same guarded cp + Brain checkout + validate step as Mind.
  4. .github/workflows/cortex_check.yml paths: optional, add state.json for symmetry.

PR C — PyAutoBrain (feature/mind-cortex-state-feed, after A and B merge)

  1. agents/conductors/intake/_intake.py: render_state(c) → JSON text via build_state(organ="mind", repo=<from c["home"]>, status, headline, updated, pages_url=_pages_url(c["home"]), items).
    Status: red if c["drift"] or c["hygiene"] flags block, or any in-flight row's status contains
    awaiting-input/blocked; yellow if any in-flight row is awaiting-merge/library-shipped, or
    human_review non-empty, or pending_release non-empty, or picks exist; green otherwise;
    grey when the census has no records at all. Headline = the Start-here count line the page shows
    (N picks · M in flight), state-word prefixed when not green. Items (cap 20, red→yellow→info):
    in-flight rows needing a human (url = PR if any else issue, prompt = the row's own payload); human
    review rows (_review_payload); pending-release rows; then top picks (/start_dev {path}, info).
    pages dict gains "state.json"; --check uses _state_body for that key; --apply writes it.
  2. agents/conductors/cortex/_cortex.py: render_state(c) for organ cortex: red if c["problems"];
    yellow if counts.running > 0 or the check-in is stale (port the JS freshness rule at L583-600 to
    Python, one helper) ; green otherwise; grey with no ledgers. Headline A active · R running.
    Items: problems → red (url = ledger issue_url if any); stale check-in → yellow with checkin_payload;
    running runs → info with resume_payload(key,row) and the ledger's issue_url. render_pages adds
    state.json; dashboard_body equivalent normalises updated; cmd_dashboard check/apply and
    cmd_checkin write it; classify_paths will pass once PR B is on Cortex main.
  3. Tests: tests/test_intake_dashboard.py — --apply writes a state.json that validates on the fictional
    Mind; awaiting-merge row → yellow item with the PR url; empty Mind → grey; --check is clean after
    --apply even when updated changes (monkeypatch the clock). tests/test_cortex_conductor.py — same
    on the skeleton (grey/green, a problem → red, a running run → info with resume payload). Fixtures
    tests/fixtures/state/{mind,cortex}.json join test_state_feed.py's parametrised validation.
  4. Docs: one line each in the two conductors' AGENTS.md and board/AGENTS.md's feed list.

Branch survey / claims

Repo Branch Dirty Claimed by
PyAutoBrain main clean eyes-organ-order (AGENTS/README/docs/root-resolution), cosmos-web-ring-greeting (clone conductor) — disjoint
PyAutoMind main clean eyes-organ-order (repos.yaml, hooks, scripts/repos_sync.py) — disjoint
PyAutoCortex claude/checkin-2026-09-19, 7 dirty, 5 unpushed (a science check-in session) — eyes-organ-order (AGENTS.md) — disjoint

The canonical Cortex checkout is left untouched; the task worktree cuts from origin/main. Own worktree
with parallel-claim: recorded (the #177 precedent).

Execution (Fable session)

/create_issue on PyAutoBrain → register active.md (parallel-claim) → worktree_create mind-cortex-state-feed PyAutoBrain PyAutoMind PyAutoCortex → ONE Opus subagent (three repos, three
commits, Mind/Cortex first so the Brain renderers can be exercised against them locally), progress file +
Monitor → /ship_library: Heart gate (RED, integrate — ask again), push + PRs A, B, C; merge A and B on
green with the human's command, then C; dispatch dashboard_refresh.yml on Mind and Cortex (they
re-render, commit state.json, dispatch Pages) → verify both published feeds → close-out.

Verification

  • Brain: pytest tests/test_intake_dashboard.py tests/test_cortex_conductor.py tests/test_state_feed.py;
    _intake.py --mind <wt>/PyAutoMind --apply dashboard then dashboard --check clean; the written
    PyAutoMind/state.json passes python board/_state.py; same for _cortex.py --cortex <wt>/PyAutoCortex.
  • Mind: pytest tests/test_spawn_template_contract.py tests/test_ledger_merge.py; spawn.py --check OK.
  • Cortex: pytest tests/test_ledger_merge.py.
  • After merges: both dashboard_refresh.yml runs commit state.json and dispatch Pages; both
    pages_dashboard.yml runs green with state: ok; curl https://pyautolabs.github.io/{PyAutoMind,PyAutoCortex}/state.json validates.

Original Prompt

Click to expand starting prompt

Organ cockpit: Mind and Cortex dashboards emit state.json via their Brain renderers

Type: feature
Target: PyAutoBrain
Repos:

  • PyAutoBrain
  • PyAutoMind
  • PyAutoCortex
    Difficulty: medium
    Autonomy: safe
    Priority: high
    Status: formalised
    Consequence: notify
    Witness: pyauto-brain intake dashboard --check reports current with state.json tracked in PyAutoMind; both pages_dashboard.yml runs green with 'state: ok'; curl https://pyautolabs.github.io/PyAutoMind/state.json and /PyAutoCortex/state.json pass the validator.
    Review-minutes: 0
    Unattended: ready
    Filed: 2026-09-26
    Epic: organ-cockpit

Phase 1 (PyAutoBrain#416, shipped 2026-09-26) defined the per-organ state.json v1 cockpit feed (board/state_schema.json, board/_state.py). The Mind task dashboard and the Cortex science dashboard are not rendered in their own repos: PyAutoBrain's intake conductor writes PyAutoMind/dashboard.md + dashboard.html (pyauto-brain intake --apply dashboard) and the cortex conductor writes PyAutoCortex's dashboard, and each repo's pages_dashboard.yml only copies dashboard.html into _site. So the emit lives in the Brain renderers and the publish/validate lives in the two workflows.

  1. PyAutoBrain intake dashboard renderer: --apply also writes PyAutoMind/state.json (organ mind, repo PyAutoMind, status from the dashboard's own headline logic — red if any task is blocked/awaiting-input, yellow if picks are waiting, green otherwise; headline = the picks/in-flight count line; items = in-flight tasks awaiting a human (awaiting-merge, awaiting-input, human review) each with its issue/PR link and the existing /start_dev or /prm copy payload as prompt). Validate through board/_state.validate_state before writing. The dashboard --check must also compare state.json.
  2. PyAutoBrain cortex conductor: the same for PyAutoCortex/state.json (organ cortex: red if any project ledger reports a failed run, yellow if runs are pending pull/checkin, green otherwise; items = projects needing the human with links).
  3. PyAutoMind and PyAutoCortex pages_dashboard.yml: cp state.json _site/state.json and a validate step; both jobs must check out PyAutoBrain (like knowledge_board.yml does) to run python3 PyAutoBrain/board/_state.py _site/state.json. dashboard_refresh.yml self-heal must regenerate state.json with the html.
  4. Brain tests: both renderers produce a feed that validates on the hermetic dashboard fixtures; Mind/Cortex commit guards accept the new tracked file.

Witness: pyauto-brain intake dashboard --check reports current with state.json tracked in PyAutoMind; both pages_dashboard.yml runs green with 'state: ok'; curl https://pyautolabs.github.io/PyAutoMind/state.json and /PyAutoCortex/state.json pass the validator.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions