CLI Reference
CLI Reference
Everything you do with Cade goes through the cade command. This page is the reference for its subcommands and the flags that matter day to day. Every command also has built-in help:
cade --help # list all commands
cade <command> --help # flags and usage for one command
Global flags
These apply to every command:
| Flag | Default | Meaning |
|---|---|---|
-d, --table-directory | current directory | Directory containing your .cade table files |
--config | ./cade.conf, then ~/.config/cade/cade.conf | Path to the runtime config file |
--livetree-enabled | false | Enable the live event-tree/cascade dashboard (WebSocket) |
Configuration precedence
Most settings can come from more than one place. Cade resolves them in this order (highest first):
- A command-line flag
- An environment variable —
CADE_plus the setting path in caps with_for.(e.g.CADE_WEB_ENABLED,CADE_LOGGING_LEVEL) - The
cade.conffile (HCL) - The built-in default
A few settings have no flag and are set only via cade.conf or the environment — for example game.max_players, game.balls_per_game, and game.credits_per_player.
Everyday commands
cade — run a table
Run with no subcommand to start the runtime. Cade loads the table, wires devices, scoring, modes, and event handlers, optionally starts the web server, and runs until you stop it (Ctrl-C).
cade -d ./my-table # run the table in ./my-table
cade -d ./my-table -w # also start the web server
With no platform block configured, Cade auto-starts a one-player headless game (handy for CI). With a platform block present, it waits for the hardware start button. Hardware and simulator connections are configured with platform "grpc" { … } blocks in your config, not with flags — see Drivers.
| Flag | Default | Meaning |
|---|---|---|
-r, --recursive | false | Search subdirectories for .cade files |
-w, --web-server | false | Enable the health/debug web server |
--web-host | localhost | Web server bind address |
--web-port | 8080 | Web server port |
--health-enabled | true | Health-monitoring endpoints |
--debug-enabled | false | Debug/visualization endpoints |
--web-logging | false | Web server access logging |
--log-level | info | debug, info, warn, or error |
--log-format | text | text or json |
cade console — interactive console
Open the interactive TUI for debugging a live table — evaluate expressions, trigger events, inspect state, and watch event cascades. When stdin isn’t a terminal (or with --no-tui), it runs in scriptable pipe mode. See Console for the in-console commands and shortcuts.
cade console -d ./my-table
cade console -d ./my-table --start --autoplay # hands-free demo
| Flag | Default | Meaning |
|---|---|---|
--theme | dark | Color theme: default, dark, light, high-contrast, monochrome, solarized-dark, solarized-light |
--start | false | Start the engine on launch |
--watch | true | Show the watch panel on startup |
--no-tui | false | Pipe mode — read commands from stdin, no TUI |
--no-audio | false | Disable the audio subsystem (useful headless/WSL) |
--autoplay | false | Drive synthetic switch activity (demo mode) |
--autoplay-speed | 70ms | Tick interval for --autoplay |
--autoplay-ball-time | 15s | Minimum time each --autoplay ball plays |
--replay | — | Load an exported session JSON into the console |
--scenario | — | Play a .cade.test file into the live event tree |
--console-config | — | Path to a console config file |
To drive the console from a simulator such as Visual Pinball X, use the gRPC flags: --grpc starts the endpoint, --grpc-host (default 0.0.0.0) and --grpc-port (default 50051) set where it listens, --grpc-platform <addr> connects out to a platform such as VPX (implies --grpc), and --grpc-platform-debug-log <path> writes platform client stream diagnostics to a file. See Visual Pinball and Migrating from Visual Pinball.
For local performance debugging, --pprof <addr> (e.g. --pprof localhost:6060) enables a profiling endpoint you can point go tool pprof at; it’s off by default and adds no overhead unless set.
cade fmt — format config files
Rewrite .cade, .cade.test, and cade.conf files into canonical HCL formatting (whitespace, alignment, indentation) — the same primitive terraform fmt is built on. It never changes a value’s bare-vs-quoted form, only the surrounding whitespace.
cade fmt # format everything under the current directory, recursively
cade fmt table.cade # format a single file in place
cade fmt -check ./tables # list files needing formatting; exit nonzero if any do
cade fmt -diff table.cade # print a unified diff instead of writing changes
A directory argument is scanned recursively for *.cade, *.cade.test, and cade.conf; a file argument is always formatted regardless of name. With no arguments, the current directory is scanned.
| Flag | Default | Meaning |
|---|---|---|
-check | false | Report files that need formatting; exit non-zero and write nothing if any do |
-diff | false | Print a unified diff instead of writing changes |
cade validate — check a config
Validate HCL syntax, required fields, types, references, circular dependencies, and variable formulas before you run.
cade validate # validate the current directory
cade validate my-table.cade # validate one file
cade validate --strict --dir ./tables -r
cade validate --include-file-org # add advisory file-organization hints
| Flag | Default | Meaning |
|---|---|---|
-s, --strict | false | Strict mode (also enables reserved-word checks) |
-f, --format | text | text, json, or yaml |
--no-color | false | Disable colored output |
--show-graph | false | Print the dependency graph |
--performance | false | Include performance analysis |
--pragma-mode | — | Override pragma mode: strict, normal, relaxed |
--ignore-pragma | false | Ignore the pragma block |
--check-reserved-words | false | Check identifiers against reserved keywords |
--dir | — | Directory to validate (takes precedence over the positional arg) |
-r, --recursive | false | Recurse into subdirectories (directory targets only) |
--include-file-org | false | Add advisory file-organization lint warnings (opt-in) |
File-organization hints
With --include-file-org, validation also runs an advisory linter that suggests
how to lay out device, module, and variable blocks across files. Its
findings are warnings only — they include a file:line and a suggestion, and
they never make validation fail. They appear in text output and in the
json/yaml formats alongside the other warnings. The linter flags:
- a
deviceblock in a file undermodules/ - a
moduleblock in a file underdevices/ - a file that mixes
deviceandmoduleblocks - a top-level
variabledeclared alongsidemoduleblocks - a file longer than the recommended 500 lines
⚠ device block in a file under modules/ (modules/playfield.cade:12)
→ Move device definitions to devices/ or the config root
To silence these hints, add them to disable_checks in the file’s pragma
block — disable_checks = ["file_organization"] turns the whole linter off for
that file, or list an individual rule (such as "device_in_module_dir") to
suppress just one.
cade validate-config — validate one file, machine-readable
Validate a single config file — HCL syntax, device references, fragment dependencies, variable usage, event references, and best-practice warnings — with output designed for scripting. Unlike cade validate, it takes exactly one file (no directory mode) and its json output carries per-finding rule ids plus a statistics block you can pipe into jq.
cade validate-config my-table.cade
cade validate-config my-table.cade --output json | jq '.valid'
cade validate-config my-table.cade --strict
| Flag | Default | Meaning |
|---|---|---|
-v, --verbose | false | Show detailed validation information |
-s, --strict | false | Strict mode — fail on warnings |
-o, --output | text | text, json, or yaml |
--pretty | true | Pretty-print JSON output (--pretty=false for compact one-line) |
cade scenario run — run tests
Run scenario tests (.cade.test files) against the real scoring engine. See Testing & Scenarios for writing them.
cade scenario run my-table.cade.test
cade scenario run ./tests -r --strict
| Flag | Default | Meaning |
|---|---|---|
-f, --format | text | text, json, or yaml |
-o, --output | stdout | Write results to a file |
-s, --strict | false | Fail on any error (implies --fail-on-error) |
--fail-on-error | false | Stop on the first error |
-p, --performance | false | Track performance |
-e, --event-spacing | 10ms | Time between events |
-t, --timing-mode | discrete | discrete (fast), wallclock (real-time), accelerated |
-r, --recursive | false | Run every scenario in a directory |
--scoring-config | — | Scoring config (.cade) to test against |
cade scenario chain — run a scenario chain
Execute a chain of related scenarios with state transfer between them — run scenarios sequentially, pass state from one to the next, and branch conditionally. Useful for testing multi-phase flows (e.g. a tutorial mode followed by a multiball progression) as a single unit.
cade scenario chain chains/tutorial_flow.cade.test
cade scenario chain chains/multiball_progression.cade.test --format json
Takes the same flags as cade scenario run (--format, --output, --performance, --fail-on-error, --strict, --event-spacing, --timing-mode, --scoring-config).
cade version
Print the version, git commit, build time, Go version, and platform.
cade version
Configuration & migration
cade migrate — fix reserved-word conflicts
Find (and optionally rewrite) identifiers that collide with Cade’s reserved keywords. Without --auto-fix it’s a dry run that reports conflicts and exits non-zero — useful as a CI gate. With --auto-fix it rewrites identifiers and leaves .bak backups. See Reserved Keyword Validation.
cade migrate --reserved-words # dry run, report conflicts
cade migrate --reserved-words --auto-fix # apply fixes (+ .bak backups)
| Flag | Default | Meaning |
|---|---|---|
--reserved-words | false | Scan for reserved-keyword conflicts (required to do anything) |
--auto-fix | false | Apply fixes and write .bak backups |
--format | text | text or json |
--dir | — | Directory to migrate |
-r, --recursive | false | Recurse into subdirectories |
--pragma-mode | normal | Severity: strict, normal, relaxed |
cade pragma — inspect and migrate pragma modes
cade pragma analyze # show effective pragma settings
cade pragma migrate my-table.cade --target-mode strict # preview
cade pragma migrate my-table.cade --target-mode strict --apply # write
cade pragma analyze [config-file]— show the effective pragma settings and their impact (--format text|json).cade pragma migrate <config-file> --target-mode <mode>— preview a move betweenstrict/normal/relaxed; add--applyto write it.
Diagnostics
The diag subcommands inspect a config without running it. Each takes an optional [config-file] (default: current directory) and supports --format and --no-color.
| Command | What it shows |
|---|---|
cade diag deps | Variable dependency graph (--format text|dot|d2|json, --variable, --depth) |
cade diag cycles | Circular dependencies in variable formulas (--max-depth) |
cade diag perf | Performance impact of scoring (--threshold <ms>) |
cade diag vars | Variables with properties and dependencies (--scope game|player|ball, --computed-only) |
cade diag stats | Configuration statistics |
cade diag deps --variable jackpot_value --format d2
cade diag perf --threshold 0.5
cade analyze [config-file] gives a combined validation-and-best-practice report (--verbose, --format, --no-suggestions, --ignore <pattern>).
History & replay
Cade can record game sessions and turn them into replays or scenario tests.
cade history list # list recorded sessions
cade history export --latest -o session.json # export the most recent
cade replay tree session.json # print its event tree
cade replay to-scenario session.json --with-expectations -o regression.cade.test
cade history list— list recorded sessions (--limit,--format table|ids,--db <path>).cade history export— export a session to JSON or event-stream (--session <id>or--latest,--output,--format json|event-stream,--db <path>).cade replay to-scenario <file.json>— convert a replay into a.cade.test(--output/-o,--ball,--scoring-only,--with-expectations).cade replay analyze <file.json>— summary report (--format text|json,--ball <n>); exits non-zero on error-level anomalies (CI gate).cade replay tree <file.json>— print the event tree, the plain-text mirror of the console’s event viewer (--ball <n>).
Portable replay files
A second, separate replay workflow trades history’s JSON export for a portable binary .cade-replay file — handy for sharing a session without a copy of the SQLite history store:
cade replay export 1a2b3c4d # → 1a2b3c4d.cade-replay
cade replay export 1a2b3c4d game.cade-replay --db ./history.db
cade replay play game.cade-replay --speed 4 # 4x fast-forward; --speed 0 = as fast as possible
cade replay convert game.cade-replay -o test.hcl # → HCL scenario
cade replay export <game-id> [output.cade-replay]— export a session from the history store to a.cade-replayfile (--db <path>); defaults to<game-id>.cade-replay.cade replay play <file.cade-replay>— replay its events in order at a configurable rate (--speed, default1.0real-time).cade replay convert <file.cade-replay>— convert to an HCL scenario (-o/--output,--with-expectations). This path is lossy relative tohistory export+replay to-scenario— prefer the JSON path above when you have it.
Many commands can emit machine-readable output for piping into other tools, but the flag is not universal: most use
--format json(several also takeyaml), whilecade validate-configuses--output. Check the command’s own flag table above before scripting against it.