Skip to content

fix(bin): register freshly spawned pi workers as Herdr agents - #3

Merged
witt3rd merged 2 commits into
mainfrom
fm/herdr-pi-agent-fix
Sep 29, 2026
Merged

witt3rd merged 2 commits into
mainfrom
fm/herdr-pi-agent-fix

Conversation

@witt3rd

@witt3rd witt3rd commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Intent

Everything of this Firstmate fleet now runs on the Herdr backend (the captain moved it off tmux on 2026-09-29). Freshly spawned pi worker panes are not registered with Herdr as agents: herdr pane list shows no agent and agent_status "unknown" for them, while relaunched pi panes and the primary pi pane register as "pi". Seen on 4 of 6 new Herdr workers in the Spire caretaker's home and on the animus kunchenguid#9 worker. Consequence: fm-send reports the live worker as exited and rings no doorbell, so steers sit unread until someone types into the pane by hand, and watcher liveness/stale checks may misread these panes. The Herdr pi integration is installed and current (v9) at ~/.pi/agent/extensions/herdr-agent-state.ts. Make freshly spawned pi workers on Herdr register as agents so steering and monitoring work.

#3 doesn't pass CI!
(That PR is this branch's PR. Its fork CI checks "Behavior portable serial 2" and "Behavior portable serial 4" fail in tests/fm-calm-pi-extension.test.sh and tests/fm-pi-branch-extension.test.sh because CI installs the latest public Pi, 0.99.1, while the fleet runs Pi 0.87.1 and main last passed on 0.87.1. The PR must be green before it is merged.)

What Changed

  • On Herdr, fm-spawn.sh now types a launch line from the new fm_backend_herdr_launch_line in bin/backends/herdr.sh. The line sources the staged launch file inside a job-controlled /bin/sh -c 'set -m; ...', so the agent gets its own process group and takes the terminal foreground. Herdr then registers the pane as an agent, and fm-send and the watchers see the worker as live. Other backends keep the . '<file>' line.
  • Adds a launch-line unit test and a live e2e test for pi launch registration, registers both in fm-test-run.sh, updates the existing Herdr remote tests and fixture for the new launch line, and documents the behavior in docs/herdr-backend.md, docs/configuration.md and docs/verification/runtime-backends.md.
  • Unrelated to the Herdr fix (separate commit 7491318, CI only): in .github/workflows/ci.yml, both jobs that install Pi now pin @earendil-works/pi-coding-agent@0.87.1. Unpinned CI installed Pi 0.99.1, which broke fm-calm-pi-extension and fm-pi-branch-extension in the portable serial shards.

Risk Assessment

✅ Low: On Herdr, the typed launch line now sources the staged launch file inside a job-controlled /bin/sh, and this is applied only to that backend. It is quoted correctly and covered by pty and live tests. CI pins Pi to 0.87.1, which addresses the stated CI failures. The one behavior change is that launch commands now run under POSIX sh on Herdr, and the change documents this.

Testing

I ran the launch-line unit test and the live end-to-end test against real Herdr 0.9.2 and Pi 0.87.1. In the live test, a Pi started through the new launch line registered as "pi" even when the pane shell had no job control. The counterfactual, a plain sourced launch, stayed unregistered with the shell in the foreground group. Both tests passed. The process-group scenario was covered only by the unit test, which is not live. The CI Pi-version pinning was not driven live, because it only takes effect on GitHub Actions.

  • Live validation: ✅ go - 2 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Fresh pi worker launched via the Herdr launch line registers as agent 'pi' under real Herdr, with no job control in the pane shell ✅ pass live tests/fm-herdr-pi-launch-registration-live-e2e.test.sh; run.log
Adversarial: the old sourced launch shape stays unregistered under Herdr (counterfactual), so the launch line is what fixes it ✅ pass live live e2e counterfactual output in run.log: foreground bash plus pi
Launch line puts the agent in its own foreground process group and the terminal returns to the shell afterward ⏸️ untested no The prior payload only ran tests/fm-backend-herdr-launch-line.test.sh, which uses real shell processes but not the live Herdr product, so it did not establish a live result for this scenario.
CI on Pi 0.99.1 goes green (the two extension tests that were failing) ⏸️ untested no Only Pi 0.87.1 is installed locally, and I could not install 0.99.1 system-wide. The result depends on GitHub Actions running the workflow change in .github/workflows/ci.yml.
Evidence: test run transcript

Source: test run transcript

== tests/fm-backend-herdr-launch-line.test.sh
ok - herdr launch line: from a shell without job control, the agent runs as its own foreground process group and the terminal returns to the shell
ok - herdr launch line counterfactual: a plain '. <file>' agent shares the pane shell's group, the shape Herdr never registers
rc=0
== tests/fm-herdr-pi-launch-registration-live-e2e.test.sh
# pi 0.87.1 under herdr 0.9.2: launch-line pane registered pi, foreground [{"name":"pi","argv0":null}]
ok - real herdr 0.9.2 + pi 0.87.1: a Pi started through the Herdr launch line registers as an agent even when the pane shell has no job control
# herdr 0.9.2 still leaves a sourced, continuously redrawing Pi unregistered under a shell without job control (foreground [{"name":"bash","argv0":null},{"name":"pi","argv0":null}]): the launch line is what registers it
rc=0

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 2 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Fresh pi worker launched via the Herdr launch line registers as agent 'pi' under real Herdr, with no job control in the pane shell ✅ pass live tests/fm-herdr-pi-launch-registration-live-e2e.test.sh; run.log
Adversarial: the old sourced launch shape stays unregistered under Herdr (counterfactual), so the launch line is what fixes it ✅ pass live live e2e counterfactual output in run.log: foreground bash plus pi
Launch line puts the agent in its own foreground process group and the terminal returns to the shell afterward ⏸️ untested no The prior payload only ran tests/fm-backend-herdr-launch-line.test.sh, which uses real shell processes but not the live Herdr product, so it did not establish a live result for this scenario.
CI on Pi 0.99.1 goes green (the two extension tests that were failing) ⏸️ untested no Only Pi 0.87.1 is installed locally, and I could not install 0.99.1 system-wide. The result depends on GitHub Actions running the workflow change in .github/workflows/ci.yml.
  • bash tests/fm-backend-herdr-launch-line.test.sh
  • bash tests/fm-herdr-pi-launch-registration-live-e2e.test.sh (real herdr 0.9.2 and pi 0.87.1, in a lab session)
✅ **Document** - passed

✅ No issues found.

⚠️ **Lint** - 1 warning
  • ⚠️ linter found issues (exit code 1)
✅ **Push** - passed

✅ No issues found.

Herdr only probes a pane for an agent when its foreground process group
changes, or in a short window after the screen has been still. A pane
shell that sources the staged launch without job control (fish, or any
shell with monitor mode off) runs the agent inside the shell's own
process group, so a worker whose launch outlasts that window and then
keeps redrawing is never registered: the pane reads no agent, fm-send
treats the live worker as exited, and liveness reads misjudge it.

On Herdr, fm-spawn now types a line that sources the staged launch file
inside a job-controlled /bin/sh, so the agent starts as its own
foreground process group and Herdr probes it immediately, whatever the
pane shell is. The terminal and the exit status return to the pane shell
when the agent exits.

Adds a portable pty regression for the process-group guarantee, a
token-free live guard against the real Herdr and Pi, the verification
record, and updates the Herdr fakes that parsed the old source line.
Unrelated to the Herdr launch fix in this branch. CI installed the latest
public Pi, which moved to 0.99.1, and its changed stock rendering fails
fm-calm-pi-extension and fm-pi-branch-extension. Pin CI to the Pi release
the fleet runs and these tests last passed on; checking compatibility with
the latest Pi is a separate follow-up.
@witt3rd
witt3rd merged commit c5d9107 into main Sep 29, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant