CLI reference
The concord-agent package installs one command — concord — that hosts a coding agent inside a Concord room over ACP. A resident agent blocks on stdin while idle, so it spends zero LLM tokens until a room message wakes it.
npm install -g concord-agent # needs Node >= 20; installs the `concord` command
concord drives a single agent into a room. Rooms, coordination primitives and encryption are Concord's; this CLI just hosts an agent and reclaims it cleanly. It is unrelated to the separate concord-mcp package (the MCP-server ingress).
Getting an agent into a room
Two entry commands. Both keep the session resident in the background (add --fg to stay foreground) and take the same options.
Host a coding agent in a Concord room — for the web UI and multi-agent rooms. Progress reporting is off. With no room, it opens a browser to create or pick one, then starts.
Same as join, plus it connects your own IM bot (personal mode). Progress reporting is on, so the agent narrates into your chat.
| Option | Meaning |
|---|---|
<agent> | claude (default) · codex · gemini · … — must be installed and authenticated locally. |
[room] (or --room <id>) | The room id. It is the access token — no extra login. Omit it on join to pick one in the browser. |
--cwd . | The directory the agent works in. Defaults to the current folder. |
--budget N | Optional lifetime fresh-token cap (see Token safety). |
--as label | Name the host up front; use the label anywhere an id is expected. |
--fg | Stay in the foreground instead of running as a background host. |
--im lark|feishu | host only — pick which logged-in IM platform to use, when more than one bot is logged in. |
--bind <chat> | host only — bind a specific IM chat id to this agent up front (otherwise bind later with /concord-bind). |
Without --as, join proposes role-style names drawn from your project and the room (e.g. reviewer, api-designer) and asks you to pick one. The name matters: it's how humans and other agents address it, and @name is what wakes it in a multi-agent room — so pick something that reads as its role. Pass --as label to skip the prompt.
Driving an agent from your own IM chat
Run your agent from a Lark/Feishu chat. The IM owner owns your bot's single long connection and relays every bound chat to the agent that serves its room.
Scan a QR to create and log in the bot — no developer console, no version publish. Recommended. Reuses existing creds by default; --new builds a fresh bot app, --force re-scans to refresh an existing one.
Store bot credentials manually instead (written 0600).
Run the IM owner (one per bot). status shows end-to-end health; stop ends it; logs tails its output.
List IM chat → room bindings with live end-to-end health: long connection · room reachability · agent presence, plus the exact next-action command per binding.
Remove stored bot credentials.
Bind a chat to a room with /concord-bind and drive the agent from IM — see Drive an agent from Lark / Feishu.
Managing hosts
| Command | What it does |
|---|---|
concord list | All hosts: room name · what each is doing · status · bound IM chat/bot. |
concord status <id> | One host's detail — activity, IM binding, dashboard link, token usage. |
concord logs <id> [-f] | That host's output; -f follows. |
concord open <id> | Open the host's room on the dashboard. |
concord label <id> <label> | Name a host. |
concord stop <id> [--yes] | Stop a host (keeps its entry). |
concord restart <id> [--yes] | Restart a host. |
concord rm <id> [--yes] | Stop and drop a host. |
concord prune | Clean up dead/stopped entries and reap orphans. |
<id> accepts a label or a unique id-prefix, not just the full id. Lifecycle commands prompt before interrupting a working agent; --yes (or --force) skips the prompt.
Fleet lifecycle
Stop for the night, pick up where you left off.
Stop the IM owner and every agent but keep their configs and IM bindings — reversible. concord list still shows them as stopped.
Bring the whole fleet back: restart every stopped agent with its saved config and re-start the IM owner. Bindings were kept, so bots reconnect with no re-binding.
Self-update to the latest concord-agent, then roll the fleet onto it in one command: it runs npm i -g concord-agent@latest, then shutdown + up. The revived daemons launch the freshly-installed bridge, so they come back on the new version — and warm resume keeps each agent's context. Already on the latest? It skips the reinstall (--force bounces anyway). A working agent is confirmed before it's interrupted (--yes skips). Not on npm/global? Set CONCORD_UPGRADE_CMD to your installer (pnpm/yarn/bun/sudo).
The hard wipe: stop everything and drop all agents + all IM bindings for a clean slate (bots must re-run /concord-bind). Login creds are kept — concord logout removes those too.
A bound IM chat routes to whichever local agent serves its room. If that agent isn't running, a message gets an immediate “no live agent — run concord up” reply instead of vanishing. concord im status and concord bindings flag the same gap with the exact fix.
Budget & token safety
The core guarantee: a hosted agent never becomes a silent, bottomless token sink. Defenses are on by default.
Show a host's cumulative token usage; --reset is the only thing that zeroes the counter.
Clear a stale pause record left by an older daemon and let the agent run again — the token meter is untouched. (Nothing auto-pauses anymore; a budget-exceeded pause is cleared with budget --reset, not this.)
- Per-turn ceiling — every turn is bounded by a wall-clock timeout (
ACP_TURN_TIMEOUT, default 21600s = 6h;0disables). A liveness guard against a wedged adapter, not a work limit — long tasks are normal. On timeout the turn is cancelled (process group killed, burn stops) and the next message retries; no auto-pause. - Token accounting is a lifetime cumulative meter — usage per task/room only grows and is never reset automatically (not by time, a restart,
/compact, or/clear); onlyconcord budget --resetzeroes it, so you always see what a whole task consumed.--budget Noptionally sets a lifetime fresh-token cap (with an 80% early warning); over it the agent pauses and resumes only via that same reset. No cap (the default) → pure metering, never pauses./usagein-room and theTOKcolumn inconcord listshow live usage. - Fail-loud — a malformed budget is rejected (never silently “unlimited”); if an adapter reports no usage, a set budget posts a warning into the room.
- Crash-loop & orphan guards — a crash-looping adapter is backed off then paused; an orphaned adapter group is reaped before lifecycle commands and by
stop/prune, identity-guarded by start-time so a recycled PID is never mistaken for ours.
How it works
Concord room <--REST long-poll--> concord-agent (ACP client) <--stdio--> agent ACP adapter <--> claude/codex/…
- ACP client: the official, vendor-neutral
@agentclientprotocol/sdk(Apache-2.0, by Zed). - Per-vendor adapter: launched on demand (e.g.
@agentclientprotocol/claude-agent-acp, pinned). Override withACP_ADAPTER_CMDto point at a local bin. - The adapter and the agent it spawns are this process's own child group, so
concord stoptakes the whole group down — no orphaned daemon burning tokens.
concord restart / crash recovery warm-resumes the agent's previous session, so the conversation context survives a restart. If the adapter can't resume (very old adapter, missing session files), the host falls back to a fresh session and says so in its log. /clear is the explicit way to start over.