CLI reference
The desktop and CLI share workflow contracts. Use the CLI when you want reviewable commands, machine-readable diagnostics, or an external automation entry point.
Find commands
Raticode --help
Raticode rattish --help
Raticode rattish docs --format jsonThe CLI command index lists every command with its options, generated from the CLI itself.
The last command prints where the installed language documentation, grammar, node contracts and schemas are. These files describe the installed compiler without requiring a source checkout. Raticode schema prints the same paths.
Scripting conventions
- Commands that print records, such as lists and status, accept
--format json. Commands that had a--jsonflag keep it as a shorter spelling, and theremlists also accept--format table. - There are two JSON shapes. Commands that work on files in the data folder, such as
rattish listorrunner list, print the bare data with--format json. Commands that talk to a running backend print a JSON envelope by default, with the data underdata(see Output and exit codes). - Data goes to stdout. Errors and warnings go to stderr, so
Raticode … --format json | jqnever receives an error message as JSON input. - Exit code 0 means success and 1 means the command failed. Exit code 2 means the command was used wrongly: an unknown option or format, an invalid input, or a Rattish workflow given to a command that only reads legacy TOML workflows (see below).
- The data folder is
GOFER_DATA_DIRwhen it is set (the desktop app sets it when you choose a custom folder), otherwise the standard one, such as~/.local/share/goferon Linux. Most commands also take--data-dir.
Rattish commands
| Command | Purpose | Executes nodes? |
|---|---|---|
Raticode rattish create "Name" --project PATH --format json | Register a workflow and return its allocated ID and source path | No |
Raticode rattish list --format json | List registered Rattish workflows | No |
Raticode rattish format PATH | Format an existing source file | No |
Raticode rattish check PATH --format json | Parse and perform static checks | No |
Raticode rattish compile PATH --format json | Compile validated source to JSON IR | No |
Raticode rattish inspect-ir PATH --pretty | Print the compiled representation | No |
Raticode rattish preflight PATH --format json | Check required runtime resources | No |
Raticode rattish run PATH --format json | Execute the workflow | Yes |
Raticode rattish triggers add cron|file|webhook PATH ... | Start the workflow on a schedule, file change, or local webhook. See Triggers | Later, when it fires |
Run help on an individual command for its current options; most also take --data-dir to use a different data folder. PATH is the source file; use the exact source path returned by create for a registered workflow.
format edits its target. Other authoring and inspection commands do not execute workflow nodes. Run can write files, call providers, and contact services, according to the authored source.
Inputs and limits
Raticode rattish run WORKFLOW_PATH --input 'message="Hello"' --format jsonInput values after = are JSON. Repeat the option for multiple public inputs. Check the input schema and workflow limits before running it. The inputs guide contains a complete example.
For shell automation, preserve the exit status and machine-readable result. Do not treat a printed message as proof that every node succeeded. A failed request with an uncertain external outcome may need inspection before retrying.
Provider profiles and health
Raticode provider --help
Raticode provider profile list --format json
Raticode provider profile create NAME --subscription codex --model MODEL
Raticode provider profile edit NAME --model MODEL
Raticode provider profile rm NAME
Raticode doctor --jsonProvider profiles are reusable deployment settings. Discover supported subscription and permission options in Raticode provider profile create --help; edit replaces only the values you pass, and rm asks first unless you add --yes. Authenticate native CLIs separately. A profile does not override a Rattish node's explicit provider, model, or effort.
Doctor checks installation health, and reports whether the Organizations Feature Preview is turned on in the current environment. Its workflow-specific legacy option is not a replacement for Raticode rattish preflight.
Other command families
| Family | Guide |
|---|---|
Raticode rattish triggers | Triggers |
Raticode schedule | Schedules |
Raticode watch | File watchers |
Raticode runner | Runner queue |
Raticode workflow run PATH | Runs a .rattish file, a workflow folder or a registered ID; --dry-run runs preflight only, and Raticode workflow resume --run-id ID resumes a run |
Raticode rem | Rem from the CLI for chat, tasks, memories, alerts and settings; Tools, skills and MCP for the skill and MCP library |
Raticode tickets, Raticode selfwork | Tickets and self-work from the CLI |
Raticode rattish start, stop, resume, runs, logs, approve and the other "(Backend)" commands; Raticode org, Raticode swarm, Raticode brain, Raticode usage, Raticode projects, Raticode devices, Raticode threads; Raticode provider list, models, status and set | Workflows, Organizations and more from the CLI: runs, approvals and trigger files through the backend, Organizations, swarms, Second Brain, providers, usage and live threads, with settings as files |
Raticode schema | Prints where the Rattish docs, contracts and schemas are installed; --legacy-toml prints the old TOML authoring contract |
Raticode serve --headless | Runs the backend with no desktop window. See Headless backend |
Raticode tokens | Creates, lists and revokes limited agent tokens. See Agent tokens |
Raticode licenses --output DIR | Exports the third-party notices bundled with this build |
Raticode ui serve | Runs the backend the desktop app starts (port 8765 by default); the same as Raticode serve. It writes no token file and Rem waits for a window, so for scripts and servers use Raticode serve --headless |
Legacy TOML commands
Raticode workflows used to be TOML files. Some commands still read only that format, and their help starts with [Legacy TOML]. New workflow source belongs in workflow.rattish.
These Raticode workflow commands accept a Rattish workflow ID, folder or .rattish file:
| Command | With a Rattish workflow |
|---|---|
run, resume | Runs or resumes it, like Raticode rattish run |
list | Lists Rattish and TOML workflows |
validate | Runs Raticode rattish check |
plan | Runs Raticode rattish preflight |
logs list, logs show, logs latest, logs prune, usage | Reads its run history |
export | Writes a .raticode archive; import FILE.raticode --project PATH installs one |
rm, rename, duplicate | Works as in the app |
approvals, approve and reject work with approval gates of legacy TOML workflows. For a Rattish workflow's gates, use Raticode rattish approvals, approve and reject through the backend. Only you can decide a gate: inside a Rem or worker turn, workflow approve and reject refuse with exit 5 and change nothing, so a workflow can't approve its own gate. --by is not your name. It picks which of the gate's listed approvers you decide as, and it is refused when the gate lists none or the name isn't on its list. Without it the decision is recorded as made from the CLI.
rm, rename and duplicate work with TOML workflows too. When a headless backend is running for the same data folder, they ask it to make the change, so only the backend writes the workflow files and it updates schedules and continuous runs straight away. Inside a Rem or worker turn that request needs an agent token, and without one it fails with exit 5 instead of changing the files. With no headless backend running, they change the files themselves, as before. The desktop app's own backend doesn't publish its address, so with only the app open they also change the files themselves.
The other workflow commands (show, edit, build, create, recipe, set-info, add-node, add-edge, add-agent, rm-node, rm-edge, set-schedule, clear-schedule, set-watch, clear-watch, trigger, secrets, stop, history, diff, restore, preview-import) work only with TOML workflows. Given a Rattish workflow, they change nothing, exit with code 2 and print the Rattish command to use instead, such as Raticode rattish inspect-ir for show or Raticode rattish triggers add cron for set-schedule.
The Raticode agent, Raticode schedule, Raticode watch and Raticode runner groups are also legacy. Use triggers for schedules and file watching, and check the guides above before using the others. They refuse a Rattish workflow the same way, with exit code 2 and the command to use: agent list --workflow points to Raticode rattish inspect-ir, runner queue to Raticode rattish run or Raticode rattish start, and schedule add to Raticode rattish triggers add cron. watch only reads TOML workflows in the data folder and ignores Rattish ones. agent list, watch list, runner list and workflow approvals accept --format json.
Raticode workflow trigger reads a webhook token from --token-file PATH (a file only you can read) or from RATICODE_WEBHOOK_TOKEN. Its old --token option still works but is deprecated and prints a warning, because other accounts can read command lines. In the same way, workflow add-node --notification-smtp-password expects a secret reference such as secret:SMTP_PASSWORD and warns when it is given a password.
Talk to a running backend
New in 0.5.3
Raticode api, Raticode wait and Raticode completion arrived in Raticode 0.5.3. So did the resource commands built on them: Rem, tickets and self-work and workflows, Organizations and more.
The commands above work on files. Everything stateful in the app (Rem, tickets and the global board, self-work, Organizations, swarms, run control) lives in the backend, so scripts reach it through the backend's local API, the same one the desktop window and the phone use. The CLI never opens those stores itself. The CLI finds a headless backend on its own. It can't find the desktop app's backend yet, because the app doesn't publish its address or token, so these commands can't reach it while only the desktop app is running.
Raticode api METHOD PATH calls any endpoint, like gh api. Paths are relative to /api:
Raticode api GET /health
Raticode api GET /rem/kanban | jq '.data.self_work'
Raticode api POST /rem/kanban/ticket -f action=create -f title="Fix flaky test" --request-id t-123
Raticode api PUT /rem/kanban/settings -F max_threads=3 --expected-revision 0
Raticode api POST /organizations --data @configure.json --expected-revision 7| Option | What it does |
|---|---|
-d, --data JSON | Request body. @file reads a file and @- reads stdin. |
-f, --raw-field key=value | A string field. For GET and DELETE it becomes a query parameter; otherwise it goes in the JSON body. Dots nest: params.taskId=t1. |
-F, --field key=value | Like -f, but true, 3, null or [...] are sent as JSON values, and @file reads the value from a file. |
--request-id ID | An idempotency key, sent as request_id. Only some endpoints deduplicate on it (listed below); for those, retrying with the same ID returns the first result instead of doing the work again. Other endpoints ignore it. auto makes one and prints it in the result. |
--expected-revision REV | Refuse the change (exit 4) if the record changed since you read it. Sent as expected_revision on /rem/... paths and expectedRevision elsewhere (inside params for Organizations). |
--follow | Stream an NDJSON endpoint such as /chat/events, or keep polling a GET that returns an events list such as /rem/events. |
--timeout 30s | Give up after this long. With --follow it limits the whole follow. |
--raw | Print the response body as it came, without the envelope. |
Finding the backend and its token
The CLI only talks to a backend on this computer: 127.0.0.1, ::1 or localhost. It refuses any other address. Raticode's backend listens only on TCP, not on a Unix socket. To reach a backend on another machine, forward its port with ssh -L and point the CLI at the local end.
api and wait have no --token option, because other accounts on a computer can read command lines. They look for the backend and token in this order:
| Looked up in order | |
|---|---|
| Address | --endpoint http://127.0.0.1:PORT, then RATICODE_URL, then <data folder>/headless/endpoint.json, then http://127.0.0.1:8765 |
| Token | --token-file PATH, then RATICODE_TOKEN, then RATICODE_TOKEN_FILE, then the token file named in endpoint.json, then <data folder>/headless/owner-token |
| Data folder | --data-dir, then RATICODE_DATA_DIR, then GOFER_DATA_DIR, then the standard folder |
A token file has to belong to you and be readable only by you (chmod 600), and endpoint.json must not be writable by anyone else, since it decides where the token is sent. The CLI refuses them otherwise. On Windows the CLI doesn't check these permissions; see Headless backend. Inside a Rem worker or another provider turn that Raticode started (where RATICODE_AGENT_SESSION is set), the CLI never picks up the owner token from the data folder, and it accepts only a limited agent token from any source. An owner token in RATICODE_TOKEN, RATICODE_TOKEN_FILE or --token-file is refused there with exit 5 (error code owner_token_in_agent_session).
Raticode serve --headless publishes headless/endpoint.json and headless/owner-token in the data folder, so the CLI finds it with no setup. For scripts that shouldn't act as you, give the CLI a limited agent token with --token-file. Raticode ui serve on its own takes its token from GOFER_UI_API_TOKEN, or makes a new random one each time it starts and writes it nowhere. In that case, start it with a token you keep in a private file and give the CLI the same file:
umask 077
python3 -c 'import secrets; print(secrets.token_urlsafe(32))' > ~/.config/raticode-token
GOFER_UI_API_TOKEN="$(cat ~/.config/raticode-token)" Raticode ui serve &
Raticode api GET /rem/tasks --token-file ~/.config/raticode-tokenYou can also export RATICODE_TOKEN_FILE in your own shell instead of passing --token-file. Raticode removes RATICODE_TOKEN and RATICODE_TOKEN_FILE from everything it starts (Rem's workers, providers and workflow commands), so they don't inherit your token even if you start the app from that shell.
Output and exit codes
Each command prints one JSON object on stdout, and messages for people go to stderr:
{"ok": false, "command": "api", "data": null,
"error": {"code": "conflict", "message": "This ticket changed. Check it and try again.", "http": 409},
"warnings": [], "request_id": "t-123"}request_id is there only when the command sent one. With --follow, the output is one JSON object per line: {"kind": "event", "data": ...} for each event, then the result object above with "kind": "result" as the last line. --output ndjson gives the same line format for any command, and --output text prints readable output. --format is accepted as another name for --output.
| Exit | Meaning |
|---|---|
| 0 | Done |
| 1 | The operation ran and failed, or the backend had an internal error |
| 2 | Invalid arguments or input (HTTP 400, 422) |
| 3 | Not found (HTTP 404) |
| 4 | Conflict or stale --expected-revision (HTTP 409) |
| 5 | Missing, rejected or unsafe token, or forbidden (HTTP 401, 403) |
| 6 | No backend answered |
| 7 | Waiting on you: an approval, consent or answer is pending |
| 8 | Timed out, or the request may or may not have taken effect |
These endpoints deduplicate on request_id:
- Rem:
POST /rem/messages,POST /rem/tasks,PATCHandDELETE /rem/tasks/ID,POST /rem/tasks/ID/runand/pause,POST /rem/runs/ID/cancel,/acknowledgeand/retry_review, andPOST /rem/threads/ID/messages - The board:
POST /rem/kanban/ticketwithactioncreateorcomment
A request that never reached the backend is always retried. Once a request has been sent, the CLI resends it automatically after a timeout, a dropped connection or a busy backend only if it is a read, or carries a request ID to one of the endpoints above. Everything else, such as starting a workflow run, is sent once: if the answer is lost, the command exits 8 and you should check whether it happened before trying again. On exit 8 from one of the endpoints above, retry with the same --request-id instead of a new one. Existing rattish commands keep their own codes, where 2 also means a source file couldn't be read.
Waiting for a state
Raticode wait PATH polls a GET endpoint until a field reaches a final state:
Raticode wait /rem/runs/RUN_ID --field run.state \
--success succeeded --failure failed,cancelled,outcome_unknown --needs-user blocked \
--timeout 30mIt exits 0 for a --success state, 1 for --failure, 7 for --needs-user and 8 when the timeout passes first. The last response is in data. If the backend restarts while you wait, wait keeps trying until the timeout.
Scripts and shell completion
The CLI never prompts when it is given --non-interactive (Raticode --non-interactive ...), when RATICODE_NON_INTERACTIVE=1 or CI=true is set, or when stdin isn't a terminal. A command that would ask for confirmation then fails with exit 2 unless you pass --yes.
Print a completion script for your shell with Raticode completion bash, zsh, fish or powershell. It completes commands and options, and for Raticode api the method and the API paths that have CLI coverage:
Raticode completion bash > ~/.local/share/bash-completion/completions/Raticode
Raticode completion zsh > "${fpath[1]}/_Raticode"
Raticode completion fish > ~/.config/fish/completions/Raticode.fishRaticode --install-completion installs it for the current shell instead.
