Operate the Chorus daemon
Use this guide after you have verified a foreground daemon connection. The commands apply to the supported resident backends: Claude Code, Codex, Kiro, and Pi.
Choose what the daemon can access
Section titled “Choose what the daemon can access”Each --cwd registers one working directory as a separate target in Chorus:
chorus daemon \ --agent claude-code \ --cwd ~/work/project-a \ --cwd ~/work/project-b \ --chorus-onlyWith no --cwd, Chorus uses the directory where you start the command. Use repeatable
--browse-root options only when users need to choose directories below a broader root.
A browse root allows discovery; it does not register every directory as an online
connection.
When you fix a working directory for a project’s agent, that
path must be one the daemon serves — include it in this daemon’s cwds set so the fixed
directory resolves to an online connection.
Configure daemon.json
Section titled “Configure daemon.json”The daemon reads its settings from ~/.chorus/daemon.json. In the common single-agent case
it is one flat JSON object holding the agent credential and the runtime options; to serve
several agents from one daemon you instead list them under an agents array — see
Run several agents in one daemon. Either way it is
written with 0600 (owner read/write only) using an atomic temp-file-plus-rename, so a crash
mid-write never leaves a truncated file. The path is fixed at ~/.chorus/daemon.json
(resolved from your home directory); there is no environment variable to relocate the file
itself.
Fields
Section titled “Fields”| Field | Type | Meaning |
|---|---|---|
url | string | Chorus server URL. |
apiKey | string | Agent API key (cho_…). |
agentUuid | string | Authenticated agent UUID (informational). |
agentName | string | Authenticated agent name (informational). |
cwds | string[] | Working directories this daemon serves. Each path is one independent online connection. |
browseRoots | string[] | Roots exposed to remote working-directory discovery. A browse root does not create a connection. |
agent | string | Local backend to wake: "claude-code", "codex", "kiro", or "pi". |
sigintTimeoutMs | number | Grace window (ms) after SIGINT before a woken agent is force-killed. Default 10000. |
agents | object[] | Optional. Serve several independent agents from one daemon; each entry overrides the top-level fields for that agent. See Run several agents in one daemon. |
A minimal file after chorus login plus chorus daemon install:
{ "url": "https://chorus.example.com", "apiKey": "cho_REDACTED", "agentUuid": "8a1c…", "agentName": "Build Agent", "cwds": ["/home/demo/work/project-a"], "browseRoots": ["/home/demo/work"], "agent": "claude-code", "sigintTimeoutMs": 10000}How the file is created
Section titled “How the file is created”chorus agents addis the usual way the file is first created: it validates each configured agent’s credential and writes it as an entry in theagentsarray. See Connect an agent runtime.chorus loginvalidates your URL and key, then writesurl,apiKey,agentUuid, andagentNamefor a single flat agent.chorus daemon installadditionally writescwds,browseRoots, andagent(it prompts for the served directories and backend when they are not already set).- A first
chorus daemonrun on a terminal completes any missing credentials interactively and writes them.
How the file is updated
Section titled “How the file is updated”Every writer performs a shallow merge: the new fields are merged over whatever is
already on disk, and unrelated fields are preserved. Re-running chorus login refreshes
the credentials without clearing your cwds, agent, or sigintTimeoutMs; re-running
chorus daemon install updates the served set without discarding the credential. A
missing or corrupt file is treated as an empty object, so a re-login always produces a
valid file rather than failing.
Field, flag, and environment variable
Section titled “Field, flag, and environment variable”Each option can be supplied three ways. Precedence is flag, then environment variable,
then daemon.json, so a one-off flag or env override never has to be written to the file:
| Concern | daemon.json field | CLI flag | Environment variable |
|---|---|---|---|
| Server URL | url | --url | CHORUS_URL |
| API key | apiKey | --api-key | CHORUS_API_KEY |
| Working directories | cwds | --cwd (repeatable) | CHORUS_DAEMON_CWDS |
| Browse roots | browseRoots | --browse-root (repeatable) | CHORUS_DAEMON_BROWSE_ROOTS |
| Backend | agent | --agent | CHORUS_AGENT |
| SIGINT grace | sigintTimeoutMs | --sigint-timeout | CHORUS_DAEMON_SIGINT_TIMEOUT |
| Permission mode | (not persisted) | --yolo / --chorus-only | CHORUS_YOLO / CHORUS_CHORUS_ONLY |
The permission mode is deliberately not stored in daemon.json. Pass --chorus-only
(or set CHORUS_CHORUS_ONLY=1) at start time; the installed service captures
--chorus-only in its unit, not in the file.
Run several agents in one daemon
Section titled “Run several agents in one daemon”One chorus daemon process can serve several fully independent agents at once — different
personas, permissions, accounts, or even different backends — instead of running a separate
daemon per agent. List them under an agents array; each entry is one agent:
{ "url": "https://chorus.example.com", "sigintTimeoutMs": 8000, "agents": [ { "apiKey": "cho_alpha", "agentType": "claude-code", "cwds": ["/home/demo/project-a"] }, { "apiKey": "cho_beta", "agentType": "kiro", "cwds": ["/home/demo/project-b"], "permissionMode": "chorus" } ]}Every top-level field is a default; a field set on an agent overrides it for that
agent only. Each agent gets its own identity (from its key), its own connections (one per its
cwds), its own wake queue, and its own backend — so they are woken and run independently, and
one agent’s failure never disrupts the others. On the server each appears as its own connection
in Settings → Agents, keyed on agent, host, and directory. Agents may even share a working
directory; the daemon does not serialize them, so avoid concurrent conflicting work in one git
tree (use separate branches or worktrees).
Per-agent fields
Section titled “Per-agent fields”| Field | Meaning |
|---|---|
apiKey (required) | The agent’s cho_ key — determines its identity. |
url | Chorus server (may differ per agent — a different server or company). |
agentType | claude-code, codex, kiro, or pi (backends may be mixed). |
cwds | Working directories this agent serves (one connection each). |
permissionMode | yolo or chorus. |
maxConcurrency | This agent’s own wake-concurrency cap (default 4). |
sigintTimeoutMs | Interrupt-escalation grace window (ms). |
browseRoots | Directory-discovery allowlist. |
Add another agent
Section titled “Add another agent”chorus login --addvalidates a new key and appends it as another agent. The first--addon a flat file migrates the existing credential intoagents[0]and adds the new key asagents[1]; a duplicate key is refused, and an existing agent is never overwritten.chorus daemon install --addloops the install wizard so you can add several agents in one pass (terminal only).- Hand-editing
~/.chorus/daemon.jsonis always supported.
Restart the daemon after editing the file (chorus daemon restart), then confirm each agent
appears in Settings → Agents.
How each backend receives its key
Section titled “How each backend receives its key”Each agent authenticates with its own key, but how that key reaches the woken subprocess depends on the backend:
- Claude Code — automatic. The daemon writes a per-wake MCP config carrying that agent’s URL and key. Nothing to configure.
- Kiro — automatic, via the environment. The installed
mcp.jsonreferences${CHORUS_URL}and${env:CHORUS_API_KEY}, which the daemon exports per wake, so each Kiro agent authenticates with its own key. - Codex — automatic, via the environment.
chorus agents addconfigures Codex keyless: it writesCHORUS_URL/CHORUS_API_KEY/CHORUS_AGENT_PROFILEinto~/.codex/.env(which Codex loads at startup) and setsbearer_token_env_var = "CHORUS_API_KEY"inconfig.toml, so Codex reads its key from the environment rather than a baked literal. The daemon injects each agent’s own key per wake, so several Codex agents in one daemon each authenticate as themselves. - Pi — automatic, via the environment. The daemon exports each agent’s
CHORUS_URL/CHORUS_API_KEY/CHORUS_AGENT_PROFILEinto the woken pi session, which thechorus-piextension reads, so each pi agent authenticates with its own key.
Install the Linux service
Section titled “Install the Linux service”On Linux, install the verified configuration as a user service:
chorus daemon install \ --agent claude-code \ --cwd ~/work/project-a \ --chorus-onlyThe installer starts the service immediately and configures it to start when the user
logs in. Run chorus agents add (or chorus login) first so the service can read the
saved credential — or pass --daemon-autostart to chorus agents add to install this boot
service in the same step.
Provide credentials a woken agent needs
Section titled “Provide credentials a woken agent needs”The daemon injects only the Chorus connection into a woken agent — CHORUS_URL,
CHORUS_API_KEY, and CHORUS_AGENT_PROFILE — never a model-provider key. When a backend reads
its model-provider credentials from the environment, those must be present in the daemon’s own
environment. A systemd --user service starts in a clean environment and does not inherit what
you export in your login shell, so set them on the service with a drop-in and restart:
[Service]Environment=EXAMPLE_PROVIDER_API_KEY=…systemctl --user daemon-reload && systemctl --user restart chorus-daemonBackends that read provider auth from a file instead (for example Claude Code and Codex under
~/.claude / ~/.codex) only need the daemon’s HOME set correctly, which the installed unit
already does.
Use these commands for routine operation:
chorus daemon statuschorus daemon logschorus daemon restartchorus daemon stopchorus daemon uninstallAfter changing credentials, working directories, backend, or permission mode, reinstall or restart the service and verify the connection in Settings → Agents.
Run without a service
Section titled “Run without a service”For a short-lived connection, keep chorus daemon in the foreground. Detached mode is
also available:
chorus daemon -d --agent codex --cwd ~/work/project-a --chorus-onlyManage it with the same status, logs, restart, and stop commands. Do not combine
detached mode with a separately written process supervisor.
Check operating health
Section titled “Check operating health”Use both command-line and web status:
- Run
chorus daemon status. - Review recent output with
chorus daemon logs. - In Settings → Agents, confirm each expected working directory is Online.
- Start a small test session and confirm it targets the intended directory.
Logs can contain paths, prompts, and command output. Remove sensitive values before sharing them. For failures, continue with Troubleshoot agent connections.