Command line
The gamewright command is the core: it checks, bakes, plays and verifies a pack, and serves the Director's tools. The Studio runs this same core for you, and every download of the Studio has the command beside it (installing says where). From a checkout of the source, run it as node core/src/cli/main.ts <command>. This page is the CLI's own help, so it always matches the code.
gamewright <command> [options]
new
gamewright new [--json] (--sample NAME | --starter TEMPLATE | --empty) [--name "Title"] DIR
Start a game in DIR, a folder that is new or empty: a sample as it is, a template's starter (the smallest game on it, playable at once, with its sample's look and sound), or nothing, for the Director's brief. The game is the person's, made now, its ids from its name (game.<slug>, brief.<slug>); --name defaults to the sample's name, or for a starter to DIR's. JSON: {ok, dir, game: {id, name, template}}.
new
gamewright new --list [--json]
The samples (name, title, template, description) and the templates (id, name, description, starter) a new game can start from.
validate
gamewright validate [--json] <pack>
Check a pack: file names, strict JSON, schemas, then the game as a whole (references, kits, events, brains, screens, builders, cues, expressions) and static analysis (obtainability, unreachable states). A game is checked with its template.
strings
gamewright strings [--json] [--locale CODE] <pack>
Every text a person reads, by its Locale key, with a Locale's translation: what a translation works from.
store
gamewright store [--json] [--out DIR] [--shots] [--timeout S] <pack>
The store page kit: page.md (what the game is, how to play, what a person can change, credits) and ai-disclosure.md (what AI made, from the documents' and files' own records, as itch.io and Steam ask), under <pack>/.gamewright/store. --shots draws cover.png (630x500, its poster) and screenshots/ (1920x1080, from its look Playtest) through the player.
analyze
gamewright analyze [--json] <pack>
The same checks, reporting what a player can obtain and which brain states are never reached.
bake
gamewright bake [--json] <pack>
Check, resolve and write the bundle the player runs, into <pack>/.gamewright/build/<hash12>/.
digest
gamewright digest [--json] [--seed S] <pack|bundle>
Bake if needed, then have the engine load the bundle and print its world digest.
sim
gamewright sim [--json] [--seed S] [--ticks N] [--tour F] [--replay F] [--trace F] [--record F]
[--asserts TEST] [--locale CODE] <pack|bundle>
Run the game headless in the engine; --asserts checks Playtest TEST's asserts where the run ends. --locale shows it in a language its Locales carry (here and below).
shot
gamewright shot [--json] --out F.png [--seed S] [--ticks N] [--at NAME] [--hour H] [--size WxH]
[--locale CODE] [--options F] [--sees KIND] <pack|bundle>
Render one frame (through tools/heavy.sh). --options draws it as a person with those options sees it (an Options file: captions, colour filter, text size); --sees as a person with that colour blindness does (protanopia, deuteranopia or tritanopia; here and below).
tour
gamewright tour [--json] --tour F [--out DIR] [--seed S] [--locale CODE] [--options F] [--sees KIND]
<pack|bundle>
Run a tour with its shots in the player (through tools/heavy.sh).
play
gamewright play [--seed S] [--level ID] [--at NAME] [--hour H] [--locale CODE] <pack|bundle>
Play the game in a window; --level starts in that Level or PlatformLevel, as a level select screen would.
verify
gamewright verify [--json] [--level L0|L1|L2|L3|L4|L5[,...]] [--seed S] [--judge-budget USD] <pack>
The verification ladder: L0 spec (validate), L1 boot (600 ticks twice, the same state hash, a clean log), L2 play (every Playtest through sim, with trace metrics), L3 frames (tour shots in the player, through tools/heavy.sh, with property checks), L4 judge (a vision model asked where the player, threats and goals are in L3's frames and what the player is to do; the Anthropic API with ANTHROPIC_API_KEY, else claude -p; costs money, at most --judge-budget, default $1), L5 web (every Playtest tour in headless Chromium on the web export, ending on the desktop's state hash). --level runs every rung up to the one named, but L4 only when named.
export
gamewright export [--json] --to linux|windows|macos|web [--out DIR] [--shots] <pack>
Bake the game and write it as one zip a person can hand on, named for it ("Ember Shore (Linux).zip"), into DIR (default: here): the player for that system with the game beside it, or for the web a folder any static host serves. The player is this version's, from GAMEWRIGHT_PLAYERS (a folder of player zips) or downloaded from gamewright.diy once and kept. macOS needs a Mac, for now. Beside it go its store page and AI disclosure; --shots draws its store pictures too (a few minutes, "<name> - store pictures"). JSON: {ok, to, zip, bytes, game: {id, name}, hash12, player}.
solve
gamewright solve [--json] [--level ID]... [--max-states N] <pack>
Prove a grid game's Levels solvable: print each one's witness (the shortest solution) and what the search saw.
reach
gamewright reach [--json] <pack>
Prove a platformer's levels completable: print each one's witness (inputs that reach the exit), the rooms a generator laid and how far the hero jumps.
fmt
gamewright fmt [--check] [--schemas <dir>]... <paths...>
Rewrite documents in canonical form (--check: only report).
hash
gamewright hash <file>
Print a document's content hash (sha256 over RFC 8785 JSON).
codegen
gamewright codegen [--check]
Regenerate TypeScript types and GDScript classes from schemas/v1 (--check: only report stale files).
changes
gamewright changes list|show|approve|reject|undo|redo|lock|unlock [--pack <dir>] [--json]
Review and decide the pack's proposed change sets: list [--status s,...]; show <id>; approve|reject|undo|redo <id>; lock|unlock <docId> [--item <id>] [--pointers /a,/b] [--reason r]. Approve checks the whole game first, as validate does.
import
gamewright import [--json] [--name NAME] [--origin O] [--ai A] [--license L] [--author A] [--url U]
[--no-use] <pack> <file>...
Bring your own pictures (PNG, JPEG, WebP) and sounds (Ogg Vorbis, WAV, MP3) into a game: each kept under its hash in assets/ with an Asset saying what it is and where it came from (--origin made_by_me|made_for_me|made_by_others, --ai no_ai|ai_assisted|ai_generated), and a Sprite or a Sound that uses it (not with --no-use). Undo with changes undo.
mcp
gamewright mcp [--pack <dir>] [--session <id>]
Serve the Director's tools to Claude Code or any MCP client over stdio, for the pack in <dir> (default: here; a new folder starts at the brief). Claude Code config: docs/director/.mcp.json.
serve
gamewright serve [--pack <dir>] [--no-verify] [--grant-fd N]
The session daemon Gamewright Studio talks to: JSON-RPC 2.0 over a WebSocket on 127.0.0.1 (schemas/v1/session.schema.json). Its first stdout line is {"port":…,"token":…}; it runs until SIGTERM, SIGINT or its stdin closes. --no-verify proposes without running the ladder on each proposal. --grant-fd is the web Studio host's (GAMEWRIGHT_HOSTED=1): its owner's key and what they may spend arrive on that pipe.
runner
gamewright runner --games DIR... [--host URL] [--pair CODE] [--name NAME] [--config FILE] [--plan]
Offer this computer's games to the web Studio: they open at gamewright.diy/app, and their builds, playtests and Director run here (docs/design/m12-runner.md). A folder with a game.json is one game, else each folder in it with one is. The first run pairs with a code from <host>/computers and keeps the token in ~/.config/gamewright/runner.json (mode 0600). --plan: the Director's turns run in Claude Code on your Claude plan.
director
gamewright director [--pack <dir>] [--model M] [--budget USD] [--new] MESSAGE
One turn of the in-app Director on the Anthropic API (your key: ANTHROPIC_API_KEY, else gamewright key set's): every event a line of JSON on stdout, the conversation kept in <dir>/.gamewright/director/studio.json.
key
gamewright key set|status|forget [--json]
Your Anthropic API key for the in-app Director: set reads it from stdin into your system's keychain (else a file only you can read); status says whether one is kept and where; forget removes it.
host
gamewright host --data <dir> [--port 8080] [--listen 0.0.0.0] [--dev-mail]
The web Studio's host: sign-in by emailed code, each person's games and a session daemon on the one they have open, the Studio's web export at /studio/, an admin console for ADMIN_EMAILS (docs/design/web-studio.md). Mail goes through Resend (RESEND_API_KEY); --dev-mail writes it to stderr instead. From the host's machine: host users list|add EMAIL [--role admin|member] [--name N]|remove EMAIL --data DIR, and host session EMAIL --data DIR (prints a signed-in cookie). As root, host check-isolation --data DIR proves daemons reach nothing but their owner's folder (one JSON line; exit 2 when not root).
version
gamewright version
Print the Gamewright version.
help
gamewright help
Show this help.
For every command
--schemas adds a directory of *.schema.json files next to schemas/v1 (repeatable); --kits-dir reads kit registrations from another folder than engine/addons/gamewright/kits; --library reads templates from another library than library/. Engine jobs take --timeout SECONDS; their JSON is {ok, status, reason, bundleDir, result} with the engine's own result.