# Chessistics automation harness Drive a running Chessistics build via file-based IPC, so an AI agent (or a scripted test) can take screenshots, inject inputs, and read game state without a human in the loop. ## How it works - Launch Godot with `--automation=`. The game activates an `AutomationHarness` node that polls `/inbox/` each frame. - Send commands as JSON files; the game writes results to `/outbox/` and screenshots to `/screens/`. - A handshake file `/ready.json` is written on startup. Without the flag, the harness is not instantiated — zero runtime overhead and zero behavior change for normal play. ## Quick start ```bash # From repo root python tools/automation/smoke.py # end-to-end smoke test python tools/automation/run_game.py # interactive REPL ``` Requirements: - Python 3.10+ (stdlib only) - Godot 4.6 mono build at `C:\Apps\godot\Godot_v4.6.2-stable_mono_win64_console.exe` (override with `Harness(godot_exe=...)` or edit the default in `harness.py`). - A compiled build: run `dotnet build Chessistics.csproj` first. ## Python API ```python from tools.automation.harness import Harness with Harness.launch() as h: h.load_mission("campaign_01", 0) state = h.state() # full snapshot as dict h.screenshot("before") # → .automation_runs//screens/before.png h.place("Rook", (0, 0), (0, 3)) # place a piece h.step() # one simulation tick (auto-waits for animation) h.screenshot("after") h.set_speed(0.1); h.play() # auto-run fast ``` Methods on `Harness`: - `screenshot(name) -> Path` - `state() -> dict` — full snapshot + `animating` flag - `select(kind)` — e.g. `"Rook"`, `"Knight"` - `place(kind, start, end, level=1)` — returns `{placed, pieceId, reason}` - `click_cell(col, row, button="left"|"right")` - `key(name)` — `"Space"` (play/pause), `"Escape"` (cancel) - `play()` / `pause()` / `step()` / `wait_idle()` - `set_speed(interval_seconds)` — auto-step interval - `load_mission(campaign, missionIndex=0)` - `back_to_menu()` / `quit()` Every non-query command auto-waits for `EventAnimator.IsAnimating == false` before returning, so consecutive calls see a fully-settled state. ## JSON protocol Inbox: `{ "id": "", "cmd": "...", "args": {...} }` Outbox: `{ "id": "", "ok": true, "result": {...} }` or `{ "id": "", "ok": false, "error": "..." }` See the `cmd` table in `Scripts/Automation/CommandDispatcher.cs` for the complete list. ## Output locations - `.automation_runs//ready.json` — handshake - `.automation_runs//inbox/`, `outbox/` — command queue - `.automation_runs//screens/*.png` — 1280x720 PNGs `.automation_runs/` is a good candidate for `.gitignore` (not added here automatically — add it manually if needed). ## Troubleshooting - **Godot exits before ready.json** — build probably didn't compile, or the `--path` arg is wrong. Run `dotnet build Chessistics.csproj` and check stderr from the harness. - **Screenshot is all black** — `--headless` was passed; the harness needs a real rendering context. Don't use `--headless` with automation. - **Command times out** — an animation may be stuck; check the Godot console log for errors. ## Architecture notes The harness sits behind a thin facade (`AutomationFacade`) that the dispatcher uses. It never reaches into engine internals — only calls existing public surfaces on `GameSim`, `InputMapper`, `EventAnimator`, `ControlBar`, `PieceStockPanel`. The black-box simulation separation stays intact.