Skip to content

CLI

chorus is the terminal control plane for a Chorus instance — a citty app whose subcommands are lazy-loaded so each one frames the same business-logic seam the HTTP and MCP transports do (packages/cli/src/main.ts:34-72).

Terminal window
chorus whoami # who the API key resolves to
chorus status # instance health + counts
chorus --help # full command tree

Declared on the root command (main.ts:13-33) and accepted by every subcommand:

Flag Alias Effect
--profile -p Use a named profile from ~/.chorus/config.yaml
--json Emit raw JSON instead of formatted tables
--verbose -v Verbose output (adds detail; e.g. status -v fetches /health/detailed)
--quiet -q Errors only

--profile and --verbose are also captured pre-parse into env (CHORUS_CLI_PROFILE, CHORUS_CLI_VERBOSE) so they resolve even before citty parses a subcommand (global-flags.ts:4-29).

The root command lazy-loads the groups below; rings is a top-level alias of org rings.

Command What it does
init [url] Connect to / scaffold an instance; writes a profile (init.ts:46-216)
login Authenticate; save API key + URL to a profile (login.ts)
whoami Resolve the current authenticated identity
status Instance health + stat counts (--next for recommended action)
resume / briefing / work / handoff Orientation + workflow helpers (workflow/* RPC)
emit / inbox / signals Signal coordination and the personal Current/Later Inbox
identity / org / rings / circles Identities, roles, rings, fills, circles
memory Typed memory graph — query/list/store/note/remember/improve/recall/forget/stats
tasks RFC-291 native execution plus dependency-add/list/update/remove and bounded graph diagnostics
workstreams / workspace / artifacts Long-lived context, files, blobs
approvals Approval gates (trust boundary)
library ask / eval over the knowledge library
admin API keys, webhooks, audit, RFC-291 ops, executor-kinds, policies, generation leases, and object-storage reconciliation
adapter github <issue-url> ingest adapter

chorus approvals create now uses requester-bound execution by default, followed by approvals execution begin-bound / finish-bound; nothing must be copied from the approver. Pass --requester-bound-attempt <id> only when you need to choose the stable attempt ID. --bearer-delegation is the advanced path for a different executor and may print a one-time token box when approval commits. Save that token at once: later get, events, or idempotent retry commands cannot recover plaintext.

The CLI is a subset of the SDK: execution sub-domains (runs, deliveries, checkouts, dispatchers), most memory-graph methods, and several signal/identity methods have no CLI command and are SDK- or MCP-only (.audit inventory-sdk-cli §3 G2).

Roles use the server’s canonical definition fields. --domains and --duties accept comma-separated values; roles have no ring or capability field:

Terminal window
chorus org roles create --name founder \
--purpose "Set strategic direction" \
--domains strategy,capital \
--duties "set direction,allocate resources"
chorus org roles update role:abc123 --domains strategy,operations
chorus org fills list --identity identity:abc123
chorus org fills list --role role:abc123

Fill listing is intentionally filtered. Passing neither --identity nor --role returns an empty list instead of materializing every identity-role assignment.

API-key creation sends the canonical owner, structured permissions, and top-level ring_scopes fields:

Terminal window
chorus admin api-keys create --identity identity:abc123 \
--signal-types pulse,alert \
--task-types review \
--memory-scopes query,list \
--ring-scopes dev \
--expires 7d

--memory-scopes names memory actions, not namespaces. --ring-scopes accepts existing ring names or canonical ring:... IDs and the server stores canonical IDs. Each omitted permission dimension is stored as an empty array, which means unrestricted for that dimension. The obsolete --scopes and inert --rings flags are not accepted; the server rejects their corresponding unknown fields rather than silently issuing an unrestricted key.

Task dependencies are managed through relation commands; do not try to patch the generated blocked_by or blocks arrays:

Task IDs are exact, untrimmed task:<suffix> record IDs of at most 500 characters. The suffix must be nonempty, its first character cannot be :, and the full ID cannot contain JavaScript or Unicode whitespace. Relation IDs follow the same contract with the exact task_dependency: prefix; later colons inside either suffix are allowed.

Terminal window
chorus tasks dependency-add task:dependent --blocker task:blocker
chorus tasks dependency-list task:dependent
chorus tasks graph task:dependent
chorus tasks dependency-remove task_dependency:edge
# External observation
chorus tasks dependency-add task:deploy --external-system github --external-id owner/repo#42
chorus tasks dependency-update task_dependency:edge --observed-state merged

Administrators migrate active pre-generation leases through a durable, resumable sequence:

Terminal window
chorus admin leases status
chorus admin leases inventory
chorus admin leases quiesce
# wait until the returned wait_until (at least four hours)
chorus admin leases drain --limit 100 # repeat until remaining=0
chorus admin leases verify
chorus admin leases enforce

Stop or upgrade every old server, dispatcher, and worker before quiesce; old binaries cannot honor the durable admission flag. The CLI will not accept a rollout maximum below the protocol minimum of 14400000 ms. Quarantine is terminal and never fabricates a generation for legacy work. See Database & migrations for the full runbook.

Config lives at ~/.chorus/config.yaml (written 0600) as a map of named profiles plus a default_profile (config.ts:42-96). Resolution per call (config.ts:42-77):

  1. Load the profile — --profile <name>, else default_profile, else default.
  2. If a profile was named explicitly, use its saved url/api_key verbatim.
  3. Otherwise (the default profile) CHORUS_URL / CHORUS_API_KEY env vars override the file.
  4. URL falls back to http://localhost:3000; a missing API key raises “No API key found”.
Terminal window
# One-shot, no config file:
CHORUS_URL=https://chorus.example.com CHORUS_API_KEY=sk-... chorus whoami
# Or save a profile and select it:
chorus login --api-key sk-... --url https://chorus.example.com --profile prod
chorus status --profile prod
chorus logout --profile prod

chorus init <url> --api-key <key> and chorus login both save the profile and then verify it against /health, but save the credentials regardless of whether verification succeeds — you get a warning, not a failure (init.ts:76-105, login.ts:82-106). There is no CLI command to obtain a key; first-key bootstrap is server-side (.audit inventory-sdk-cli §5).

chorus logout first calls POST /auth/logout with the selected profile key. Only after the server confirms revocation does it erase that profile’s local key; sibling profiles are untouched. If revocation fails, the local key is retained for a retry. A CHORUS_API_KEY environment override cannot be erased by the CLI, so unset it in the shell after logout.

Chorus does not implement or proxy OpenAI’s OAuth flow. Use the official Codex CLI browser login to seed a file-backed ChatGPT session. Use an isolated CODEX_HOME so the resulting refresh-token chain is owned only by the Chorus consumer that receives it:

Terminal window
seed_dir="$(mktemp -d)"
CODEX_HOME="$seed_dir" codex --config 'cli_auth_credentials_store="file"' login
CODEX_HOME="$seed_dir" codex --config 'cli_auth_credentials_store="file"' login status
install -m 600 "$seed_dir/auth.json" /var/lib/chorus/codex/library/auth.json

Set LLM_CODEX_AUTH_FILE=/var/lib/chorus/codex/library/auth.json for the synthesis lane, or seed a separate file such as /var/lib/chorus/codex/audit/auth.json and set LLM_AUDIT_CODEX_AUTH_FILE for the audit lane. The parent directory must be owner-only and writable by Chorus because refresh replaces the file atomically and uses a sibling lock. Seed every Chorus consumer independently, remove the isolated seed directory after transfer, and never point Codex, Hermes, and Chorus at the same credential file. It contains live credentials: do not commit it, paste it into tickets, or expose it in logs. The official Codex authentication guide documents codex login, codex login status, CODEX_HOME, file-backed auth.json, and cli_auth_credentials_store.

chorus --version is compiled from packages/cli/package.json; the executable has no runtime package-file lookup. chorus status renders the server’s flat signal_count, identity_count, role_count, ring_count, and memory_count fields.