Mode: Pi extension background wake.
When this session owns supervision and away mode is not active:
- Drain first with
bin/fm-wake-drain.sh. - Confirm the Pi primary auto-loaded both project extensions (plain
pi, after approving project trust once per clone); if not, restart with-e __FM_PI_TURNEND_EXT__ -e __FM_PI_EXT__as a trust-free fallback. - Arm supervision with the
fm_watch_arm_pitool. Use/fm-watch-arm-pionly as a human-entered fallback. Never runbin/fm-watch-arm.shthrough Pi's bash tool because that foreground arm can wedge the agent and bypasses extension-owned cleanup. - The extension starts
bin/fm-watch-arm.sh --restart, keeps the child attached to the live Pi process, and sends a follow-up user message when the child exits with an actionable watcher reason. - If the extension says the watcher is already healthy, do not start another cycle.
- If the extension reports a watcher failure, drain queued wakes, inspect the failure text, and restart Pi with both extensions loaded if needed.
- Never use shell
&for watcher supervision. The arm mechanism above is extension-owned, not a model tool call, but a manual recovery probe that backgrounds, pipes, or bundles the arm is denied automatically by the PreToolUse seatbelt (bin/fm-arm-pretool-check.sh, wired into the turn-end guard extension at__FM_PI_TURNEND_EXT__).
The turn-end guard extension lives at __FM_PI_TURNEND_EXT__.
The watcher extension lives at __FM_PI_EXT__.
Both are tracked, project-local .pi/extensions/*.ts files that Pi auto-discovers once the project is trusted; bin/fm-session-start.sh reports when the running Pi session has not loaded both required extensions.
Verification on 2026-07-09 used Pi 0.80.5, an isolated PI_CODING_AGENT_DIR, an isolated FM_HOME, and the dedicated tmux socket fm-pi-q6-lab.
The command Use the fm_watch_arm_pi custom tool now. Do not use bash. rendered watcher: started Pi extension arm child 1, then the model returned DONE without the prior result.content.filter(...) crash.
The extension tool returned Pi's required text content plus structured details and used Type.Object({}) for its parameter schema.
The human command /fm-watch-arm-pi notified through ctx.ui.notify(...) and returned no value.
The clean-exit probe ran /quit, printed PI_EXIT=0, and confirmed that both the attached arm process and watcher child were gone.
That cleanup is owned by a one-shot process exit listener because Pi 0.80.5 did not reliably emit session_shutdown for /quit; the listener is removed when session_shutdown does run.
Command run for the complete interactive regression: FM_PI_LIVE_E2E=1 tests/fm-pi-primary-live-e2e.test.sh.
Observed output: ok - Pi 0.80.5 live E2E rendered the tool, guarded once, woke, re-armed, and cleaned up on exit.
Command run for the installed-type contract: tests/fm-pi-primary-types.test.sh.
Observed output: ok - Pi primary extensions pass strict no-emit typecheck against Pi 0.80.5.