First mate v1b — live integration (supervisor + heartbeat)#3
Open
tomplex wants to merge 7 commits into
Open
Conversation
…ures bridge session; heartbeat emit hoists to main loop)
… pane_id -> respawn loop); drop unused _render_delta prev + dup import
…e first mate is reachable in the dashboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes the first mate live, on top of the v1a substrate. Stacked on #2 (base is
claude-driver, notmain) — its diff is v1b-only; retarget tomainonce #2 lands.What it adds (all inside the already-
is_prod()-gated activity worker)first_mate.supervisor_pass/_spawn_first_mate) — ensures one livebridge:first-matepane: spawns viaclaude_exec() --append-system-prompt ROLE_PROMPT, marks it (first_matetable), respawns if it dies. Idempotent (a live marker short-circuits). Self-gates onis_prod()— dev never spawns._worker_tick(worker thread) assembles a side-effect-free per-pane digest (assemble_pane_views+ pure_curate_pane, nobuild_window_viewso it can't race the poll), diverges vs the last push, and stashes aPush;run_worker(main loop)awaitsemit_channel_event, advancing_LAST_SENTonly on a successful send (retry-next-tick fallback).need_humaninterrupt hook in_do_notify_tool— immediate push to the first mate, out of band from the 30s heartbeat.fleet_digestpull tool (the one v1a deferred) + theROLE_PROMPT(chief-of-staff role, standing-tier only, absolute prohibitions incl. never-merge-fdy).Correctness points worth a reviewer's eye
asyncio.runin the worker thread —_MCP_SESSIONSstreams are loop-affine; an in-thread loop would be a cross-loop bug. Theneed_humanhook uses_task(create_task(...))because_do_notify_toolalready runs on the main loop.handle= tmuxpane_id(%N), not@periscope_id— worker rows carry no resolved pid (resolution writes state.json and isn't thread-safe).%Nread comes back empty, it leaves the marker unset rather than stampingpane_id=""— which would've been never-in-the-live-set and respawned a window every tick (unbounded budget leak). Regression-tested.run_workerstays mocked intest_app.py— so the in-tick supervisor/heartbeat never fires a live pass during pytest (budget-safety landmine).Provenance & tests
structure → (event-loop + spec corrections) → plan → plan-review (caught 2 Must-fix: pid-empty handle, async tests no-op) → subagent execution → 2-stage review (code-review caught the phantom-marker bug).
uv run pytest -q→ 706 passed, incl. a real@needs_tmuxspawn/respawn integration test (isolated-Lsocket,catstub exec).🤖 Generated with Claude Code