This project now exposes a headless JSON interface intended for automation, scripted debugging, and agent-driven playtesting. The Bevy client remains the human-facing tool; app_headless is the machine-facing tool.
- let an agent inspect authoritative sim state without scraping UI text
- let an agent apply deterministic simulation commands in batch form
- let debugging and replay flows use the same structured data contract
List scenarios:
cargo run -p app_headless -- --list-scenarios --jsonObserve a scenario after advancing ticks:
cargo run -p app_headless -- --scenario first_slice --ticks 20 --jsonObserve a thinner summary-only payload:
cargo run -p app_headless -- --scenario first_slice --ticks 20 --json --json-profile summaryInspect a specific part from a save:
cargo run -p app_headless -- --load /tmp/three_d_systems_debug_save.json --inspect-part 12 --jsonRun a scripted batch and emit a per-step trace:
cargo run -p app_headless -- \
--scenario first_slice \
--command-file /tmp/agent-script.json \
--emit-trace /tmp/agent-trace.jsonl \
--json--json emits a top-level object with these fields:
ok: whether the run completed without a scripted or inspection errorerror: first user-level execution error, if anysource: scenario id or save path used to seed the runsteps: compact outcomes for scripted steps and convenience tick actionssummary: aggregated machine-readable world summaryinspect: optional detailed inspection for--inspect-partworld: the full validated save snapshot shape
--json-profile controls payload size:
summary: summary/checkpoints only, no top-level inspect or full world snapshotinspect: keep inspect data, omit the full world snapshotfull: current complete payload, including the validated world snapshot
summary includes:
tickstate_hashsizepartsobjectivecontaminationproduced_totalbuild_inventorypart_state_counts
inspect and scripted inspect_part steps include:
- the full
partstate - sim-owned
status port_links- filtered active
item_traces connected_power_partsconnected_item_parts
--command-file accepts either:
- a JSON array of steps
- an object of shape
{ "steps": [ ... ] }
Supported step types:
apply_commandtickuntil_victoryinspect_part
apply_command uses the serialized sim_core::Command shape. Example:
[
{
"type": "apply_command",
"command": {
"type": "place_part",
"def_id": "frame_block",
"origin": { "x": 1, "y": 1, "z": 1 },
"facing": "north"
}
},
{
"type": "apply_command",
"command": {
"type": "place_part",
"def_id": "wire",
"origin": { "x": 2, "y": 1, "z": 1 },
"facing": "north"
}
},
{
"type": "tick",
"ticks": 8
},
{
"type": "inspect_part",
"part_id": 1
}
]Supported command variants:
place_partremove_partrotate_partset_machine_enabledset_machine_recipeset_build_recipe
--emit-trace <path> writes newline-delimited JSON records.
Each record captures:
stage:initial,step, orfinalstep_indexstepokerrorsummary- optional
inspection
This is intended for:
- agent training/evaluation traces
- regression debugging
- scripted scenario analysis without re-parsing terminal text
- The JSON interface is derived from authoritative sim reports, not Bevy-only state.
worldcan be large because it includes the full save snapshot.- Use
--json-profile summaryor--json-profile inspectwhen you want lighter automated tooling payloads. - Human-readable mode remains the default when
--jsonis omitted. - Script execution stops on the first failing step, but still returns the current world snapshot and failure metadata.