CLI Conventions
Every Ritual command shares the same global options, the same rules for running without a terminal, the same scripting output formats, and the same exit codes. This page collects them so the command pages do not repeat them.
Global Options
Section titled “Global Options”These options work on every command. Each has an environment variable that does the same job. When both are given, the flag wins. An empty or whitespace-only variable counts as not set.
| Option | Environment variable | Description |
|---|---|---|
--base-dir <path> |
RITUAL_BASE_DIR |
Use this directory instead of the current working directory |
--cache-server <host:port> |
RITUAL_CACHE_SERVER |
Use a remote cache server instead of local cache files |
--no-input |
RITUAL_NO_INPUT |
Never prompt; fail or use documented defaults where input would be required |
--locale <tag> |
RITUAL_LOCALE |
Language for Ritual’s own interface text (BCP-47, e.g. de-AT) |
A few environment variables have no flag:
| Environment variable | Description |
|---|---|
RITUAL_NO_UPDATE_CHECK |
Never look up or announce newer Ritual releases (the update notice) |
RITUAL_STATE_DIR |
Where Ritual keeps its small per-user state file |
RITUAL_ADMIN_SETUP_TOKEN |
Pins the one-time token ritual admin requires to create the first account (First-Time Setup) |
CI |
Marks a CI run: no offer to migrate and no update notice. CI=false (or another off spelling) counts as unset |
RITUAL_NO_UPDATE_CHECK and CI read 0, false, no, and off (any casing) as unset, like RITUAL_NO_INPUT.
--base-dir
Section titled “--base-dir”By default Ritual reads and writes files relative to the directory you run it from. --base-dir points it at a different directory:
# Run from anywhere, but operate on files in ~/my-collectionritual --base-dir ~/my-collection build-site
# Price a deck in a specific project directoryritual --base-dir /projects/mtg price "My Deck"This affects every path: decks, collections, wanted lists, the cache, config files, and the output dist/ directory. Paths in ritual.config.json are resolved relative to it.
RITUAL_BASE_DIR does the same whenever the flag is not passed, so a shell session or a service unit can set the workspace once:
export RITUAL_BASE_DIR=~/my-collectionritual lists # operates on ~/my-collectionritual --base-dir /projects/mtg lists # the flag wins for this one runThe directory must already exist. Ritual never creates a base directory. A path that is missing, or is not a directory, is a usage error (exit code 2), and nothing is read or written:
base directory does not exist: /home/you/my-collectoinbase directory is not a directory: /home/you/notes.txtbase directory is not readable: /srv/private — EACCES: permission denied, stat '/srv/private'The third form covers permission problems and any other filesystem failure while checking the path. Failing early protects you from a typo: a misspelled --base-dir would otherwise look like an empty workspace, and a write would put your data in a stray directory.
--no-input
Section titled “--no-input”Disables every interactive prompt. Use it in scripts, CI, and agents. A command that would normally prompt either fails with a usage error or falls back to a documented default. Each command’s page says which; see for example price, export, and cleanup.
RITUAL_NO_INPUT does the same whenever the flag is not passed, so you can set it once in CI:
RITUAL_NO_INPUT=1 ritual cleanup --skip-formatsritual import ./decklist.txt --type deck --no-inputA falsy value (0, false, no, off, any casing) counts as not set, so an inherited RITUAL_NO_INPUT=1 can be turned off for one run:
RITUAL_NO_INPUT=0 ritual edit "My Deck" # prompts again, despite the CI defaultWhen prompts are unavailable
Section titled “When prompts are unavailable”A prompt cannot run in two situations: --no-input / RITUAL_NO_INPUT disabled prompting, or stdin is not a terminal (piped input, </dev/null, most CI runners). The CLI treats both the same way. No command opens a prompt, spawns a pager, or exits 0 after quietly skipping the work.
Where an answer is required, you get a usage error (exit code 2) naming what was needed: the flag that would have supplied the answer where one exists, otherwise the thing the prompt asked for:
Input required: pass --finish <nonfoil|foil|etched> (no terminal available for prompts).Input required: pass --finish <nonfoil|foil|etched> (prompts are disabled by --no-input / RITUAL_NO_INPUT).Input required: a printing of the card (...)The parenthetical says which cause applied, since the remedies differ: supply the missing flags, or reconsider --no-input.
Interactive-only surfaces refuse to open and point at their headless equivalent: edit, the history editor, move’s session, and dep-license’s picker. license and dep-license <package> print their text to stdout instead of paging it through less.
Where a question has a documented default, that default is used instead of failing. The general rule is that --refresh ask is declined wherever it would prompt. A few commands differ, and their pages say so:
build-sitebulk-downloads an empty or stale card cache without asking, since it cannot build without card data.sellredownloads an already-downloaded Card Kingdom buylist once it is a day old.admin,serve --api, and a sell-modebuild-sitedo the same. Only the first buylist download prompts.collection-syncfails the run instead of skipping.- A text
importwithout--typefalls back to a deck under an explicit--no-input. A merely piped run still errors, since nothing said which type was meant. - A URL
import(andimport-account) without a--sync-printings/--no-sync-printingsanswer behaves the same way: an explicit--no-inputkeeps the source’s exact printings and says so; a merely piped run errors.
Ritual’s update notice is never a question either: a release build prints one stderr line (after the command’s output; at startup for serve and admin) when a newer release exists. It is off without a terminal on stderr, under --output json/ndjson/csv or --quiet, when CI is set, with RITUAL_NO_UPDATE_CHECK set (the same on/off spellings as RITUAL_NO_INPUT), or with updateCheck: false, and it never changes the exit code.
One question is never required: when a workspace has pending updates, Ritual offers to run ritual migrate before the command. Without a prompt (and also when stdout is not a terminal, under --output json/ndjson/csv, --dry-run, --yes, or a set CI variable) it prints one line on stderr instead and runs the command. That line never changes the exit code or stdout, so scripts can ignore it; run ritual migrate --check to test for pending updates explicitly.
--locale
Section titled “--locale”Sets the language of Ritual’s own interface text: output, prompts, menus, help, and errors. It takes a BCP-47 tag (en, de, de-AT, pt-BR). Tags are canonicalized, so --locale de-at and --locale de-AT mean the same thing.
ritual --locale de lists # this one runexport RITUAL_LOCALE=de # this shellritual config set uiLocale de # this workspace, persistentlyPrecedence: --locale → RITUAL_LOCALE → the uiLocale config key → your OS locale → en. Only the flag is strict: a tag naming no known language is a usage error (exit code 2). A bad RITUAL_LOCALE or uiLocale warns and falls through to the next tier.
Run ritual locale to see which tier won, or ritual locale --detect to run the deeper OS probes (Windows/macOS) and optionally save the result as uiLocale.
Scripting
Section titled “Scripting”Most commands that produce data can emit it in a machine-readable form:
# One JSON documentritual price "My Commander Deck" --output json | jq '.totals'
# One JSON object per line, with only the fields you wantritual card --from-file cards.txt --output ndjson --fields name,set,prices.usd
# No prompts, no writesritual import-account johndoe --all --no-input --dry-runA few habits make scripts robust:
- Prefer
--output jsonor--output ndjsonover parsing text. - Use
--fieldsto project a stable subset of the data. - Set
--no-input(orRITUAL_NO_INPUT) in headless environments, and pass--yeswhere a confirmation is required.
--output always means the scripting format
Section titled “--output always means the scripting format”--output text|json|ndjson selects the format the command writes to stdout. It never means a file format or a destination. json emits exactly one document per run, so a batch of card lookups or a multi-page search is still one array. ndjson streams one JSON object per line. text is the human rendering.
Three commands differ:
scryadds--output csv, which Scryfall renders itself.selladds--output csvwith a different payload: Card Kingdom’s sell-cart upload rows, not the report.exporthas no--output. Its stdout payload is the export; choose it with--format csv|json|text|mdand redirect it with--out <file>.
Errors always go to stderr, structured to match the output mode. Under json/ndjson an error is {"error": {"code", "messageKey", "messageParams", "message", "details"}}; under text it is a plain line. code and messageKey never change with the locale, so match on those. message is prose in the UI locale. messageParams is always flat strings and numbers in English: a param that is itself a message, a list or a duration is given as its English rendering, so the pair stays locale-invariant. messageKey and messageParams are omitted when the failure has no message-catalog entry, such as an error quoted verbatim from Scryfall or the filesystem. An unexpected internal failure uses the same envelope with code: "runtime_error", exit code 1, and neither messageKey nor details. stdout stays parseable in every case.
--quiet suppresses chatter, never data
Section titled “--quiet suppresses chatter, never data”--quiet removes progress and status messages: “Reading cards from file…”, “Successfully imported…”, applied counts, confirmations. It never removes:
- the structured payload.
--output json/ndjsonstdout is always emitted, so--quiet --output jsonis a JSON document with nothing around it. For total silence, redirect stdout. - errors, and warnings that mean content was lost: a card line the parser could not read, a change skipped as a conflict, a result set truncated by the page cap. These always print to stderr.
A command with no non-essential output does not register the flag at all. card, diff, scry, cache status, dep-license, history, login status, deck-sync status, and skills list accept --output but no --quiet: everything they print is either the payload or a warning that must survive.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 |
Success |
1 |
Runtime error — the work was attempted and failed |
2 |
Usage error — a bad flag value or an impossible combination, including a malformed --base-dir or --cache-server |
3 |
Not found — a named list, file, card, or other resource does not exist |
4 |
Updates pending — migrate --check found workspace updates to apply, or self-update --check found a newer release |
A closed stdout pipe is not a failure: ritual … --output ndjson | head stops quietly and exits 0, like any standard Unix tool.
The card-ID backfill
Section titled “The card-ID backfill”Every card line in a list file ends in a stable internal ID, the &N suffix (- 1 Sol Ring &5). Ritual manages these IDs; never hand-author or renumber them. When a file is missing IDs, typically after a hand edit, Ritual fills them in before running any command that rewrites card lines or needs every line to carry an ID:
- the editors:
edit,history’s editor mode,admin(the server itself, not itssetup/reset-password/disable-totpsubcommands),mcp, andserve --build/--api; - the one-shot card commands:
add-card,remove-card,set-card,note, andmove; - the importers and syncs:
import,import-account,import-changes,deck-sync pull/deck-sync push(not the read-onlydeck-sync statusor the front-matter-onlydeck-sync link), andcollection-sync; - the whole-workspace passes:
cleanupandbuild-site; set-list-image, whenever the run can name an&N:--card, or no mode flag at all (the wizard). Never for--file,--url, or--default.
No other command triggers the backfill, so no other command rewrites the card lines in your list files:
- the read-only commands (
lists,diff,price,sell,export,get-primer,history --show,list-all-cards,scry,card, …); - the lifecycle commands
new,rename, anddelete, which create, move, or trash list files but never touch card lines; - the front-matter-only
metadatacommand and the front-matter-only modes ofset-list-image; - the
categoriescommand, which writes only the categories file; detect-changes, in all three of its modes, since a backfill would rewrite the very files it is inspecting (--hash-onlystill writes.sha256files, as that is its job).
-n/--dry-run also skips the backfill: a dry run writes nothing.
The backfill never hides a hand edit from change tracking. It refreshes a file’s .sha256 companion file only when that hash already matched the file, so detect-changes still sees your edits and records their changelog entries.
Ritual is unofficial Fan Content permitted under the Fan Content Policy. Not approved or endorsed by Wizards of the Coast. Portions of the materials used are property of Wizards of the Coast. ©Wizards of the Coast LLC.
Card data, images and symbols come from Scryfall, which is not affiliated with this project. Ritual is free software under the AGPL-3.0. License and attribution.