Skip to Content
CLI flag reference

Getting started

CLI flag reference

Every command below is generated from rystic help <command>. Use this reference to choose flags; Docker configuration shows where to put them in Compose.

View command help directly from the Docker image without installing anything locally:

docker run --rm registry.rystic.ai/kalshi-twin:<version> rystic help run

Flags belong to a command; there are no inherited global flags. -h or --help prints help for any command. Long flags accept one or two leading hyphens. Booleans use --flag=false to turn off a default; --flag false does not set a boolean to false. Arguments after -- in run, batch and grid belong to the child process.

Defaults below come from help in a clean environment. Empty strings are shown as unset; numeric zero and boolean false are shown explicitly. run --port uses -1 internally to mean “resolve environment/config, then 8080.” See configuration precedence and live environment variables for resolved defaults.

CommandPurpose
rystic pulldownload and install a twin release
rystic updateinstall a newer twin release, or just ask whether one exists
rystic runrun a twin (pulls it if missing); -d detaches, args after — go to the twin
rystic pslist running twins — status from a live probe, not the record
rystic stopstop instances (SIGTERM, then SIGKILL after -timeout)
rystic restartstop and start again from the recorded spec
rystic rmremove a stopped instance’s record and log (refuses a live one)
rystic logsprint a detached twin’s log; -f follows
rystic reportthe batch P&L table — per-world declared columns, exact totals, settled vs left open
rystic upstart every service of a stack file — each exactly one run -d
rystic downstop every instance of a stack file’s project
rystic exportwrite a docker-compose.yaml (digest-pinned, license from .env) or the Antithesis scaffold from a stack file
rystic statuslicense, runtime, registry, installed, running, updates — one screen
rystic batchrun a bot against every tape in your library — natively, or one container per world with —runner docker
rystic gridrun the bot × world matrix: bundled example bots (plus yours) against the twin’s scenario worlds
rystic checkboot an installed twin and confirm it serves and resets
rystic tailstream a running twin’s state events to this terminal
rystic feedfeed a running twin live exchange frames (the twin’s manifest declares the source; a release build carries the key it needs)
rystic doctorcheck this machine end to end without running anything
rystic featureslist what the installed twin can do
rystic listreleased sims your license covers — latest, installed, running (—installed: the old per-version lines)
rystic logininstall a license file, and log docker in to the registry with it
rystic licenseshow the active license, or install one
rystic configshow every setting with its source, or set one
rystic self-updatereplace this CLI with the latest release
rystic versionprint this CLI’s version, then every running twin’s
rystic helpprint this message; help &lt;command&gt; shows a command’s flags

pull

usage: rystic pull [flags] [product]

download and install a twin release

Installs into $RYSTIC_HOME/twins/<product>/<version> and marks it current,
verifying the download against the release checksum before unpacking.

FlagDefaultMeaning
--arch stringunsettarget arch (default: this machine’s): amd64 or arm64
--endpoint string$RYSTIC_RELEASE_ENDPOINT or https://www.rystic.ai/api/twin-release release endpoint
--license stringunsetpath to the license file
--os stringunsettarget OS (default: this machine’s); linux for the docker runner
--version string“latest”release version to install (e.g. VERSION)

update

usage: rystic update [flags] [product]

install a newer twin release, or just ask whether one exists

With -check, prints what is available and exits 10 when a newer
version exists — nothing is downloaded.

FlagDefaultMeaning
--checkfalseonly report whether newer versions exist (exit 10 if so); download nothing
--cli-endpoint string$RYSTIC_CLI_ENDPOINT or https://www.rystic.ai/api/cli-release CLI release endpoint
--endpoint string$RYSTIC_RELEASE_ENDPOINT or https://www.rystic.ai/api/twin-release release endpoint
--license stringunsetpath to the license file
--no-selffalsedo not update the CLI itself

run

usage: rystic run [flags] [product] [-- args...]

run a twin (pulls it if missing); -d detaches, args after -- go to the twin

Prints one identity line — product, version, model, licensee, URL — once
the twin serves. --scenario/--seed/--tapes/--tape choose the starting state.
Default port 8080; a busy port is a conflict (exit 9); --port 0 picks a free one.

