Skip to Content
The rystic CLI

Reference

The rystic CLI

Installation is the walkthrough. CLI flag reference lists every command and flag, generated from command help. Docker covers running without a local CLI: image defaults, Compose overrides and environment variables.

Install

curl -fsSL https://www.rystic.ai/install.sh | sh
rystic login rys_…                        # an API key from /account/api-keys (+ docker login)
rystic login --token-stdin < key.txt      # the same, kept out of shell history
rystic login ./rystic-license.json        # Enterprise: activate a license file (+ docker login)
  1. The CLI is the downloader, not the product — anyone can install it. Simulator binaries and images need an API key or, on Enterprise, a license.
  2. macOS and Linux; Windows zip on request. RYSTIC_BIN overrides where it lands.
  3. login rys_… stores the key at $RYSTIC_HOME/token, readable by you only, and never prints it. login <file> verifies a license offline and parks it in $RYSTIC_HOME. Either runs docker login registry.rystic.ai when a runtime answers; --no-docker skips that half. Plans and API keys covers both.
  4. After a license login, on a terminal and with $CI unset, login offers a numbered menu of simulators to start, each exactly as rystic run <product> -d --scenario <its quickstart scenario>; a busy port retries once on a free one. --no-start skips the offer, and so does any non-terminal or CI run.

Commands

CommandWhat it does
login <rys_key | file>store an API key, or install an Enterprise license file, and log Docker in to the registry with it
docs [topic] | search <terms>Rystic’s docs, offline: the site’s pages as of this CLI’s release, plus each installed simulator’s HOWTO.md and SCENARIOS.md
run [product]run a simulator (pulls it if missing); -d detaches, args after -- go to the simulator
ui [product]run a simulator’s verified UI against a running instance: the <product>-ui image through the registry when Docker answers, else its archive on your Node; Pro and Enterprise
pslist running simulators — status from a live probe, not the record
stop <name>… | --allstop instances (SIGTERM, then SIGKILL after -timeout)
restart <name>… | --allstop and start again from the recorded spec
rm <name>…remove a stopped instance’s record and log
logs [-f] <name>print a detached simulator’s log; -f follows
tail [-addr url] [-events …]stream a running simulator’s state events to this terminal
up [-d] [-f rystic.yaml] [svc…]start every service of a stack file — each exactly one run -d
down [-f rystic.yaml | --project p]stop every instance of a stack file’s project
export compose|antithesis [-f] [-o dir]a digest-pinned docker-compose.yaml (+ .env.example), or the Antithesis scaffold
scenario save <instance> <file>a running instance’s state as a scenario file that run --seed and POST /_rystic/seed take back; --force replaces an existing file
statusAPI key, license, runtime, registry, installed, running, updates — one screen
listreleased simulators — latest, installed, running (reads a license file)
pull [product]download and install a simulator release without running it
updateinstall a newer simulator release, or just ask whether one exists
checkboot an installed simulator and confirm it serves and resets
doctor [product]check this machine end to end without running anything
featureslist what the installed simulator can do
config [set k v]show every setting with its source, or set one
license [activate <file>]Enterprise: show the active license, or install one
mcp [install --client c]serve MCP tools on stdio so a coding agent drives simulators, or write the server into a client’s config (guide)
feedback [message]send Rystic a bug, friction or feature request, filed under your account
self-updatereplace this CLI with the latest release
versionthis CLI’s version, then every running simulator’s — warning on any drift

rystic help <command> prints a command’s flags on stdout. An older CLI prints them on stderr; rystic help <command> 2>&1 works on either.

--json prints {schema_version, command, status, data, warnings, error}. Only run, ps, restart, up, status, list, version, config, report, docs and scenario save take it; the rest refuse it (exit 2).

Simulator-specific commands

These only apply to a simulator whose manifest declares the feature — today the Kalshi simulator. rystic features lists what the installed build supports.

CommandWhat it does
run --live / feed <product>feed a simulator from the exchange as it moves — Live mode
logs --feed <name>a detached instance’s feeder log
batch [--runner docker --image <ref>]run a bot against every tape in a library — Backtesting
report <batch-out-dir> [-sort col] [-csv]the batch P&L table — exact totals, settled vs left open
grid [product] [-- <bot command>]the bot × scenario matrix — bundled example bots plus yours

run

