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).
chorus whoami # who the API key resolves tochorus status # instance health + countschorus --help # full command treeGlobal flags
Section titled “Global flags”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).
Command groups
Section titled “Command groups”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).
Organization contracts
Section titled “Organization contracts”Roles use the server’s canonical definition fields. --domains and --duties accept
comma-separated values; roles have no ring or capability field:
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,operationschorus org fills list --identity identity:abc123chorus org fills list --role role:abc123Fill listing is intentionally filtered. Passing neither --identity nor --role returns an
empty list instead of materializing every identity-role assignment.
API-key permissions
Section titled “API-key permissions”API-key creation sends the canonical owner, structured permissions, and top-level
ring_scopes fields:
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.
chorus tasks dependency-add task:dependent --blocker task:blockerchorus tasks dependency-list task:dependentchorus tasks graph task:dependentchorus tasks dependency-remove task_dependency:edge
# External observationchorus tasks dependency-add task:deploy --external-system github --external-id owner/repo#42chorus tasks dependency-update task_dependency:edge --observed-state mergedGeneration-lease rollout
Section titled “Generation-lease rollout”Administrators migrate active pre-generation leases through a durable, resumable sequence:
chorus admin leases statuschorus admin leases inventorychorus admin leases quiesce# wait until the returned wait_until (at least four hours)chorus admin leases drain --limit 100 # repeat until remaining=0chorus admin leases verifychorus admin leases enforceStop 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.
Targeting an instance
Section titled “Targeting an instance”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):
- Load the profile —
--profile <name>, elsedefault_profile, elsedefault. - If a profile was named explicitly, use its saved
url/api_keyverbatim. - Otherwise (the default profile)
CHORUS_URL/CHORUS_API_KEYenv vars override the file. - URL falls back to
http://localhost:3000; a missing API key raises “No API key found”.
# 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 prodchorus status --profile prodchorus logout --profile prodchorus 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.
Codex provider credentials
Section titled “Codex provider credentials”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:
seed_dir="$(mktemp -d)"CODEX_HOME="$seed_dir" codex --config 'cli_auth_credentials_store="file"' loginCODEX_HOME="$seed_dir" codex --config 'cli_auth_credentials_store="file"' login statusinstall -m 600 "$seed_dir/auth.json" /var/lib/chorus/codex/library/auth.jsonSet 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.