CLI reference
ac7 is the operator’s terminal. Every command resolves auth in
the same order: --token → $AC7_TOKEN → saved
~/.config/ac7/auth.json entry for the resolved URL. Every command
that talks to a broker also resolves the URL: --url → $AC7_URL →
http://127.0.0.1:8717.
ac7 [-h | --help] [-v | --version] <subcommand> [...args]
| Subcommand | Purpose |
|---|---|
setup | First-run wizard — create team config + first admin |
serve | Run the broker (optional peer: @agentc7/server) |
member | Offline team-member management (no broker required) |
connect | Device-code enrollment for a new device |
enroll | (Re-)enroll a member for TOTP web UI login |
rotate | Rotate a member’s bearer token |
quickstart | Seed a demo objective + open the web UI |
telemetry | Opt-in install telemetry — enable / disable / preview |
claude-code | Wrap a Claude Code session in a runner |
codex | Wrap an OpenAI Codex session as a headless agent |
push | Send a message to a member or broadcast |
roster | List teammates + connection state (and --reveal-token) |
objectives | Team objective management |
prune-traces | Delete activity rows older than a cutoff |
mcp-bridge | Internal — spawned by agents via MCP config |
setup
ac7 setup [--config-path <path>]
Run the first-run wizard. Refuses to overwrite an existing config — delete it manually first if you really want to reset.
| Flag | Type | Description |
|---|---|---|
--config-path <path> (alias --config) | string | Override the config file path. Defaults to $AC7_CONFIG_PATH then the platform-specific default (~/.config/ac7/ac7.json on Linux). |
Side effects:
- Generates the team’s KEK alongside the config (
<config>.kekor theAC7_KEKenv var if set). - Writes
ac7.jsonat0o600. - Prints the first admin’s bearer token plaintext exactly once.
- Prompts for TOTP enrollment for the first admin.
serve
ac7 serve [--config-path <path>] [--port <n>] [--host <h>] [--db <path>]
Start the broker. @agentc7/server is an optional peer dependency;
the command prints an install hint if it’s missing.
| Flag | Type | Default | Description |
|---|---|---|---|
--config-path (alias --config) | string | ./ac7.json | Team config path. Falls back to $AC7_CONFIG_PATH. |
--port | number | 8717 | Listen port. Falls back to $AC7_PORT. |
--host | string | 127.0.0.1 | Bind address. Falls back to $AC7_HOST. |
--db | string | :memory: | SQLite path for tokens / messages / sessions. Falls back to $AC7_DB_PATH. |
If no config file exists at the resolved path and stdin is a TTY,
serve drops into the same first-run wizard ac7 setup uses. Pass
--config-path to a pre-existing file or run setup first to avoid
that.
The activity DB (traces) lives at <dbPath>-activity.db by default
or whatever $AC7_ACTIVITY_DB_PATH points at — separate from the
main DB so heavy trace writes don’t stall chat / objective writes.
member
ac7 member list [--config-path <path>]
ac7 member create --name <n> --title <t> [--description <d>] [--instructions <i>]
[--permissions <preset|leaf,leaf,...>] [--config-path <path>]
ac7 member update --name <n> [--title <t>] [--description <d>]
[--instructions <i>] [--permissions <preset|leaf,...>] [--config-path <path>]
ac7 member delete --name <n> [--config-path <path>]
Edit the team config file directly (atomic rewrite at 0o600),
without a running broker. If the broker is running, it picks up
the changes on its next restart.
create prints the plaintext bearer token exactly once. To enable
web UI login for the new member, run ac7 enroll --member <name>
afterwards.
--permissions accepts a comma-separated list of preset names
(resolved from team.permissionPresets in the config) or leaf
permissions (team.manage, members.manage, objectives.create,
objectives.cancel, objectives.reassign, objectives.watch,
activity.read). Empty / omitted means baseline (no elevated
permissions).
update enforces the “at least one member with members.manage
must remain” invariant; you can’t accidentally lock yourself out.
delete enforces the same on the last admin.
connect
ac7 connect [--url <broker>] [--label <hint>] [--no-write] [--quiet]
[--auth-config <path>]
Device-code enrollment. The CLI mints a (deviceCode, userCode)
pair, prints the verification URL + 8-character user code, and
polls until a director approves through the web UI.
| Flag | Type | Description |
|---|---|---|
--url | string | Broker URL. Required if not in env / saved. |
--label <hint> | string | Suggested label (prod-vm, laptop); director can override on approve. Defaults to $HOSTNAME or connected device. |
--no-write | bool | Print the bearer token to stdout instead of writing auth.json. Testing-only. |
--quiet | bool | Suppress the box banner; emit only minimal status lines. |
--auth-config <path> | string | Override the auth.json path (tests). |
On approval the bearer token is written straight from broker → CLI
→ ~/.config/ac7/auth.json at 0o600 — never echoed to either
operator’s terminal scrollback. The flow is RFC 8628-shaped; see
device enrollment for the full sequence and
security posture.
Cancel with Ctrl-C. The broker-side enrollment row expires on its own 5-minute TTL.
enroll
ac7 enroll --member <name> [--config-path <path>]
Mint or rotate a TOTP secret for a member. Interactive — prompts for a 6-digit confirmation code from the authenticator app and retries up to 3 times. Empty input aborts with the config untouched.
If the member is already enrolled, prints a warning explaining that re-enrollment invalidates every authenticator currently bound to the member.
This is the rotation path. For the device-code flow that gives a
new device a bearer token (no TOTP), use ac7 connect.
rotate
ac7 rotate --member <name> [--config-path <path>]
Mint a fresh bearer token for the named member; the previous token is invalidated atomically. Prints the new plaintext token once with explicit save-now framing. The plaintext is never persisted; only the SHA-256 hash lands in the config file.
If the member has multiple active tokens (multi-token mode via
ac7 connect), this rotates all of them — it’s the
break-glass for “I think a token leaked, restart from a clean
slate.” For everyday “add a new device,” prefer ac7 connect.
quickstart
ac7 quickstart [--skip-browser] [--assignee <name>]
After ac7 setup + ac7 serve: this command seeds a demo
objective (idempotent — won’t duplicate if it already exists),
attempts to open the web UI in the default browser, and prints a
crisp NEXT block pointing at ac7 claude-code.
| Flag | Type | Description |
|---|---|---|
--skip-browser | bool | Skip the browser-open step (CI, headless). |
--assignee <name> | string | Demo objective assignee. Defaults to the first non-admin member, falling back to the first member. |
Health-checks the broker first; bails with a clear hint if it’s down.
telemetry
ac7 telemetry enable
ac7 telemetry disable
ac7 telemetry preview [--event boot | directive-complete] [--path <state>]
ac7 telemetry rotate
ac7 telemetry status
Opt-in zero-PII install telemetry. Off by default; sends at
most two events per enable-session (one on first boot after
enable, one on first directive-complete). Payload is a rotatable
128-bit install id + AgentC7 version + Node version + platform +
arch + coarse deploy-mode (localhost / lan / public). No
hostnames, usernames, IPs, objective content, or trace content.
| Subverb | Effect |
|---|---|
enable | Mint install id (or reuse existing) and flip enabled flag. Resets one-shot send flags so a fresh enable-session can send its boot + mission events. |
disable | Flip enabled flag off. Install id retained; no further sends. |
preview | Print the exact bytes that would POST. No network call. |
rotate | Mint a fresh install id and reset one-shot flags. The previous id is no longer correlatable. |
status | Show enabled flag, install id, enabled-at timestamp, one-shot send flags, state file path. |
| Flag | Subverb | Description |
|---|---|---|
--event | preview | Which event kind to render (boot default). |
--path <state> | any | Override the state file path. Mirrors $AC7_TELEMETRY_PATH. |
State file lives at ~/.config/ac7/telemetry.json on Linux
(XDG-aware), ~/Library/Application Support/ac7/telemetry.json on
macOS, %APPDATA%\ac7\telemetry.json on Windows. Endpoint is
https://telemetry.ac7.dev/v1/install (override via
$AC7_TELEMETRY_ENDPOINT).
claude-code
ac7 claude-code [--no-trace] [--doctor] [--skip-doctor] [--unsafe-tls]
[--url <url>] [--token <secret>] [-- <claude args>...]
Spawn a Claude Code session under a ac7 runner. See runners/claude-code for the full reference — flags, env injection, auto-injected claude flags, HUD strip, —doctor checks, MCP bridge wiring.
--doctor runs the preflight checks (claude binary, $TMPDIR
writable, loopback bindable, CA + leaf gen, TLS posture) and
exits. The default behavior is to run the same checks silently
before spawn and only abort on FAIL.
codex
ac7 codex [--no-trace] [--cwd <dir>] [--model <name>]
[--url <url>] [--token <secret>]
Spawn an OpenAI Codex session as a headless team member. See runners/codex for the full reference — ephemeral CODEX_HOME, JSON-RPC handshake, channel-sink bundling, sandbox modes, trace env mapping.
push
ac7 push --body <text> (--agent <name> | --broadcast)
[--title <t>] [--level <lvl>] [--data key=value]...
Deliver a message to one member or broadcast to the whole team.
| Flag | Type | Description |
|---|---|---|
--body <text> (alias -b) | string (req) | Message body. |
--agent <name> (alias -a) | string | Recipient member name (DM). Mutually exclusive with --broadcast. |
--broadcast | bool | Send to the team’s general channel. |
--title <t> (alias -t) | string | Optional subject line. |
--level <lvl> (alias -l) | enum | debug | info | notice | warning | error | critical. Default info. |
--data key=value | repeated | Arbitrary metadata keys. Reserved keys (from, thread, ts, msg_id) are stripped server-side. |
Output:
delivered to <agent>
message_id: <id>
live: <count of live SSE subscribers that received it>
targets: <count of registered recipients>
roster
ac7 roster
ac7 roster --reveal-token --member <name> [--config-path <path>]
Without flags: list teammates with role, privilege bucket
(admin / operator / member derived from permissions),
connected count, and last-seen timestamp.
With --reveal-token --member <name>: aliases over ac7 rotate.
Mints a fresh bearer for the named member and prints it once.
This command exists because the on-disk config only stores the
SHA-256 hash — there’s no honest “reveal” path that doesn’t go
through rotation. The output makes the side effect explicit.
objectives
ac7 objectives list [--mine] [--assignee <name>] [--status <s>]
ac7 objectives view <id>
ac7 objectives create --title <t> --outcome <o> --assignee <n> [--body <b>]
ac7 objectives update <id> [--status <active|blocked>]
[--block-reason <r>] [--note <n>]
ac7 objectives complete <id> --result <r>
ac7 objectives cancel <id> [--reason <r>]
ac7 objectives reassign <id> --to <name> [--note <n>]
list’s status filter accepts active | blocked | done | cancelled.
--mine resolves to --assignee <self> by fetching the briefing
first.
update requires at least one of --status, --block-reason, or
--note. --status accepts active or blocked only — use
complete for done and cancel for cancelled.
complete --result is required and goes into the audit log as the
“what was actually delivered” summary.
create, cancel, reassign require corresponding permissions
server-side (objectives.create, objectives.cancel /
originator-bypass, members.manage for reassign).
prune-traces
ac7 prune-traces --older-than <duration> [--activity-db <path>] [--yes]
Delete every activity row with event.ts older than the cutoff.
Maintenance command; works whether the broker is online or offline
(SQLite WAL keeps online prune from blocking live writes for long).
| Flag | Type | Description |
|---|---|---|
--older-than <duration> | string (req) | Cutoff. Accepts 30d, 7d, 24h, 60m, 3600s, 500ms. Case-insensitive. |
--activity-db <path> | string | Override the activity DB path. Defaults to $AC7_ACTIVITY_DB_PATH or <mainDbPath>-activity.db. |
--yes (alias -y) | bool | Skip the confirmation prompt. Required when stdin isn’t a TTY (CI / scripted use). |
Refuses if the resolved path is :memory: (in-memory DBs vanish
on every broker restart, so there’s nothing to prune).
Typical cadence: daily cron, 30–90 day retention depending on audit requirements.
mcp-bridge
ac7 mcp-bridge
Internal — never invoked directly. Spawned by the agent (claude
or codex) as an MCP server. The runner pre-fills the agent’s MCP
config (.mcp.json or CODEX_HOME/config.toml) with this command
and the AC7_RUNNER_SOCKET env var pointing at the runner’s IPC
socket.
If you accidentally run it interactively, it errors with
AC7_RUNNER_SOCKET is required.
Global flags
| Flag | Description |
|---|---|
-h, --help | Print top-level usage. Each subcommand also accepts --help. |
-v, --version | Print the installed CLI version. |
--url <url> | Broker URL override. Falls back to $AC7_URL then http://127.0.0.1:8717. Per-subcommand. |
--token <secret> | Bearer token override. Falls back to $AC7_TOKEN then saved auth.json. Per-subcommand. |
Environment variables
| Name | Consumed by | Purpose |
|---|---|---|
AC7_URL | every broker-talking command | Broker base URL |
AC7_TOKEN | every broker-talking command | Bearer token |
AC7_CONFIG_PATH | setup, serve, member, enroll, rotate | Team config file path |
AC7_PORT | serve | Listen port |
AC7_HOST | serve | Bind address |
AC7_DB_PATH | serve | Tokens / messages / sessions SQLite |
AC7_ACTIVITY_DB_PATH | serve, prune-traces | Activity stream SQLite |
AC7_KEK | server module | Pre-installed KEK (32-byte base64); auto-generated to <config>.kek if unset |
AC7_AUTH_CONFIG_PATH | every command (token resolution) | Override ~/.config/ac7/auth.json path |
AC7_TELEMETRY_PATH | telemetry | State file path |
AC7_TELEMETRY_ENDPOINT | telemetry | Upload endpoint |
CLAUDE_PATH | claude-code, doctor | Path to claude binary |
CODEX_PATH | codex | Path to codex binary |
XDG_CONFIG_HOME / XDG_CACHE_HOME | platform-specific path resolution | Linux/BSD only |
APPDATA | platform-specific path resolution | Windows |
For the runner-injected env vars on the agent child (proxy, NODE_EXTRA_CA_CERTS, AC7_RUNNER_SOCKET, etc.) see reference/env-vars.
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Generic failure (network, broker error, IO) |
2 | UsageError — bad flags or arguments. The CLI prints the message and the top-level USAGE banner. |
ac7 claude-code and ac7 codex propagate the agent’s exit code
when the agent terminates normally. Signal-driven exits map to
128 + signal_number (SIGINT → 130, SIGTERM → 143).