CLI
cymatics: every API operation from your terminal, plus browser login, a local simulator, scenario control and webhook forwarding. Built for people and agents alike.
Install
Requires Node.js 20.19 or later. Check it with cymatics --version.
Log in
cymatics login opens the dashboard in your browser. Confirm there and the CLI receives a new key on a one-time local callback. It checks the key with GET /v1/project before saving it to profiles.json, readable only by you. In CI, pipe an existing key to --key-stdin so it never appears in your shell history.
$ cymatics login # confirm in the browser
$ cymatics login --live # a live key instead
$ cymatics login --no-browser # print the URL instead
$ printf '%s' "$KEY" | cymatics login --key-stdin --profile ciProfiles and modes
Test mode is the default; --live selects live credentials. The key comes from, in order, CYMO_TEST_API_KEY or CYMO_LIVE_API_KEY, then CYMO_API_KEY, then the selected profile. The API decides a key's project and mode, and the CLI rejects responses from the other mode.
$ cymatics auth status # verify the key online
$ cymatics auth status --offline # which key, no request
$ cymatics projects current # the key's project
$ cymatics profiles list # never shows the keys
$ cymatics profiles use staging # the new default
$ cymatics logout --profile stagingQuickstart
$ cymatics login
$ cymatics vitals get --room room_bedroom --json
$ cymatics vitals stream --room room_bedroom --max-events 3Commands
Commands are cymatics <group> <action>, generated from the API contract, so they always match the API reference. Parameters are flags in kebab case, such as --room-id or its alias --room. A single path parameter can be passed positionally. cymatics api runs any operation by its ID.
$ cymatics rooms get --room room_bedroom --json
$ cymatics results list --room room_bedroom --limit 100 --paginate
$ cymatics webhooks create --input webhook.json \
--idempotency-key "$(uuidgen)"
$ cymatics api get-room --room room_bedroom --dry-runcymatics project | get |
cymatics capabilities | list |
cymatics models | list, get |
cymatics sensing-profiles | list |
cymatics retention-profiles | list |
cymatics coordinate-frames | list |
cymatics skeleton-definitions | list |
cymatics rooms | list, create, get, update, archive, zones get, zones replace, calibration get, calibration replace, processing-config get, processing-config replace, stream |
cymatics devices | list, get, update, health, sensing-config get, sensing-config replace, observations list, raw-stream |
cymatics scenes | list, create, get, update, delete |
cymatics vitals | get, history |
cymatics presence | get |
cymatics movement | get |
cymatics stress | get |
cymatics skeleton | get |
cymatics classifications | get |
cymatics results | list |
cymatics people | results list, stream |
cymatics sleep | sessions list, summary get |
cymatics activity | summary get |
cymatics analyses | list, get |
cymatics events | list |
cymatics webhooks | list, create, get, update, delete, test, deliveries list |
cymatics scenarios | list, run |
cymatics scenario-runs | get, control |
cymatics raw-data | exports create, exports get, exports download |
cymatics usage | get |
cymatics request-logs | list |
Flags and output
Results go to stdout as JSON, the same envelope as the API; streams and listen print one NDJSON line per message. A failure prints one {"error": {"code", "message"}} object on stderr and nothing on stdout.
--test, --livedefault --test | Choose the mode's credentials. Both at once is an error. |
--profile <name> | Use a saved profile instead of the default one. |
--json | Print the response envelope as JSON on stdout. |
--input <file|-> | The JSON request body, from a file or stdin. Invalid input fails before any request. |
--dry-run | Validate and print the request, with the key redacted, without sending it. |
--paginate | Print every page, one envelope each, until the cursor stops advancing. |
--max-events <n>, --duration-ms <ms> | Bound a stream or listen; it then exits 0. |
--agent | Bound a stream to ten events or ten seconds, whichever comes first. |
--read-only | Refuse any command that writes. The API still enforces the key's scopes. |
--idempotency-key <key> | Make a write safe to retry: the API replays the first response. |
--timeout-ms <ms> | Per-request timeout. |
--output-file <path>, --max-bytes <n> | Write binary data to a new file, up to a size limit. |
--base-url <url>default https://api.cymatics.tech | The API origin: HTTPS, or HTTP on loopback. |
Streams and downloads
Stream commands run until Ctrl-C unless you bound them with --max-events or --duration-ms. Binary data is only ever written to a new --output-file.
$ cymatics rooms stream --room room_bedroom --max-events 5
$ cymatics vitals stream --room room_bedroom --duration-ms 10000
$ cymatics raw-data exports download EXPORT_ID \
--output-file capture.bin --max-bytes 1048576Local simulator
cymatics mock start runs the real API gateway on 127.0.0.1 with the test simulator, in memory and offline. It has built-in keys: cym_test_local with every scope, cym_test_readonly with results:read, and cym_test_other for a second project.
$ cymatics mock start --port 8787
# in another terminal
$ export CYMO_API_URL=http://127.0.0.1:8787
$ export CYMO_TEST_API_KEY=cym_test_local
$ cymatics rooms get --room room_bedroom --jsonScenarios
Start a preset or custom timeline with scenarios run, then pause, resume or advance it with scenario-runs control. The run's rooms answer every read and stream. See Scenarios for the presets.
$ echo '{"scenario_id":"bed_exit","seed":42}' | cymatics scenarios run --input -
$ echo '{"action":"pause"}' | cymatics scenario-runs control RUN_ID --input -
$ echo '{"action":"advance","duration_ms":6000}' \
| cymatics scenario-runs control RUN_ID --input -
$ cymatics events list --room ROOM_ID --jsonForward webhooks
listen forwards your project's new events to a local URL (localhost, 127.0.0.1 or [::1]) with the production body and headers, signed with a fresh whsec_ secret it prints first. Verify them with verifyWebhookSignature exactly as in production. Deliveries add Cymo-Forwarded: cli, and --events or --webhook-id filter the types.
$ cymatics listen --forward-to http://localhost:3000/api/cymo-webhook
$ cymatics listen --forward-to http://localhost:3000/hook \
--events bed.exited,fall.detected
$ cymatics listen --forward-to http://localhost:3000/hook \
--webhook-id wh_123 --max-events 10For AI agents
Agents in a terminal can discover everything offline, without a key. agent guide returns the recommended workflow and agent schema every command's JSON Schema with a readOnlyHint. Combine --dry-run, --read-only and --agent to keep an agent's calls safe and bounded. For agents that speak MCP, use the MCP server.
$ cymatics agent guide # workflow, exit codes
$ cymatics agent schema --group rooms # JSON Schemas
$ cymatics schema get-room # one operation
$ cymatics rooms stream --room room_bedroom --agentExit codes
0 | Success, including a stream or listen that ended at its bound or on Ctrl-C. |
1 | API or response error, such as resource_not_found, live_unavailable or an invalid response. |
2 | Invalid arguments or input, an unknown command, an invalid origin or configuration file. |
3 | Credentials or permissions: a missing, invalid, expired or revoked key, 401 or 403, a mode mismatch, or a cancelled or failed login. |
4 | Network: connection failure, timeout, 503 service_unavailable or a login timeout. |
5 | 429: rate_limit_exceeded after the SDK's automatic retries (with retry_after_ms), or quota_exceeded. |
quota_exceeded is never retried: the message says how to raise the key's live-hour cap in the dashboard.
Environment variables
CYMO_TEST_API_KEY, CYMO_LIVE_API_KEY | The key for that mode. Checked first. |
CYMO_API_KEY | A key for whichever mode is selected, checked after the mode's own variable and before saved profiles. |
CYMO_API_URLdefault https://api.cymatics.tech | The API origin, like --base-url. Point it at cymatics mock start to work offline. |
CYMO_SITE_URLdefault https://cymatics.tech | The website that browser login opens, like --site-url. |
CYMO_CONFIG_DIRdefault ~/.config/cymatics | Where profiles.json and config.json live. $XDG_CONFIG_HOME is honoured. |
CYMO_NO_UPDATE_CHECK1 to disable | Skip the daily background check for a newer release. It never runs in CI or when stdout isn't a terminal. |