Operating & Deployment
Operating & Deployment
This page is about running Cade unattended on a real machine — a cabinet in a lineup, a location piece, or a dedicated test rig — rather than driving it interactively from your bench. The console is the hands-on tool for development; here we cover starting the runtime at boot, capturing its logs, watching its health, and rolling out updates.
Early stage — planned feature set. Cade can be operated in production today, but the operations story is deliberately thin and still being built out. There is no built-in service manager, daemon mode, log-file/rotation config, live config reload in the running runtime, or persistence of game state across a restart yet. The patterns below lean on your operating system (systemd) to fill those gaps. First-class operating features are planned — treat this page as the current state, not the destination.
A single binary to deploy
Cade ships as one self-contained executable. The Go runtime and everything Cade needs are compiled in, so there’s no interpreter, virtual machine, language runtime, or package tree to install alongside it — copy the single binary onto the machine, point it at a table directory, and run. Deploying and updating Cade is a matter of moving one file (see Updating Cade).
It’s also light on the processor. The event pipeline runs at 50–100 Hz and the scoring engine resolves rules in well under a millisecond, so flipper and coil timing stay tight and the runtime leaves plenty of headroom on modest cabinet hardware — you don’t need a powerful machine to run a table.
Running the runtime
Starting a table is a single command — point Cade at the table directory and it loads the config, wires devices, scoring, modes, and event handlers, and runs until stopped:
cade -d /opt/tables/my-table
There’s no TUI involved in this mode; it runs headless and writes to standard output and standard error. Add -w to bring up the web server for remote monitoring. Cade shuts down cleanly on SIGINT/SIGTERM, so stopping it from a service manager (or Ctrl-C) is graceful — in-flight work is allowed to wind down.
See the CLI Reference for the full flag list.
Configuration on a deployed machine
On a deployed machine, settings come from (highest priority first) command-line flags, CADE_* environment variables, a config file, then built-in defaults. Cade looks for its runtime config file as --config <path> if given, otherwise ./cade.conf in the working directory, otherwise ~/.config/cade/cade.conf.
Keep the table itself (.cade files, sounds, assets) in its own directory and pass it with -d. Keep machine-level settings (platform/driver, web server, logging) in the cade.conf for that machine. For the full block reference, defaults, and precedence rules see Runtime Configuration.
Choosing the hardware platform
Which driver Cade talks to — FAST hardware, a Visual Pinball X bridge, or the built-in virtual driver — is selected in configuration, so the same table runs against real hardware in the cabinet and the virtual driver on a test rig without editing the table. See Drivers for each driver’s setup.
Logging
Cade logs to standard output and standard error (info and below to stdout, warnings and errors to stderr). Two settings control it:
cade -d /opt/tables/my-table --log-level info --log-format json
| Setting | Values | Default |
|---|---|---|
--log-level | debug, info, warn, error | info |
--log-format | text, json | text |
Use json when a log shipper or journald is going to parse the output. There is no built-in log-file path or rotation — capture and rotate the stream with your service manager (systemd’s journal does this for you) or a shell redirect. Per-table audio, scoring, and event detail is best inspected live in the console rather than from these logs.
Running at boot with systemd
Cade has no built-in service installer or daemon mode — running it at boot is an operating-system job. On Linux, a systemd unit is the straightforward path. Because Cade exits cleanly on SIGTERM, the default systemd stop is graceful, and Restart=on-failure gives you crash recovery:
# /etc/systemd/system/cade.service
[Unit]
Description=Cade pinball runtime
After=network.target
[Service]
Type=simple
User=cade
WorkingDirectory=/opt/tables/my-table
EnvironmentFile=-/etc/cade/cade.env
ExecStart=/usr/local/bin/cade -d /opt/tables/my-table --log-format json
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
Put any CADE_* overrides in the EnvironmentFile (for example CADE_WEB_ENABLED=true). Then:
sudo systemctl daemon-reload
sudo systemctl enable --now cade
journalctl -u cade -f # follow the logs
Restart=on-failure brings Cade back up if it crashes — but note that a restart starts a fresh game (see Restarts and state), so it recovers the process, not an in-progress game.
Health monitoring
For an unattended machine, enable the web server and point a monitor at its health endpoint. The /health/status endpoint returns an HTTP status code that reflects the table’s state (200 healthy, 206 degraded, 503 unhealthy), so most uptime tools and load balancers can consume it directly:
cade -d /opt/tables/my-table -w
curl -fsS http://localhost:8080/health/status
The full set of endpoints, the live dashboard, and the event-flow debugger are covered in Web Dashboard & Observability. (That surface is also early-stage — see its own note.) For resilience within a running game — keeping play going when a rule or device misbehaves — see Scoring Safety Mode.
Applying configuration changes
The running production runtime does not watch your .cade files — to apply a config or table change, restart the process (systemctl restart cade). Live reload, where the engine recompiles scoring as files change while preserving player state, is available today while you’re iterating in the console; it is not yet wired into the unattended runtime. Plan config rollouts as a quick restart between games.
Restarts and state
A restart — whether you triggered it or Restart=on-failure did — begins a fresh game. In-progress game and player state is not persisted across a process restart. Schedule updates and restarts for when the machine is idle, not mid-ball. (Historical event data can be recorded separately for later analysis; see the history and replay commands in the CLI Reference.)
Updating Cade
Cade is distributed as a single binary on an invite basis, and there is no self-update — updates are a manual swap. The safe sequence:
cade version # note the current version
sudo systemctl stop cade # stop between games
sudo install -m755 cade-new /usr/local/bin/cade
sudo systemctl start cade
cade version # confirm the new version
Validate the table against the new binary before putting the machine back in service:
cade validate -d /opt/tables/my-table
Production checklist
- Table directory and
cade.confare in place;cade validatepasses. - Hardware platform/driver is configured for this machine.
- A systemd unit (or equivalent) runs Cade at boot with
Restart=on-failure. - Logs are captured —
--log-format jsonplusjournalctl, or your log shipper. - The web server is enabled and an uptime monitor watches
/health/status. - You have a tested update procedure and run it while the machine is idle.