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: just craftos-exec '<lua>' 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
safe headless exec recipes 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:
- Recipe split. The old
just craftos(TrapOS dev mounts + persistent.craftos/) is renamedjust trapos. A newjust craftoslaunches a fresh, mount-less CraftOS-PC under.craftos-vanilla/. Ajust trapos-installrecipe exercises the real ccpm bootstrap on an ephemeral state to validate the install path end-to-end. - 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 safe exec flavors:
-
just trapos-exec '<lua>'— probe against the TrapOS dev environment. Mounts of/apis,/programs,/servers,/startup,/tests, and the repo root at/traposare live, sorequire('/apis/eventloop')and friends work against the current branch. Use this when the question involves repo code. -
just craftos-exec '<lua>'— 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.lua→ccpm update→ccpm install trapos) on a fresh ephemeral state. This is the probe to run when changing anything in the install path itself.
Conventions:
- Prefer the safe exec recipes over raw
--headless --exec. They wrap snippets withxpcall, callos.shutdown()on success or Lua error, and useTRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS(default10) as a host watchdog for true hangs. - Keep snippets minimal and side-effect-free. If the probe reveals a fact worth defending,
add a
libtestcase undertests/— 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
luacheckbut fail in-game. - A named pattern (
just trapos-exec '<lua>'/just craftos-exec '<lua>') shows up inCLAUDE.mdanddocs/install-craftos-pc.md, so contributors and agents reach for it without rediscovery. .craftos-vanilla/is added to.gitignorealongside.craftos/.just trapos-installis not part ofjust ci: it is network-dependent and slower thanjust test. Run it manually when touchinginstall-ccpm.luaor ccpm package descriptors.