Expand description
The tool contract (ADR-0005 §1, ADR-0022): the operations an agent, CI
or a person runs on a game, each a library function with a typed input
and output that serde reads and writes and JSON schemas describe. The
CLI (shuyi <op> [--json]) is one surface over them; the MCP server
(shuyi mcp, crate::mcp) is another, where each is a tool and a
session keeps one game running between calls.
| Op | Does | Module |
|---|---|---|
new <dir> | a new game from the engine’s template, templates/shuyi-default, its parts picked by the answers (--template grid, --answers, --set) | new |
check [--baked] | every error of every validator of the game’s content; with --baked, every way its pack differs from its sources | check |
check --target <id> | whether the game’s frame, text and controls fit a target | check, target |
lint | the game’s code: check-keys, check-text and the rules crate’s fence, each finding with file and line | lint |
modules | the catalog by concern, the modules the game’s engine builds, and the ones the game has on | modules |
add <module> | a module turned on: its feature of shuyi in Cargo.toml, its skill copied, what it is for, an alternative already on | add |
run | plays a key script headless: the top screen, the scene, events, sounds; with --perf, the frames’ times | run, perf |
scene | the scene or stage on screen after a script; with --path one value of its data, with --shape its shape | run |
replay <record> | a state hash per step, and the first step where two runs differ | replay |
playtest | the game’s named bots each play K tries on every core, timed and judged against its bands (none: a plain bot run); each try’s commands and record for replay, each bot’s outcomes counted and the spread of its numbers | playtest |
autobalance | the game’s knobs change a stage until its named bots land in their bands: the changes, the reports before and after; with --apply, the stage written | autobalance |
import <file> | a file read through the format registry, or its errors | import |
bake [--target <id>] | the game’s sources baked into one pack: sizes and times | bake |
export <target> | the target’s check, then the game built and packaged for it: a zip, a tar.gz, an .app or a web folder, with NOTICES.txt, export-report.json and exposure-report.json | export |
doctor | the toolchain: what is missing and how to install it | doctor |
explain [<code>] | every problem code, or one code’s page | explain |
attach <host:port> | a running debug build over the live link: steps played as a player’s input, then its screens, frame, log and window’s picture | attach |
Every answer is an Answer: the contract’s VERSION, the
operation, whether it passed, its result or the error that stopped it,
and its limits, what it could not determine (“no scene: the top
screen is no stage”). An error carries a problem code and a help line
(codes), and the code’s class sets the exit code: 0 passed, 1
failed, 2 wrong arguments, 3 fix the setup, then run it again.
The MCP server’s session tools (start, step, scene, frame_png,
events, perf, reset, stop; Op::SESSION) answer the same way.
The schemas of every input and answer are generated from these types
(schemas) and checked in under crates/cli/schemas/. A test fails
when they change and VERSION doesn’t.
Modules§
- add
add <module>: a module of the game’s engine turned on (ADR-0009 §6). It:- attach
attach: a build that is already running, reached over the live link (ADR-0047) instead of a game started headless. It needs no project: the build is a debug build of a game with its backend’slinkfeature, started withSHUYI_LINK=<port>, and its log’s lineshuyi link: listening on <address>, token <token>gives the address and the token.- autobalance
autobalance: the game’s knobs change one of its stages until each of its named bots (its entrants) succeeds as often as its checks’ bands want (shuyi_core::autobalance_by). The bots never change, only the stage. The game gives the plan (GameTools::autobalance_plan): its entrants and checks, asplaytesthas them, and the stage the search may change, with its knobs (Tunable). This runs the search, each setting’s tries played on every core (crate::pool) and judged once in seed order, so what it finds never depends on the thread count. It stops at the budget of evaluations or the time limit with the best setting seen, says the changes in the knobs’ words and, withapply, has the game write the changed stage. The answer passes when every rate is in its band.- bake
bake [--target <id>] [--out <file>] [--sheet <file>]: the game’s sources baked into one pack (.shuyipak, ADR-0023), with what went in, the sizes, and how long baking and loading took. A source with errors is refused, with every error.check --bakeduses the same bake to prove the pack equal to its sources (check_baked).- check
check [--baked]: the game loads all its content through every validator it has, and the answer lists every error found, each with its file, line and message. With--baked, the game’s sources are baked into a pack too, and every asset read from the pack must equal the one read from its source (bake::check_baked). Once the content loads without errors, the game’s text is checked against its font atlas (GameTools::font_atlas,shuyi_assets::font::undrawn): a character the atlas can’t draw is an error. It passes when there are no errors.- cli
- The contract on the command line:
shuyi <op> [args] [--json]. Each op’s arguments become its input, its answer is printed for people or, with--json, as one JSON document (Answer::to_json). An error carries a problem code (codes), and the exit code is 0 if it passed, 1 if not, 2 for wrong arguments (SH0nnn), and 3 for a setup to fix before running it again (SH1nnn: no project, a project file that lacks what it needs, the toolchain). - codes
- Problem codes (ADR-0028): every error the contract gives carries a
stable code,
SHand four digits, whose first digit is its class, and the class sets the exit code. Each code has a row here, with a help line, and a page incrates/cli/errors/thatshuyi explain <code>prints. - doctor
doctor: checks the toolchain a game on the engine builds with: Rust and Cargo, rustup’s targets, MSYS2’s linker andobjcopyon the Windows GNU toolchain (AGENTS.md), on Linux the C linker,pkg-configand the system libraries the backend links and opens, and the web target. Each check says what it found and, if it failed, how to fix it (its help): on Linux, the install command for the distribution’s package manager (/etc/os-release), andscripts/setup-linux.sh, which installs the same list. It passes when every check does; when one fails, it answerscodes::TOOLCHAINand exits 3.- explain
explain [<code>]: every problem code, or one code’s page (codes). It needs no project, likedoctorandschema, and is how an agent or a person learns what an error’s code means and how to fix it (shuyi explain SH2003, asrustc --explain E0277).- export
export <target> [--out <dir>] [--release] [--run] [--without <feature>]: the game checked against the target (check --targetwith the target’s profile: thedesktopone forwindows,linuxandmacos), refused on any error, then built and packaged by the target’s exporter (crate::export). The package goes in--out(from the game’s folder;dist/export/<target>without it) withexport-report.json, which holds this answer’s result: the target, the version, the sizes, the check’s warnings, the signing and, with--release, the debug file kept beside the package. The final package is read back intoexposure-report.json, and refused if it breaks the game’sdisclosurepart (crate::export::disclosure). With--run, the package is run after that.- import
import <file> [--kind K] [--print]: a file read through the format registry (ADR-0019) as every kind whose formats know it, with a short summary of what was read, the asset itself with--print, or every error with its file and line.- lint
lint: everything wrong with the shape of the game’s code, in one answer, each finding with its file, its line and what to do (ADR-0005 §1):- modules
modules: the catalog by concern (ADR-0009 §6), as the engine the game builds with has it, and which modules the game has on.- new
new <dir>: a new game indir, from the engine’s template,templates/shuyi-default, made of parts (ADR-0013 §3,crate::template). It is embedded in theshuyibinary, sonewneeds no checkout of the engine.- perf
- Perf traces as the contract hands them to agents (ADR-0046 §7): the
frames’ records a session kept, read as a stream (
PerfRead), summed up (summary), and written as JSON lines (lines). - playtest
playtest: the game’s named bots (its entrants) each play its stage K times from seedsseed,seed + 1, …, the game measures every try, and its checks say per bot whether it succeeded as often as wanted (shuyi_core::bots::playtest). The game gives the plan (GameTools::playtest_plan): its stages, its entrants and their groups, its checks and how one try is played. This plays the tries on every core (crate::pool), times them, and judges them once in seed order, so the report never depends on the thread count. The answer passes unless a rate fell under its floor.- replay
replay: a record of a game re-run by the game’s own rules, with a state hash per step (shuyi_core::state_hash). One record is run twice, which finds luck or state that a run doesn’t own; two records are run side by side. The answer says the first step where the two runs’ hashes differ, and passes if there is none.- run
runandscene: the game started headless as the game’s options say, a script of keys, controller buttons, actions by name and waits played, and some frames more.runanswers with the top screen, the frame as text, the scene, what happened, the sounds asked for, the game’s log and its modules;scenewith the scene and the log. With--perf,runalso measures each frame and answers a summary of the times, and with--perf-outwrites every kept frame as a JSON line (super::perf); where the heap is counted by memory tag, it takes a heap snapshot before the script and one after the last frame, and answers what held the heap and what grew. With--session, the game starts from a session record instead (shuyi_platform::session), played to its end or to the first frame this build plays differently, and the script goes on from there.- session
- A game running headless, for the operations that play it (
run,scene) and the MCP server’s session (crate::mcp):Session, which any game gives as aHeadlessover itsHarness. - target
check --target <id>: whether the game fits a target (ADR-0008 §1), by the target’s profile and the game’s setting for it inshuyi.ron(TargetSetting). Five checks for now:
Structs§
- Answer
- What an operation answers.
- Problem
- A problem in a file: what a validator found, with where.
- Schema
File - One schema file: its name (
run.input.json) and its text. - Version
Line - One line of
schemas/versions.json: a version and its schemas’ fingerprint.
Enums§
- Op
- An operation of the contract.
Constants§
- VERSION
- The contract’s version, in every answer. Raise it whenever an input
or an answer changes shape (the schemas’ test says when), and add the
new schemas’ fingerprint to
schemas/versions.json.
Functions§
- fingerprint
- The fingerprint of
files: a hash of their names and texts, whichschemas/versions.jsonkeeps for eachVERSION. - op_
schemas - The schemas of
op’s input and answer: as the CLI and the MCP tool of its name take it, or, ifsession, as the MCP server’s session tool does (namedsession.<op>;Op::SESSION). - schemas
- Every operation’s input and output schema, in
Op::ALL’s order, then the MCP server’s session tools’ (Op::SESSION), then the fileexportwrites beside its package.