acpmux: ACPMUX_HARNESS_FIXTURE serves a capture fixture's harnesses and health
acpmux reads ACPMUX_HARNESS_FIXTURE at start. It names a JSON file of harness profiles and health rows, and the daemon serves those in place of what it would find on the host, so a screenshot rig's before and after builds show the same Settings > Agents > Harnesses data on any machine.
The ask, from Leo's standing order for the infra lane: "get the proper reasonable features in. Period." The concrete problem it fixes: live captures of a Harnesses change (cmux#26083) could not be matched. Each host listed its own harnesses, and the running daemon ignored a seeded harness-health.json as soon as it ran its own check.
What the variable does
The file looks like {"harnesses": {ID: HarnessProfile}, "health": [HarnessHealth]}. With the variable set:
- The catalog joins the fixture's harnesses in place of discovery (PATH,
~/.acpxand the cached ACP Registry). Profile files still join. _acpmux/harness/healthserves the fixture's rows as every check, includingrefresh,checkLatestandrescan. Nothing is probed, fetched or saved.- Every update path refuses: auto-update,
_acpmux/harness/update, the cached update plan and update prepare. - None of these run: launcher verification, live model lists (cached or probed), model probes of a fixture harness,
_acpmux/registryand_acpmux/harness/add. - The file is opened with
O_NOFOLLOW. If the variable is set but empty, or the file is missing or unparsable, the daemon refuses to start, so a capture can never silently show the host's harnesses.
Risk
Low. With the variable unset, every path runs as before. The one refactor is moving auto-default selection into pick_auto_default, and its behaviour is unchanged. A signed app passes only an allowlist of variables to its daemon (AcpmuxDaemonLauncher.signedInheritedKeys), so only DEV builds and hand-run daemons can receive this one. A session the person starts on a fixture harness still runs that profile's argv; the rig never opens one.
Evidence
- Rust: lib tests for the parser, the health service and catalog joining.
tests/harness_fixture.rsdrives the real daemon binary: harnesses, health with and without refresh, a refused update, a refused registry read, the fixture harness never started, no health copy saved, and an empty or missing fixture stopping the start. - Live rig, cmux#26083 (Settings > Agents > Harnesses). The same fixture file was used for both captures: Codex 0.3.1 ā 0.4.0 (npm), Claude Code 2.0.5 ā 2.0.9 (needs sudo) and GitHub Copilot 1.4.0 (current). Before is
e519622e(the merge's parent) and after isd65a93cf(the merge). Each capture ran with this change applied on top (refscapture-fixture/26083-beforeand-after). The rows match; the after adds the update cards cmux#26083 introduced.
Before (e519622e + fixture) | After (d65a93cf + fixture) |
|---|---|
![]() | ![]() |
![]() | ![]() |
Companion rig change (the capture state's harnessFixture field): manaflow-ai/cmuxterm-hq.
Agent session: agent session
š¤ Generated with Claude Code