FlagDefaultMeaning
--copies int0play —tape as this many markets at once, each under its own ticker (<tape>-1 … <tape>-N) on its own WS stream
-dfalsedetach: return once the twin serves; ‘rystic stop <name>’ ends it
--egress-retain stringunsetRYSTIC_EGRESS_RETAIN for the twin
--env valueunsetextra KEY=VALUE for the twin (repeatable)
--jsonfalseprint the JSON envelope instead of the identity line
--license stringunsetpath to the license file
--livefalsefeed the twin live exchange frames from this process (the manifest declares the source; a release build carries the key it needs; default: $RYSTIC_LIVE)
--live-carry int0pre-carry the busiest N before anything is picked; 0 carries nothing until the UI picks (default: $RYSTIC_LIVE_CARRY)
--live-env stringunsetexchange environment from the twin’s manifest (default: $RYSTIC_LIVE_ENV, then the manifest’s default_env)
--live-markets stringunsetcomma-separated markets to carry before anything is picked in the UI (default: $RYSTIC_LIVE_MARKETS)
--live-markets-file stringunsetstartup watch-list file: one ticker per line or comma-separated; read once at startup (default: $RYSTIC_LIVE_MARKETS_FILE; mutually exclusive with —live-markets)
--live-max-markets int500how many of the busiest open markets to offer in the twin UI (default: $RYSTIC_LIVE_MAX_MARKETS)
--live-series string”*”comma-separated series to carry; * = every open market on the exchange (default: $RYSTIC_LIVE_SERIES)
--live-shards int3exchange sockets to spread the carried markets over (the exchange caps connections per key; default: $RYSTIC_LIVE_SHARDS)
--name string“default”instance name — what ps/stop/logs call it
--network stringunsetRYSTIC_NETWORK for the twin: off, on, or a profile file
--port int-1listen port; 0 picks a free one (default: $RYSTIC_PORT, config.json, then 8080)
--project string“default”project label — what ‘ps —project’ and ‘down’ group by
--runner stringunsetnative or docker (default: $RYSTIC_RUNNER, config.json, then native)
--scenario stringunsetboot into a named scenario (the twin’s own catalog)
--seed stringunsetboot seed file, applied before the first request
--seed-rng stringunsetpin the twin’s RNG once serving
--speed float1replay speed for —tape
--tape stringunsetstart replaying this tape once serving (needs a tape library); a comma-separated list plays them as ONE synchronized group — merged onto a single clock and trimmed to the window they share
--tapes stringunsettape library for replay (validated before start; default: $RYSTIC_TAPES, config.json)
--timeout duration30show long to wait for the twin to serve
--version stringunsetinstalled version to run (default: current)

ps

usage: rystic ps [flags]

list running twins — status from a live probe, not the record

FlagDefaultMeaning
-afalseinclude exited instances (and do not prune their records)
--jsonfalseprint the JSON envelope
--project stringunsetonly instances of this project (‘rystic up’ labels a stack file’s services with its project)

stop

usage: rystic stop [flags] <name>… | --all

stop instances (SIGTERM, then SIGKILL after -timeout)

FlagDefaultMeaning
--allfalsestop every instance
--timeout duration3show long to wait after SIGTERM before SIGKILL

restart

usage: rystic restart [flags] <name>… | --all

stop and start again from the recorded spec

FlagDefaultMeaning
--allfalserestart every instance
--jsonfalseprint the JSON envelope
--timeout duration3show long to wait after SIGTERM before SIGKILL

rm

usage: rystic rm <name>…

remove a stopped instance's record and log (refuses a live one)

No flags.

logs

usage: rystic logs [flags] [-f] <name>

print a detached twin's log; -f follows

FlagDefaultMeaning
-ffalsefollow: keep printing new lines
--feedfalseprint the feeder’s log instead of the twin’s (‘run —live’)

report

usage: rystic report [flags] <batch-out-dir> [-sort col] [-csv]

the batch P&L table — per-world declared columns, exact totals, settled vs left open

FlagDefaultMeaning
--csvfalseCSV to stdout (no totals row — spreadsheets sum themselves)
--jsonfalseprint the JSON envelope
--sort stringunsetsort by a declared column, worst first; prefix - for best first

up

usage: rystic up [flags] [-d] [-f rystic.yaml] [service…]

start every service of a stack file — each exactly one `run -d`