rystic run stripe-twin                                # serves :8080, streams events
rystic run stripe-twin -d --name a --port 0           # detach on a free port
rystic run stripe-twin --scenario design_studio       # boot into a named scenario
rystic run stripe-twin --seed ./scenario.json         # seed file, applied before the first request
rystic run stripe-twin --runner docker -d             # as a container, from registry.rystic.ai
rystic run stripe-twin -- --events=all                # args after -- go to the simulator
  1. CLI flags can appear before or after the product name; anything after -- goes to the simulator.
  2. Default port 8080; a busy port is exit 9; --port 0 picks a free one.
  3. --runner docker needs a container runtime. The image comes from the registry, or is built locally from a pulled Linux archive when image_source=archive or the registry is unreachable. See Docker.
  4. Replay (--tapes, --tape, --copies, --speed) and --live are Kalshi features: Replay, Live mode.
  5. On Free and Pro, run hands the simulator your API key and the simulator checks in with Rystic while it serves. -v prints one line per check-in. On Free, --network exits naming the faults feature the plan lacks: Boot inputs.

up, down, export — the stack file

# rystic.yaml — every key is a run flag; the service name is the instance name
version: 1
project: demo
services:
  payments: {product: stripe-twin, port: 0, scenario: design_studio}
  reviews:  {product: github-pulls-twin, port: 0, seed: ./seeds/repo.json}
  exchange: {product: kalshi-twin, runner: docker, port: 0, scenario: thin_book}

File paths are relative to the stack file. On Free, a service may set no network. Kalshi-only keys (tapes, tape, copies, live and the live_* family) are listed on the Kalshi page. The Docker builder writes this file for you.

rystic up -d                       # one identity line per service
rystic ps --project demo
rystic down
rystic export compose -o ./deploy  # digest-pinned compose + .env.example
rystic export antithesis -o ./anti --tenant <t> --gcp-project <p>

A stack file never carries a key or license. A malformed one is refused naming the file, service and key. export warns when a tape: cannot be expressed in Compose.

ps, stop, logs, status, tail

rystic ps                    # NAME PRODUCT VERSION RUNNER URL MODEL LICENSEE UPTIME STATUS
rystic stop a b              # or --all
rystic logs -f a
rystic status                # --offline skips the network

status prints the registry line — registry.rystic.ai · logged in · reachable. A token: line shows the API key masked (rys_AAAA…), where it came from, and the organization and plan the site reports; --offline prints not checked instead. A license file adds a license: line. With neither, it prints credential: none and the rystic login line to run. --json carries both as token and license, never the key itself.

rystic tail -addr http://localhost:53124            # a detached instance on another port
rystic tail -events all                             # public market data too

tail reads the simulator’s GET /_rystic/events stream. -addr defaults to http://localhost:8080.

doctor

rystic doctor stripe-twin

The pre-demo check, no boot: the CLI and its home, configuration, the install, signing-key agreement, simulator data, container runtime, registry login — and, for a simulator with a live feed, the exchange key and where it came from. Exits 0 when no line shows ✗.

doctor checks the credential the installed build runs on. On an API key:

✓ api key                rys_AAAA… · from /Users/you/.rystic/token · org <org> · <plan> plan · www.rystic.ai answered

✗ api key plan means the plan does not include that product; a refused key is ✗ api key with the exit-11 sentence, and doctor exits 11. If the site does not answer, the line is a ! warning and the simulator checks the key when it starts. With a license file, doctor checks the license instead and reports any stored key as api key (not in use), a warning at most. rystic check <product> boots the installed build once to prove it.

docs

rystic docs                          # numbered index: the site's pages, then each installed simulator's HOWTO and SCENARIOS
rystic docs agent-quick-start        # one page as Markdown
rystic docs cli#exit-codes           # one section
rystic docs stripe-twin              # the installed HOWTO.md, plus the live routes of each running instance
rystic docs kalshi-twin scenarios    # the installed SCENARIOS.md
rystic docs search rate limit        # every section holding all the terms, as <topic>#<anchor>
rystic docs -online cli              # read the live site instead of the built-in snapshot

The site’s pages are a snapshot built into the CLI when it was released, so rystic docs works offline and needs no key; a page added since needs -online. A product’s short name works too (rystic docs stripe); with nothing installed it falls back to the site’s page for that simulator. -json prints the envelope, -n caps search results. An unknown topic, section or SCENARIOS.md exits 5 and says what to try instead. Stripe ships no SCENARIOS.md.

