cc-libs/docs/adrs/adr-0012-headless-craftos-pc-as-hypothesis-probe.md

4.6 KiB

ADR 0012: Headless CraftOS-PC As The Canonical Hypothesis Probe

Status

Accepted

Date

2026-06-09

Context

ADR-0005 made CraftOS-PC the local harness and ADR-0007 / ADR-0008 / ADR-0009 wired it into the test suite via just test. That work focused on the test path. Headless CraftOS-PC is also a cheap, deterministic interactive tool: craftos --headless --exec '<lua>; os.shutdown()' boots the emulator, runs an arbitrary Lua snippet against the real CC:Tweaked ROM, prints output to stdout, and exits in well under a second. Humans and LLM agents can use it to verify hypotheses about CC:Tweaked behavior before writing code or tests — "does os.epoch('utc') return ms?", "does my new API factory require cleanly?", "does fs.exists follow symlinks inside --mount-ro?".

Today this usage was implicit: the harness existed, but no document framed --headless --exec '...' as the recommended first move when an agent is unsure about CC:Tweaked behavior. The original recipe was also named just craftos even though it mounted the entire TrapOS dev environment — so probes against it were never against vanilla CC:Tweaked, even when the agent thought they were.

Two concrete changes triggered this ADR:

  1. Recipe split. The old just craftos (TrapOS dev mounts + persistent .craftos/) is renamed just trapos. A new just craftos launches a fresh, mount-less CraftOS-PC under .craftos-vanilla/. A just trapos-install recipe exercises the real ccpm bootstrap on an ephemeral state to validate the install path end-to-end.
  2. Explicit guidance. Agents working in this repo should reach for a headless probe the moment they catch themselves guessing about CC:Tweaked behavior, instead of speculating or committing changes that only run luacheck.

Decision

Frame headless CraftOS-PC as the canonical hypothesis-probe pattern, with two flavors:

  • just trapos --headless --exec '<lua>; os.shutdown()' — probe against the TrapOS dev environment. Mounts of /apis, /programs, /servers, /startup, /tests, and the repo root at /trapos are live, so require('/apis/eventloop') and friends work against the current branch. Use this when the question involves repo code.

  • just craftos --headless --exec '<lua>; os.shutdown()' — probe against vanilla CraftOS-PC. No mounts, no startup scripts. Use this when the question is purely about CC:Tweaked behavior and TrapOS files would be a distraction, or to confirm a behavior is upstream rather than something the dev env layered on.

  • just trapos-install — drive the full real install (install-ccpm.luaccpm updateccpm install trapos) on a fresh ephemeral state. This is the probe to run when changing anything in the install path itself.

Conventions:

  • Always terminate the snippet with os.shutdown(). The shell watchdog from ADR-0009 governs just test, not these recipes; a missing shutdown will hang until the user kills the process.
  • Keep snippets minimal and side-effect-free. If the probe reveals a fact worth defending, add a libtest case under tests/ — probes are not a substitute for committed tests.
  • LLM agents SHOULD prefer a quick headless probe over speculation when answering "does X work in CC:Tweaked?" or "does my refactor still load?". The cost is one extra emulator boot (~1s); the benefit is grounded answers instead of plausible-sounding ones.

Consequences

  • Higher CraftOS-PC invocation traffic during agent sessions; cheap enough that this is a good trade.
  • Faster convergence on correct fixes: agents stop committing speculative changes that pass luacheck but fail in-game.
  • A named pattern (--headless --exec '<lua>; os.shutdown()') shows up in CLAUDE.md and docs/install-craftos-pc.md, so contributors and agents reach for it without rediscovery.
  • .craftos-vanilla/ is added to .gitignore alongside .craftos/.
  • just trapos-install is not part of just ci: it is network-dependent and slower than just test. Run it manually when touching install-ccpm.lua or ccpm package descriptors.

Cross-references

  • ADR-0005 — CraftOS-PC as the local harness.
  • ADR-0007 — libtest for CraftOS tests.
  • ADR-0009 — layered test timeouts.
  • ADR-0010 — ccpm package manager (drives the just trapos-install flow).