A stack file is a hand-picked set of twins: version: 1, project, and
services: {name: {product, version, runner, port, scenario, seed, tapes,
tape, speed, env, args, seed_rng, egress_retain, network, live}} — the same
keys as run's flags; the service name is the instance name; the project
labels every twin for `ps --project` and `down`. Already-running services
are said, not restarted. Without -d, up holds the terminal and Ctrl-C is
`down`.

FlagDefaultMeaning
-dfalsedetach: return once every service serves; ‘rystic down’ ends them
-f string./rystic.yamlstack file
--jsonfalseprint the JSON envelope instead of identity lines
--timeout duration30show long to wait for each twin to serve

down

usage: rystic down [flags] [-f rystic.yaml | --project p]

stop every instance of a stack file's project

FlagDefaultMeaning
-f string./rystic.yamlstack file whose project to stop
--project stringunsetproject to stop (instead of reading a stack file)
--timeout duration3sgrace before SIGKILL

export

usage: rystic export [flags] compose|antithesis [-f rystic.yaml] [-o dir]

write a docker-compose.yaml (digest-pinned, license from .env) or the Antithesis scaffold from a stack file

compose: each service becomes a compose service on registry.rystic.ai/<product>@<digest>
(resolved through the front door with your license — the run is reproducible),
RYSTIC_LICENSE from .env (.env.example is written beside it, never a value),
init: true, the image's HEALTHCHECK for depends_on. antithesis: the same plus
platform linux/amd64, Dockerfile.config (FROM scratch, the compose file + .env)
and a README with the tenant push commands (--tenant, --gcp-project). A tape:
key cannot be expressed in compose and is reported.

FlagDefaultMeaning
-f string./rystic.yamlstack file
--gcp-project stringunsetantithesis: the GCP project of your tenant repository
--no-digestfalsepin images by tag, no registry call (a digest pin is what makes a run reproducible)
-o stringunsetwrite the files here (compose: default stdout; antithesis: required)
--tenant stringunsetantithesis: your tenant name (the README’s push commands)

status

usage: rystic status [flags]

license, runtime, registry, installed, running, updates — one screen

FlagDefaultMeaning
--jsonfalseprint the JSON envelope
--license stringunsetpath to the license file
--offlinefalsedo not ask the release endpoint about updates
--pub stringunsetpath to a license public key (overrides the built-in one)

batch

usage: rystic batch [flags] [product] [flags] -- <bot command>

run a bot against every tape in your library — natively, or one container per world with --runner docker

