8.5 KiB
ADR 0005: CraftOS-PC Harness, Periphemu Bootstrap, and Headless Probes
Status
Accepted
Date
2026-06-08
Context
This repository targets CC:Tweaked on Minecraft 1.21. The Lua we ship runs inside the ComputerCraft sandbox: it depends on os.pullEventRaw, peripheral, rednet, textutils.serializeJSON, modem channels, and CC-specific globals. Standard Lua cannot execute this code as-is, so a normal local test harness was never a serious option.
Contributors have been running the code in two places:
- In-game on a real Minecraft server, which is slow to iterate on.
- In CraftOS-PC (https://www.craftos-pc.cc/), a desktop emulator that ships the same ROM/BIOS as CC:Tweaked, supports modem peripherals via
periphemu, and can run fully headless (--cli --headless --script <file>).
CraftOS-PC was the de facto local harness for months but lived only as a single line in AGENTS.md. There was no install guide, no minimum version, and just install did not check the binary was present. Two related concerns emerged on top of that:
startup/servers.luahistorically calledperiphemu.createfour times on computer 0 (a top modem, twocomputerpeers at ids 1 and 2 both labelledTrap, and a router peer at id 10). In CraftOS-PC GUI mode this opened four windows on every launch, and the duplicateTraplabel plus persistent per-id state across versions caused recurring confusion.- Headless CraftOS-PC is also a cheap, deterministic interactive tool: it boots the emulator, runs an arbitrary Lua snippet against the real CC:Tweaked ROM, prints output, and exits in well under a second. Humans and agents can use it to verify hypotheses about CC:Tweaked behavior before writing code or tests. That usage was implicit; no document framed headless exec recipes as the recommended first move when an agent is unsure about CC:Tweaked behavior.
Decision
1. CraftOS-PC as a first-class local dev dependency
- Minimum version
v2.8.3— recent enough to have the current CC:Tweaked ROM, old enough that contributors already on a 2.8.x build will not be forced to upgrade again. - Documented install in
docs/install-craftos-pc.md, with a SHA-256-verified macOS flow and pointers to the official Windows/Linux artifacts. - Documented upstream navigation in
docs/craftos_pc_glossary.md, covering CLI flags, mounts,periphemu, save data, and troubleshooting pages. - Verified by
just installviacheck-install, which checkscraftos,jq,luacheck, andopenssl.check-craftosrunscraftos --versionand requires v2.8.3 or newer. Failure prints a one-line pointer to the install guide. - Repository-local TrapOS launch.
just traposruns CraftOS-PC with--directory .craftos, keeps the macOS--rom /Applications/CraftOS-PC.app/Contents/Resourcesworkaround, mounts the repository root read-only at/trapos, and mounts each top-level source directory read-only at its ComputerCraft root path. - Vanilla launch.
just craftoslaunches CraftOS-PC under.craftos-vanilla/with no mounts and no startup, for probes that should not see TrapOS files and for thejust trapos-installend-to-end install verification. just ciis the local verification entry point. It runscheck-craftos,check, andtest. Local Git hooks are installed byjust install; see ADR-0011 for the commit/push split.
The existing AGENTS.md constraint ("Do not run Lua locally or add a test harness unless asked") is reframed rather than removed: there is still no standalone Lua harness, and we are not adding a Busted-style test runner. The harness is CraftOS-PC, invoked deliberately.
2. Periphemu bootstrap stays minimal
startup/servers.lua attaches only a top modem under periphemu:
if periphemu then
periphemu.create('top', 'modem');
end
Extra emulated computers are spawned manually from the CraftOS-PC shell when actually needed (e.g. periphemu create 10 computer to bring up a router peer for cross-VM testing). The pattern is documented in docs/periphemu.md. The if periphemu then guard is preserved so in-game behavior is unchanged.
3. Headless probes as the canonical hypothesis pattern
Two safe-exec recipes wrap raw --headless --exec with xpcall, call os.shutdown() on success or Lua error, and use TRAP_CCLIBS_HEADLESS_TIMEOUT_SECONDS (default 10) as a host watchdog:
-
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. - Keep snippets minimal and side-effect-free. If a 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
- Contributors must install CraftOS-PC before
just installsucceeds. The install guide makes this a 4-step copy/paste on macOS. - Headless tests live under
tests/and are driven byjust test. See ADR-0007 for the runner and timeout layering. - The macOS install symlinks the binary into
/usr/local/bin, which makes CraftOS-PC unable to auto-discover the ROM that ships inside the.appbundle (Could not mount ROM). Thetest:recipe works around this by passing--rom /Applications/CraftOS-PC.app/Contents/Resourceson Darwin. Linux (AppImage) and Windows (installer) auto-discover correctly. just traposuses repository-local save data under.craftos/config/and.craftos/computer/. This keeps emulator state out of~/Library/Application Support/CraftOS-PCduring repository work and keeps repo files visible through read-only mounts instead of copying them into the VM save.just replis a human-only interactive wrapper aroundjust trapos --cli; automation and LLM agents must usejust trapos-exec '<lua>'orjust craftos-exec '<lua>'instead.craftos(GUI) now opens a single unlabelledComputer 0window with a top modem attached. Cross-machine testing requires an explicitperiphemu createcall from the shell rather than being implicit on boot — one extra command when you need a peer, no surprise windows or persisted ghost VMs..craftos-vanilla/is in.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.- Higher CraftOS-PC invocation traffic during agent sessions; cheap enough that this is a good trade.
- The harness version becomes a project-level concern. When CC:Tweaked ships breaking changes that require a newer CraftOS-PC build, we bump the minimum version in
docs/install-craftos-pc.mdandcheck-craftoskeeps contributors honest. - No CI integration yet. Running CraftOS-PC headless in GitHub Actions is feasible (the AppImage works on Ubuntu runners) but is out of scope; the contract is local-only for now.
Future Work
- API-loading smoke test. Extend
tests/with a script thatrequires/apis/eventloop,/apis/net,/apis/libtest, and the router, asserting the wiring loads without errors. - CI. Run
just teston push using the Linux AppImage. - Pinned ROM. Point CraftOS-PC at a vendored ROM via
--romif we ever need to test against a specific in-game version. - If
tests/grows a multi-VM scenario, drive peer creation from the test script itself (eachtests/*.luaalready owns its setup) rather than re-adding peers tostartup/servers.lua.