list, pull, update

rystic list                                # PRODUCT LATEST INSTALLED RUNNING SUMMARY (on an API key or a license file)
rystic pull -version <x.y.z> stripe-twin   # omit for latest
rystic update                              # the CLI and every installed simulator
rystic update -check                       # report only; exit 10 if newer ones exist

pull installs into $RYSTIC_HOME/twins/<product>/<version>, checksum-verified, marked current. -os linux -arch amd64 fetches another platform’s build (the air-gap Docker path).

config

rystic config                       # every setting, its value and where it came from
rystic config set runner docker     # flag > env > config.json > built-in
KeyEnvBuilt-in
runnerRYSTIC_RUNNERnative
portRYSTIC_PORT8080
tapesRYSTIC_TAPES— (Kalshi replay library)
image_sourceRYSTIC_IMAGE_SOURCEregistry (archive builds locally)
registryRYSTIC_REGISTRYregistry.rystic.ai
docker.binaryRYSTIC_DOCKERdocker, else podman
docker.hostDOCKER_HOST—
release_endpointRYSTIC_RELEASE_ENDPOINThttps://www.rystic.ai/api/twin-release
catalog_endpointRYSTIC_CATALOG_ENDPOINThttps://www.rystic.ai/api/catalog
docs_endpointRYSTIC_DOCS_ENDPOINThttps://www.rystic.ai (what docs -online reads)
tokenRYSTIC_TOKEN— (an API key; rystic config shows only (set) and where it came from)

config set token is refused: edit config.json or use rystic login.

Files and environment

Everything lives under $RYSTIC_HOME (default ~/.rystic): installed simulators, the current marker per product, token (the API key login stored) or the active license, config.json (once you config set something), and run/ — one record per instance.

VariableMeaning
RYSTIC_HOMEinstall root
RYSTIC_PRODUCTproduct to use when no product argument is given; set by the image
RYSTIC_TOKENan API key; checked before config.json and the stored token, and how containers get it
RYSTIC_LICENSEEnterprise: a license file path — or the license itself (JSON or base64), which is how containers get it
RYSTIC_REGISTER_WAIThow long a simulator retries reaching Rystic at start, default 10m; 0 tries once
RYSTIC_LEASE_URLthe lease server a Free or Pro simulator checks in with, default https://lease.rystic.ai
RYSTIC_LEASE_CACHEwhere a simulator keeps its last lease for an offline start, default rystic/leases under your config directory
RYSTIC_LEASE_VERBOSEtrue prints one line per check-in; run -v sets it
RYSTIC_DOCS_ENDPOINTthe site docs -online reads
RYSTIC_CLI_ENDPOINTwhere update and self-update look for a newer CLI, default https://www.rystic.ai/api/cli-release
RYSTIC_LICENSE_PUBKEYa license public key to verify against instead of the built-in one (-pub on the command line)
DOCKER_CONFIGwhere status and doctor look for your Docker login, as Docker does; only the entry names are read
CIany value suppresses login’s offer to start a simulator
RYSTIC_BINinstaller: where it puts rystic
RYSTIC_VERSIONinstaller: which CLI version to install, default latest

RYSTIC_TOKEN, RYSTIC_LEASE_URL, RYSTIC_REGISTER_WAIT, RYSTIC_LEASE_CACHE and RYSTIC_LEASE_VERBOSE reach the simulator, including a --runner docker container, when they are set.

The simulator binary also reads these variables. With the default image command, rystic run inherits them or sets them from the corresponding CLI flags:

VariableMeaning
RYSTIC_ADDRdirect simulator listen address (--addr); rystic run sets it from --port / RYSTIC_PORT
RYSTIC_SCENARIOboot into a named scenario (--scenario)
RYSTIC_SEEDboot seed file (--seed)
RYSTIC_NETWORKoff, on, or a profile file (run --network); Pro and Enterprise
RYSTIC_EGRESS_RETAINegress frames kept, default 100000 (run --egress-retain)
RYSTIC_EVENTSevent feed scope (--events)
RYSTIC_SEED_GATEreject refuses an incomplete seed instead of serving it with a warning
RYSTIC_GATEWAY_TOKENfor a simulator behind your own proxy: the bare binary, or a container with a health check of its own. Every request, /_rystic/version included, must carry X-Rystic-Gateway-Token with this value or gets 403. rystic run’s readiness probe and the image’s HEALTHCHECK send no header, so run -d times out (exit 7) and the stock image never reports healthy