One twin+bot pair per tape, -j at a time, longest tape first, at speed 1 —
real time, so the code under test keeps a coherent clock. One JSONL ledger
row per tape in -out. -dry-run prints the plan without running anything.
The bot contract is four environment variables — RYSTIC_ADDR, RYSTIC_WORLD,
RYSTIC_WORLD_KIND, RYSTIC_RESULT, plus RYSTIC_MARKET on a tape cell — and
the same values are substituted into the bot's own argv as {{addr}}
{{world}} {{world_kind}} {{result}} {{market}}, for a bot that takes them as
flags rather than from the environment: `-- python3 bot.py --event
{{market}}` gives each cell its own market instead of one market N times.
{{market}} is the MARKET ticker the tape directory is named for; a bot
wanting a coarser id derives it itself, and on -scenarios it is refused
rather than substituted empty. With --runner docker the substitution happens
inside your image, and an image whose rystic predates placeholders is
refused before it runs rather than passing the braces through verbatim.
--runner docker --image <ref> runs each world in its own container from YOUR
image (FROM registry.rystic.ai/<product>:<version> + your bot's runtime): the
same ledger, state and logs, kernel-isolated, no shared ports; the license
reaches each container only through its environment.

FlagDefaultMeaning
--bot-argv-placeholdersfalsecapability handshake set by ‘batch —runner docker’ on the container’s own argv; not for callers
--dry-runfalseprint the plan and exit without running anything
--egress-retain stringunsetvalue for RYSTIC_EGRESS_RETAIN on each twin (” = the twin’s default)
--image stringunsetwith —runner docker: the image each world runs in — yours, built FROM registry.rystic.ai/<product>:<version> plus your bot’s runtime
-j int2concurrent slots (twin+bot pairs); -j auto is not built yet
--license stringunsetpath to the license file
--limit int0run at most N tapes (0 = all)
--market stringunsetonly tapes whose market matches this pattern (e.g. ‘KXBTC15M*’)
--out stringbatch-<timestamp>output directory
--runner stringunsetnative (one twin process per world here) or docker (one container per world from —image; default: $RYSTIC_RUNNER, config.json, then native)
--scenarios stringunsetrun named scenarios instead of tapes: ‘all’, or a comma-separated list; the catalog is the twin’s own, so planning boots one twin briefly — even with -dry-run
--settle-route stringunsetsettlement endpoint to POST to (default: whatever the twin archive’s manifest declares)
--settlements stringunsetJSON file of market -> outcome, applied when each tape ends so held positions realize (a capture never records how a market resolved)
--tape stringunsetexactly one tape, by market id — the unit a container runs per world; not with -market
--tapes string$RYSTIC_TAPES, then $RYSTIC_HOME/tapes, then where the twin manifest says the twin lookstape library
--timeout duration30m0sper-tape budget: twin boot, playback, teardown
--version stringunsetinstalled version to run (default: current)

grid

usage: rystic grid [flags] [product] [flags] [-- <bot command>]

run the bot × world matrix: bundled example bots (plus yours) against the twin's scenario worlds

One twin per cell. Rows are the archive's declared grid bots, plus your own
command after `--` (same contract as batch: read RYSTIC_ADDR, exit 0 for
pass, and the same argv placeholders — except {{market}}, which a scenario
world has not got and which grid therefore refuses). Columns default to the
archive's declared worlds; -worlds overrides
('all' runs the twin's whole catalog). Prints the grid and exits non-zero
if any cell failed.

FlagDefaultMeaning
--dry-runfalseprint the plan and exit (‘-worlds all’ still boots one twin briefly to read the catalog)
-j int2concurrent cells (twin+bot pairs)
--license stringunsetpath to the license file
--out stringgrid-<timestamp>; must not already existoutput directory
--ticks int15tick budget handed to each cell’s bot via RYSTIC_TICKS (0 = no budget)
--timeout duration5m0sper-cell budget: twin boot, bot run, teardown
--version stringunsetinstalled version to run (default: current)
--worlds stringunsetcomma-separated scenario names, or ‘all’ (default: the archive’s declared grid worlds)

check

usage: rystic check [flags] [product]

boot an installed twin and confirm it serves and resets

FlagDefaultMeaning
--license stringunsetpath to the license file
--timeout duration15show long to wait for the twin to serve
--version stringunsetinstalled version to check (default: current)

tail

usage: rystic tail [flags]

stream a running twin's state events to this terminal

Connects to the twin's /_rystic/events stream and prints one line per
event. -events scopes the feed (private, public, writes, reads, control;
or all) — the default shows fills, order updates and other state changes
and skips public market-data floods.

FlagDefaultMeaning
--addr stringhttp://localhost:8080 twin base URL
--events stringprivate,writes,control; or off/all/comma listevent scope

feed

usage: rystic feed [flags] [product] --instance <name> | --url <base>

feed a running twin live exchange frames (the twin's manifest declares the source; a release build carries the key it needs)

Runs in the foreground until Ctrl-C. `rystic run --live` starts a twin and
this feeder together (either runner: the feeder is a host process posting
to the twin's URL); use `feed` alone for a twin already running — any
runner, any machine. --live-series * carries whatever the twin's Markets
card picks from the exchange's busiest open markets; nothing is carried
until something is picked (--live-carry N pre-carries the busiest N,
--live-markets A,B carries exactly those). Every --live-x-y flag defaults
from RYSTIC_LIVE_X_Y. The twin's manifest names its exchange key vars: an
id, then either <X>_PRIVATE_KEY_FILE (a path) or <X>_PRIVATE_KEY_B64 (the PEM).

FlagDefaultMeaning
--instance stringunsetfeed the named running instance (‘rystic ps’)
--live-carry int0pre-carry the busiest N before anything is picked; 0 carries nothing until the UI picks (default: $RYSTIC_LIVE_CARRY)
--live-env stringunsetexchange environment from the twin’s manifest (default: $RYSTIC_LIVE_ENV, then the manifest’s default_env)
--live-markets stringunsetcomma-separated markets to carry before anything is picked in the UI (default: $RYSTIC_LIVE_MARKETS)
--live-markets-file stringunsetstartup watch-list file: one ticker per line or comma-separated; read once at startup (default: $RYSTIC_LIVE_MARKETS_FILE; mutually exclusive with —live-markets)
--live-max-markets int500how many of the busiest open markets to offer in the twin UI (default: $RYSTIC_LIVE_MAX_MARKETS)
--live-series string”*”comma-separated series to carry; * = every open market on the exchange (default: $RYSTIC_LIVE_SERIES)
--live-shards int3exchange sockets to spread the carried markets over (the exchange caps connections per key; default: $RYSTIC_LIVE_SHARDS)
--url stringunsetfeed the twin at this base URL, e.g. http://localhost:8080 
--version stringunsetinstalled version whose manifest to read (default: current)

doctor

usage: rystic doctor [flags] [product]

check this machine end to end without running anything

Verifies the license, the install, that the twin and your license agree on a
signing key, and that the data the twin needs is where it expects it. Exits 0
when everything passes; warnings (!) are features you do not have yet, not
failures. Run it before a demo, not during one.

FlagDefaultMeaning
--license stringunsetpath to the license file
--pub stringunsetpath to a license public key (overrides the built-in one)
--version stringunsetinstalled version to inspect (default: current)

features

usage: rystic features [flags] [product]

list what the installed twin can do

Read from the twin's own manifest, so it describes the build you have rather
than what this CLI was written against. -v adds detail and control-plane URLs.

FlagDefaultMeaning
-vfalseinclude the long description and control-plane endpoints for each feature
--version stringunsetinstalled version to describe (default: current)

list

usage: rystic list [flags]

released sims your license covers — latest, installed, running (--installed: the old per-version lines)

FlagDefaultMeaning
--endpoint stringunsetcatalog endpoint (default $RYSTIC_CATALOG_ENDPOINT, config.json, then https://www.rystic.ai/api/catalog ); file:// reads a JSON file
--installedfalseonly what is installed here, one line per version (the old output)
--jsonfalseprint the JSON envelope
--license stringunsetpath to the license file

login

usage: rystic login [flags] <file>

install a license file, and log docker in to the registry with it

Verifies the license and parks it in $RYSTIC_HOME, where every later
command finds it without a flag (`rystic license` shows it afterwards).
The same file is the password for the Rystic image registry, so when a
container runtime answers this also runs `docker login <registry> -u
license --password-stdin` — `docker pull <registry>/<product>:<version>`
and `rystic run --runner docker` then work with nothing else. --no-docker
skips that half.

FlagDefaultMeaning
--forcefalseactivate even if the license is expired
--no-dockerfalseactivate the license only; do not ‘docker login’ to the registry
--pub stringunsetpath to a license public key (overrides the built-in one)

license

usage: rystic license [flags] [activate <file>]

show the active license, or install one

`rystic license activate <file>` verifies a license and parks it in
$RYSTIC_HOME, where every later command finds it without a flag.

FlagDefaultMeaning
--license stringunsetpath to the license file
--pub stringunsetpath to a license public key (overrides the built-in one)

config

usage: rystic config [flags] [set <key> <value>]

show every setting with its source, or set one

Settings resolve flag > environment > $RYSTIC_HOME/config.json > built-in,
and this prints which. Keys: runner, port, tapes, release_endpoint,
catalog_endpoint, image_source (registry|archive), registry, docker.binary,
docker.host.

FlagDefaultMeaning
--jsonfalseemit the JSON envelope instead of a table

self-update

usage: rystic self-update [flags]

replace this CLI with the latest release

The CLI itself is not license-gated: it downloads from the public release
endpoint. With -check, reports and exits 10 without replacing anything.

FlagDefaultMeaning
--checkfalseonly report whether a newer CLI exists (exit 10 if so); download nothing
--endpoint string$RYSTIC_CLI_ENDPOINT or https://www.rystic.ai/api/cli-release CLI release endpoint
--forcefalsereplace even a dev build, or re-install the version already running
--version string“latest”CLI version to install (e.g. VERSION)

version

usage: rystic version [flags]

print this CLI's version, then every running twin's

Prints this CLI's version, commit, build date and platform, then every
running twin's product, version and model, and warns when a running twin
is behind the installed one.

FlagDefaultMeaning
--jsonfalseprint the JSON envelope

help

rystic help lists commands; rystic help <command> lists that command’s flags.

Last updated on