Repository navigation
feat(bin): add Prime Agent as a verified crewmate and scout harness - #2
Merged
Merged
Conversation
Detect Prime Agent through its own kernel and daemon-worker markers, before the Pi marker that Prime sets for every tool. Launch Prime workers with --no-skills and --no-session, and load a per-task extension that reports busy state and turn ends. Map effort to --thinking, interrupt with one Ctrl+C, and exit with /quit. Refuse Prime for secondmates, because no Prime primary integration exists. Record the live Herdr evidence in docs/verification/prime.md and add an opt-in live guard.
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.
Intent
Captain (13 Sep 2026, from data/harness-inventory-13sep/report.md part B): verify Prime Agent as a firstmate worker harness under the harness-adapters verify plan. Two known entry blockers: the PI_CODING_AGENT marker collision with the pi adapter, and the 366k-token skills prompt from ~/.agents/skills. Also clear the two idle Prime Agent sessions the 13 Sep probes left open.
What Changed
prime(Prime Agent) as a verified crewmate and scout harness.bin/fm-harness.shchecks forPRIME_AGENT_KERNEL_OWNER_PID,PRIME_AGENT_INTERNAL_DAEMON_WORKER, or theprime-agentprocess title before it checksPI_CODING_AGENT=true. This stops a Prime worker from showing aspi.fm-spawn.shstarts it with--no-skills --no-session, which keeps the startup prompt small and stops the worker when its TUI exits.fm-spawn.shalso maps shared effort levels to--thinking. Bootstrap validation, quota provider mapping, and teardown now includeprime.state/<id>.prime-ext.tsextension with theprime-extbusy source. It sets busy onagent_start. Afteragent_end, it pollsctx.isIdle()with no time limit and sets idle when that check is true. It also sets idle onsession_shutdownand touches the turn-end marker onturn_end. Infm-control-lib.sh, Prime uses oneC-cto interrupt and/quitto exit.fm-spawn.shrefuses other backends before it creates an endpoint.fm-control.shrefuses a relaunch ontoprimeon another backend before it stops the running agent. New docs: thereferences/harness/prime.mdskill reference anddocs/verification/prime.mdevidence. New tests:tests/fm-prime-harness.test.sh, the opt-intests/fm-prime-herdr-live-e2e.test.sh, and Prime cases in the busy-wiring, control, and relaunch tests.🤖 Generated with Claude Code
Risk Assessment
✅ Low: The change adds an opt-in, herdr-only crewmate adapter. Prime markers are checked before the Pi marker, and
--no-skillsbounds the startup prompt. A shared capability check in fm-control-lib.sh refuses Prime on other backends, in both spawn and relaunch, before anything stops. The idle poll has no cap, and a newer run or shutdown supersedes it. Tests cover the new behavior, and no existing adapter path changes behavior.Testing
I drove the real prime-agent inside an isolated Herdr lab session through the exact launch that fm-spawn composes. Native detection, Prime-over-Pi harness detection, extension idle settling, the single Ctrl+C interrupt, and /quit worker cleanup all passed. A live token measurement confirmed that --no-skills cuts the prompt from 60,533 to 18,148 tokens. The real fm-spawn refuses Prime on tmux and zellij and records no task state. The 13 Sep probe sessions are archived. The relaunch refusal before stop and the uncapped idle poll were not driven live. Only the faked-tmux relaunch test and the virtual-time busy wiring test cover them. The Prime harness, busy wiring, control, and relaunch suites pass. The earlier baseline failure in fm-lint.test.sh is fixed. When I reported, the baseline rerun had finished 27 files with no failures and was still running.
tests/fm-control-relaunch.test.shcovered it. Run the relaunch on a host with tmux…Evidence: Live Prime Agent Herdr guard transcript
Source: Live Prime Agent Herdr guard transcript
# prime-agent 0.9.4 # herdr 0.9.0 # model openrouter/moonshotai/kimi-k2.6 ok - real herdr: detects the Prime pane natively as agent prime-agent ok - real prime-agent: a tool beside PI_CODING_AGENT=true detects harness prime ok - real prime-agent: the generated extension settles the turn idle and touches the turn-end marker ok - real prime-agent: one Ctrl+C cancels the run, keeps the agent, and settles idle ok - real prime-agent: /quit ends the client-owned worker and its Python kernelEvidence: Skills prompt budget, live
Source: Skills prompt budget, live
480 skills; default: prompt_tokens 60533; --no-skills: prompt_tokens 18148Evidence: Real fm-spawn refuses Prime on non-herdr backends
Source: Real fm-spawn refuses Prime on non-herdr backends
error: prime is verified on the herdr backend only; backend 'tmux' is unverified for Prime. Select --backend herdr or a different verified harness. exit=1 # state dir after refusal: .last-watcher-beatEvidence: 13 Sep Prime probe sessions state
Source: 13 Sep Prime probe sessions state
01a09ad4-... archived idle 2026-09-13T12:53 no-worker 01a09ad3-... archived idle 2026-09-13T12:52 no-worker live sessions created 2026-09-13: 0Evidence: Prime harness behavior tests
Source: Prime harness behavior tests
Evidence: Prime busy-state wiring tests
Source: Prime busy-state wiring tests
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed (2) ✅
bin/fm-spawn.sh:2801- The Prime extension stops polling 30 seconds afteragent_end. Ifctx.isIdle()has not read true by then, nothing publishes idle, and the busy record staysbusy prime-extuntil the nextagent_start. Example sequence: a long turn ends withagent_end, then Prime keeps the session non-idle for more than 30s (for example threshold auto-compaction over a large context) and settles without a new run. The poll gave up atIDLE_POLL_LIMIT_MS, so the crewmate classifies busy with no end. Consumers that wait for idle (inbox delivery, supervision) never see the turn finish.docs/verification/prime.mdlists this case as not verified, and the comment says leaving busy is deliberate. That is why this is ask-user. Smallest remedy: keep polling with backoff until a neweragent_startorsession_shutdownsupersedes it, instead of a hard 30s give-up.bin/backends/tmux.sh:172- Prime is now dispatchable on every backend, including defaulttmux, but only Herdr was verified.fm_backend_tmux_classify_process_namehas noprime-agententry, andfm_harness_path_namehas noprime-agentname. On tmux, a running Prime pane therefore classifiesother, andfm_backend_agent_statereadsambiguous. As a result,bin/fm-control.sh <id> interrupt|exitrefuses the task. The verification doc confirms this: 'the tmux control fake reads a Prime pane as ambiguous and refuses lifecycle verbs'. So an operator on the default backend can spawn a Prime crewmate that the control plane cannot interrupt or stop. The verify plan requires tmux liveness only for secondmate-capable adapters, so this does not contradict the plan. It is a product decision: either refuse Prime spawns on non-Herdr backends until tmux is verified, or verify and addprime-agentto the tmux classifier.🔧 Fix applied.
1 warning still open:
bin/fm-spawn.sh:1398- The fix round added a herdr-only refusal for Prime, but onlybin/fm-spawn.shchecks it.fm-control.shreaches that check after it has already stopped the running agent. Reachable path: a crewmate runs on the default tmux backend withharness=claude. The operator runsbin/fm-control.sh <id> relaunch --harness prime --note ....resolve_relaunch_profileaccepts it, becausefm_control_harness_supported primeandfm_control_harness_supports_kind prime shipboth pass. Thendo_relaunchrunssafe_checkpointanddo_exit, which stops the claude worker. Next,fm-spawn.sh --relaunchtakesBACKEND=tmuxfrom meta and exits with "prime is verified on the herdr backend only". fm-control then dies with "the replacement agent ... could not be launched on prime". The task has no running worker. This breaks the invariant stated atbin/fm-control.sh:658-663: a launch that must be refused is refused before anything stops.tests/fm-control-relaunch.test.sh:741already covers this for the task-kind boundary. Fix: move the backend boundary into the shared capability table inbin/fm-control-lib.sh, for examplefm_control_harness_supports_backend <harness> <backend>. Call it fromresolve_relaunch_profilebefore the stop, using the recorded$BACKEND, and from thebin/fm-spawn.shrefusal. Add a relaunch test liketest_secondmate_relaunch_onto_a_crewmate_only_adapter_refuses_before_stopthat proves the tmux agent is still running after the refusal.🔧 Fix applied.
✅ Re-checked - no issues remain.
tests/fm-lint.test.sh- The baseline command exits 1 because tests/fm-lint.test.sh reports 'not ok - changed-mode lint run failed'. It is a lint failure on the changed files, not a Prime behavior failure. This test step may not run linters, so the lint phase or CI must find and fix the specific lint error before merge.prime-agent list --jsonreports 0 active sessionsbin/fm-test-run.sh --changed --exclude-family real-herdr-gatedFM_PRIME_HERDR_LIVE=1 HERDR_LAB_HELPER=bin/fm-herdr-lab.sh tests/fm-prime-herdr-live-e2e.test.sh(real prime-agent 0.9.4, real herdr 0.9.0, openrouter/moonshotai/kimi-k2.6)prime-agent -p --mode json --no-session [--no-skills] --model openrouter/moonshotai/kimi-k2.6 'Reply with the single word OK.'from $HOME, comparing prompt tokensprime-agent list --jsonandprime-agent list --all --jsonto check the 13 Sep probe sessionstests/fm-prime-harness.test.shtests/fm-control-relaunch.test.sh(includes test_relaunch_onto_prime_on_a_non_herdr_backend_refuses_before_stop)bin/fm-test-run.sh --changed --exclude-family real-herdr-gatedrerun, which identified the tests/fm-lint.test.sh failureherdr session listandpgrep -fl 'prime-agent|kernel-venv'to confirm lab teardown and no leftover workers🔧 Fix applied.
1 error still open:
tests/fm-control-relaunch.test.shcovered it. Run the relaunch on a host with tmux…bin/fm-test-run.sh --changed --exclude-family real-herdr-gatedFM_PRIME_HERDR_LIVE=1 HERDR_LAB_HELPER=bin/fm-herdr-lab.sh tests/fm-prime-herdr-live-e2e.test.sh(real prime-agent, real herdr lab session, openrouter/moonshotai/kimi-k2.6)prime-agent -p --mode json --no-session [--no-skills] --model openrouter/moonshotai/kimi-k2.6 'Reply with the single word OK.'from the firstmate worktree with 480 skills in ~/.agents/skillsRealbin/fm-spawn.sh <id> <project> prime --mode no-mistakes --yolo off --backend tmux|zellijwith isolated FM_HOME on a host without tmuxprime-agent list --all --json | jqfiltered to sessions created 2026-09-13tests/fm-prime-harness.test.shtests/fm-control-relaunch.test.sh(test_relaunch_onto_prime_on_a_non_herdr_backend_refuses_before_stop)tests/fm-busy-adapter-wiring.test.sh(Prime extension cases)tests/fm-control.test.sh(Prime control table)Rerun of baselinebin/fm-test-run.sh --changed --exclude-family real-herdr-gated(partial: 27 files finished, all exit 0 including tests/fm-lint.test.sh)✅ **Document** - passed
✅ No issues found.
🔧 Fix applied.
1 warning still open:
✅ **Push** - passed
✅ No issues found.