Control plane and plans lists every simulator variable, its default and which ones a plan gates.

Kalshi-only variables — RYSTIC_LIVE*, KALSHI_KEY_ID, KALSHI_PRIVATE_KEY_*, KALSHI_CAPTURE_DIR — are on the Kalshi page.

Exit codes

Stable — script against them.

CodeMeaning
0ok
1error
2usage
3license (Enterprise): missing, unreadable, unsigned, expired or for another product. Also no license and no usable API key (none, or not shaped rys_…) when pull or update asks for a build, or run does because the simulator is not installed yet
4network
5not found: not installed, no matching release asset, or no such doc, section or SCENARIOS.md (docs)
6integrity
7simulator unhealthy
8runtime unavailable
9conflict (port or name in use, or the file scenario save would write exists)
10update available (-check)
11API key: missing or malformed when run starts an installed Free or Pro build, or refused by the release endpoint: invalid_token, revoked, org_deleted, key_expired, product_not_in_plan. A new key or a bigger plan fixes it; a retry does not

A simulator stopped by its lease (monthly limit, spend cap, revoked key) exits 1 with the reason on stderr, and a foreground run hands that back.

Next

  1. Docker — pull, compose, CI.
  2. Simulators — one page per API: Anthropic, Clerk, Dropbox, GitHub, Gmail, Google Drive, Kalshi, Linear, Lob, Notion, Okta, PayPal, Resend, S3, Shopify Storefront, Slack, Stripe and Word.
  3. Control plane and plans — every /_rystic route and the plan that serves it.

What leaves your machine

On Free and Pro, the simulator checks in with https://lease.rystic.ai while it runs: at start, every 30 seconds, and on exit, carrying your API key and the 30-second windows in which it was in use. Never your requests, their contents, your data or your hostname. Plans and API keys lists every field. An Enterprise simulator makes no outbound calls. (One exception, Enterprise included: the Kalshi simulator’s replayed-market metadata fetch, documented on its page.)

The CLI itself calls Rystic only in these cases:

WhenWhereWhat it sends
pull, update, status (its update check; --offline skips it), run or up when a simulator is not installed yet (for a Docker service, only to learn the latest version), and ui when its verified UI is not installed yethttps://www.rystic.ai/api/twin-releaseyour API key or license, the product, version, OS, architecture, which command asked and, for ui, artifact: "ui"
list, and the start offer after a license loginhttps://www.rystic.ai/api/catalogthe license
update and self-updatehttps://www.rystic.ai/api/cli-releaseOS, architecture and the version asked for; no credential
update, self-update and install.sh, after cli-release answershttps://release-assets.githubusercontent.comnothing: a download of the short-lived URL cli-release returned
login with no key (which install.sh runs)https://www.rystic.ai/api/device/statusthe API key the CLI generated, polled until someone approves its /device link; the link you open carries only the key’s hash, its prefix and a name for the machine
doctor and status (not with --offline)https://registry.rystic.ai/v2/nothing: an anonymous request to see whether the registry answers
loginregistry.rystic.ai, through your local docker loginthe key or license as the registry password
run --runner docker, up with Docker services, and ui when Docker answersregistry.rystic.aian image pull, with the key or license as the credential
batch --runner docker, when its --image is not on the machine yetthe registry that image namesan image pull, with whatever your docker login holds for that registry
export composeregistry.rystic.aithe license, to look up each image’s digest (--no-digest skips it)
feedbackhttps://www.rystic.ai/api/feedbackyour API key, the report as typed, the CLI’s version, OS, architecture and container engine, and each running simulator’s product, version, name and status; never an env file, a request body or a key’s value
docs -onlinehttps://www.rystic.ai (RYSTIC_DOCS_ENDPOINT)nothing: it reads llms.txt and the pages’ .md

rystic docs without -online, ps, logs, stop, features, config and help stay on the machine.

A live feed adds the source API itself: the CLI dials it from your machine — see Kalshi → Live mode.

Last updated on