For AI agents: the complete documentation index is available at /cafleet/llms.txt, the full documentation bundle is available at /cafleet/llms-full.txt, and this page is available as Markdown at /cafleet/spec/cli-options.md.

CLI options

The unified cafleet CLI uses literal subject IDs, synchronous SQLite access and explicit pane actions. Run each command as one isolated shell-tool invocation.

Subcommand summary

CommandPurposeSubjectJSON
setupInitialize/migrate the current database and install assets—no
doctorDiagnose multiplexer, database, agent assets and member permissions—yes
fleet createRegister the calling Director atomically—yes
fleet list / fleet showRead fleet registryFLEET_ID for showyes
fleet deleteDeregister a fleet and its membersFLEET_IDyes
fleet captureCapture the active roster onceFLEET_IDyes
member createRegister and spawn an independent agent--fleet-id relationshipyes
member deleteKill its owned pane and deregisterMEMBER_IDyes
member show / member listRead detail / active rosterMEMBER_ID / FLEET_IDyes
member prompt / member execSubmit authorized native inputMEMBER_IDyes
member captureRead a pane tailMEMBER_IDyes
message sendPersist a point-to-point message and preview it for an ordinary recipientSender/recipient flagsyes
message poll / message waitRead incoming deliveries / block until deliveries arriveMEMBER_IDyes
message listenStream pending inbox records through stdoutMEMBER_IDJSONL only
message ack / message showConsume / read one messageMESSAGE_IDyes

Environment variables

VariableFieldDefaultMeaning
CAFLEET_DATABASE_URLdatabase_urlsqlite:/// + ~/.local/share/cafleet/cafleet_v8.dbSelected SQLite file path
CAFLEET_MULTIPLEXERmultiplexerAuto-detectExplicit supported multiplexer override
CAFLEET_MAX_TEXT_LENmax_text_len200CLI text-output body codepoint limit

The default expands HOME once. An explicit URL has the form sqlite:///<path>; resolve a relative file path against the invoking working directory before canonicalizing the database file for shared pane-lock identity. A literal tilde in an override is not expanded. Count values accept nonnegative integers and invalid values fail with <NAME> must be a non-negative integer (got '<value>').

Global Options

cafleet --version prints cafleet <version> and exits 0 before dispatch.

Output shapes

CommandTextJSON
fleet create<fleet-id> director=<member-id>Ordered fleet_id, name, created_at, director, with Director identity/description/registration/placement
fleet listFLEET_ID DIRECTOR NAME MEMBERS CREATED_AT columnsFleet records
fleet showFleet row with deleted_at:Fleet including nullable deleted_at
fleet deleteDeleted fleet ID. Deregistered N members.{deregistered_count}
message sendMessage sent. then envelope{message, notification_sent}
message pollEnvelopes, or No messages found.Full record array
message ackMessage acknowledged. then envelope{message}
message showEnvelope{message}
message waitAvailability/timeout line and any messages{member_id, outcome, messages, notification_errors}
message listen—Tagged ready, message, closed JSONL records; no --json flag
member createID NAME backend=AGENT pane=PANEMember with placement
member deleteMember deleted. with member/pane lines{member_id, pane_status}
member showID NAME STATUSDetail including kind and placement
member listRoster rows or 0 members.Roster array
member promptSent prompt TEXT_REPR to member NAME (PANE).{member_id, pane_id, text}
member execDispatched native command to member ID (PANE). Inspect the pane for its result.{member_id, pane_id, coding_agent, command, dispatched}
member captureExact selected content{member_id, pane_id, lines, content, captured_at, content_sha256}
fleet captureOne annotated section per entryOrdered capture-entry array
doctorComplete diagnosis and issue footerDiagnosis object

Member list output

Roster records include member_id, name, kind, placement, last_sent, last_recv, last_ack and idle. kind is director when the fleet reference matches, otherwise member. Missing activity is null; placement may be null, or its pane ID pending. Text uses - for absent values and (pending) for a pending pane.

JSON output (--json)

Use a trailing per-subcommand --json. It emits compact single-line JSON with UTF-8 and complete untruncated message text. Application errors remain stderr text; parse errors exit 2. Commands marked no reject the flag, including the root group.

Positional subject ids

Place FLEET_ID, MEMBER_ID or MESSAGE_ID immediately after the subcommand. The subject row supplies related fleet/recipient state. IDs are complete DB-assigned integers, without prefix resolution or environment defaults. A missing or malformed subject uses the parser's native error, exit 2.

Spawned members read literal FLEET ID:, YOUR MEMBER ID:, DIRECTOR MEMBER ID: and CODING AGENT: lines. Pass these literal IDs on each invocation.

Sender and recipient (--from-member-id, --to-member-id)

Send requires integer sender and recipient flags. Both must be active in the same live fleet. The sender row determines the fleet; IDs are coordination identifiers within the local trust model.

permissions.allow coverage

Use prefix rules such as Bash(cafleet message *) to cover broker operations, including cafleet message listen ID --timeout 300 and finite cafleet message wait. Verify native Monitor authorization separately: a Bash-rule check establishes no Monitor permission. Director capture is covered by Bash(cafleet fleet capture *) or a broader authorized prefix. Literal IDs and trailing JSON flags preserve prefix matching.

Keep Bash(cafleet member prompt *) and Bash(cafleet member exec *) under permissions.ask, because their bodies carry operator-controlled input. Ask rules outrank allow rules. The permission profiles describe each role's needs.

Message Body Truncation

CLI text bodies use CAFLEET_MAX_TEXT_LEN Unicode codepoints followed by … when truncated. Full JSON and pane captures preserve their complete content. Pane notification lines follow their own inline-body limit. Message envelope owns the compact rendering.

Text bodies (positional TEXT / --file)

Send and member creation require exactly one positional body or --file PATH; --file - reads UTF-8 stdin. Preserve exact nonblank body text. Missing/both sources or a blank positional body exit 2; blank file/stdin sources and file-read errors exit 1 with the authored diagnostics below. File read/UTF-8 failures retain the actual cause. Compact role-by-path spawn prompts remain necessary because resolved prompts enter backend/multiplexer argv.

member prompt takes one positional line. Native exec has the separate command contract.

cafleet setup — Onboarding and Schema Management

cafleet setup [--coding-agent AGENT...] validates the selected database format before either half writes. Initialize an empty zero-identity file with the embedded baseline in one transaction; migrate known current-family versions. An ahead ledger version or incompatible shape rejects both setup write paths before database mutation, asset installation or asset-install recording. Independent half-error reporting applies after this compatibility gate. A format failure prevents asset installation and content writes. Compatible setup installs embedded assets offline and records versions. Backend selection is multi-value/repeatable, deduplicated and defaults to the supported backend registry.

The database half prints Created PATH and applied migrations to head (N)., Upgraded from M to N. or Already at head (N); nothing to do. according to state. Report actual errors as db half failed: CAUSE or assets half failed: CAUSE; failed halves exit 1. Assets require a compatible usable current schema.

Config-dir resolution

Every surface that installs to or checks a backend's user-level config directory resolves it through the backend's native config-location environment variable, falling back to the default when the variable is unset:

BackendVariableBase when setBase when unsetSkills dirPreset target
claudeCLAUDE_CONFIG_DIR$CLAUDE_CONFIG_DIR~/.claude<base>/skills—
codexCODEX_HOME$CODEX_HOME~/.codex<base>/skills<base>/rules/cafleet.rules
opencode (skills)— (fixed discovery path)—~/.config/opencode<base>/skills—
opencode (preset)OPENCODE_CONFIG_DIR$OPENCODE_CONFIG_DIR~/.opencode—<base>/agents/cafleet.md

opencode splits by purpose: agents/ is in OPENCODE_CONFIG_DIR's documented search list, so the preset may relocate and remain a valid --agent cafleet discovery path; skills are not in that list — opencode discovers them only at fixed paths — so the skills install ignores the variable.

OPENCODE_CONFIG_DIR adds a preset search directory alongside default home configuration. Agent definitions with the same name can merge across these sources; inspect the effective configuration when customizing a preset.

Validation. A set variable must hold an absolute path. Any other value — the empty string, a relative path, a literal unexpanded ~/… — fails at resolution time with exit 1:

Error: <VAR> must be an absolute path (got '<value>')

Validation is lazy: a variable is read and validated only when a site actually resolves that backend's directory. cafleet setup --coding-agent claude with an invalid CODEX_HOME succeeds because the selector resolves only the targeted agent's directory; plain cafleet setup resolves all three identity paths, so an invalid variable fails its assets half. The spawn preconditions themselves read none of the three variables for claude and codex (PATH-check-only; opencode's resolves the preset base) — but the stale-assets guard fronting every fleet-scoped command, member create included, resolves all three identity paths. One exception to strict lazy failure: doctor catches per-agent resolution errors and renders them as issues instead of aborting (see doctor).

Recorded-path identity. Every surface that keys on "the agent's resolved path" — the asset_installs rows, the stale-assets guard, and doctor's setup column — uses one canonical path per agent, the resolved base directory, stored absolute exactly as resolved (no canonicalization beyond the absolute-path validation):

AgentRecorded / status-keyed path
claudeThe resolved claude config dir ($CLAUDE_CONFIG_DIR or ~/.claude)
codexThe resolved codex home ($CODEX_HOME or ~/.codex)
opencodeThe resolved preset base ($OPENCODE_CONFIG_DIR or ~/.opencode) — the only opencode root that can vary; the skills base is fixed and carries no identity

Assets half

Each agent's preset, where one exists, is a static file embedded in the binary next to the skills; install targets resolve per Config-dir resolution:

AgentBundled presetInstall target
claude— (skills only)—
codexpresets/codex/cafleet.rules<codex base>/rules/cafleet.rules (default ~/.codex/rules/cafleet.rules)
opencodepresets/opencode/cafleet.md<preset base>/agents/cafleet.md (default ~/.opencode/agents/cafleet.md)

Each backend replaces the two embedded skills sequentially, removes a leftover cafleet-research entry, then replaces its preset where present. Existing targets are deleted before their replacements are written. Unrelated skills remain untouched. A symlink target is unlinked as an entry; its referent is not deleted. Skills-operation errors retain failed to install skills into <skills_dir>: <error> and preset-operation errors retain failed to install preset into <target>: <error>.

The command prints each success line after that operation completes, then records the installed version after all operations succeed. The preset line appears only for codex and opencode:

<agent>: installed cafleet, cafleet-design-doc (v<version>) -> <skills dir>
<agent>: installed preset (v<version>) -> <target>

Shared diagnosis and connection reuse

Use the invocation’s shared classifier and connection for guard/setup work. Doctor completes read-only sections even when the database is unavailable. Compatibility includes identity, ledger version and expected table/column shapes.

Schema-version guard

The fresh baseline creates exactly the application tables declared in the schema. Compatibility diagnosis verifies current application identity, ledger version, every required table’s column shape, and required indexes/foreign keys. Known versions use their recorded migration shape; newer versions are diagnosed before any head-shape comparison. Unrelated auxiliary tables, indexes and triggers are compatible while those required definitions remain intact.

Every fleet/member/message command validates current format before writes and asset checks. Identity is application_id=1128351288; malformed or incompatible files fail with database format is incompatible at 'PATH'; choose an empty database path and run 'cafleet setup'. Preserve file bytes and existing sidecars. Empty state reports no cafleet database; run 'cafleet setup'. Behind state reports database schema is outdated (schema M, head N); run 'cafleet setup'; ahead reports database schema M is newer than this cafleet (head N); upgrade cafleet. Database-open/read errors preserve their cause. Setup initializes/repairs compatible known versions; doctor reports rather than blocks its other diagnostics.

Stale-assets guard

Every fleet-scoped surface — the fleet, member, and message groups — validates the recorded assets installs after the schema-version guard passes and before any subcommand body runs. The guard resolves each agent's identity path per Config-dir resolution and checks only the row at that path. Apply the following precedence:

Recorded install stateResultExit
A config-path variable fails validationThe pinned validation error1
No agent has a row at its currently-resolved path in a compatible at-head databaseError: no assets install is recorded at the resolved paths; run 'cafleet setup' to install1
A row at a resolved path has cafleet_version ≠ the runtime CLI version (string inequality — either direction)Error: stale assets detected (<agent>=<recorded>[, ...]; CLI <runtime>); run 'cafleet setup' to reinstall, stale agents in ascending order1
Every row at a resolved path matchesThe command proceeds silently0

Staleness checks use version records at currently-resolved paths; agents without a matching row contribute nothing to staleness. Plain cafleet setup installs agents at their resolved paths. Setup and doctor are exempt:

Exempt surfaceWhy exemptBehavior under a stale/missing install
setupIt must remain runnable to repair the installRuns normally — it is the repair path
doctorIt reports instead of blockingRenders each agent's setup state in the coding-agents section

--help renders at parse time and exits before any command body runs, so neither group-level help (cafleet fleet --help) nor subcommand help (cafleet fleet create --help) triggers either guard — both always print help, even under a missing database or a missing or stale install.

cafleet fleet — Fleet Management

fleet create

cafleet fleet create --name NAME --coding-agent AGENT [--json]

Require the selected backend token and a valid tmux/herdr context. Outside that context fail with cafleet fleet create must be run inside a tmux or herdr session. Insert fleet, current Director member and placement in one transaction and backfill director_member_id before commit. The Director has name="Director" and description="Root Director for this fleet". Creation splits no pane and launches no process. An ordinary member can be created immediately.

The calling pane becomes the Director's concrete placement. Run fleet create from the coding-agent session declared by --coding-agent, then arm native message reception before depending on member replies. Root-Director messages remain in the durable inbox for native or manual reads; automatic pane previews target ordinary members.

fleet list

List non-deleted fleets by descending creation timestamp/fleet ID. Rows retain the Director reference so its ID remains discoverable.

fleet show

cafleet fleet show FLEET_ID [--json] includes soft-deleted rows. Unknown ID: fleet 'X' not found., exit 1.

fleet delete

cafleet fleet delete FLEET_ID [--json] locks active concrete placements in sorted key order, revalidates the placement set, then stamps deletion and deregisters active members/removes placements in one transaction. It retains messages and is idempotent. Close owned member panes individually first.

One operation-wide five-second deadline bounds lock acquisition, with 50-millisecond retries and set-change restart. Contention leaves state unchanged and exits 1 with fleet ID pane input remained busy for 5 seconds at member MEMBER_ID; fleet was not deleted.

fleet capture

cafleet fleet capture FLEET_ID [--lines N] [--ansi] [--json] checks fleet existence and soft-deletion before resolving the multiplexer. An absent or deleted fleet exits 1 with Error: fleet ID not found. Capture reads the current active roster once, Director first then placement-owning members by ascending ID. The default depth is 20. Per-pane failures, including a pending Director placement, annotate entries and leave the rest available. It writes no broker state.

Text sections begin === ID (NAME; kind=KIND; coding_agent=AGENT; pane=PANE; captured_at=TS) ===, separated by a blank line. A failed/pending pane omits capture time and carries its diagnostic.

JSON entries are ordered member_id, name, kind, coding_agent, pane_id, lines, content, captured_at, content_sha256, error. Kind is director/member. On error, content/time/hash are null; pane_id is null only without a concrete pane. Successful hash/timestamp semantics match member capture.

cafleet doctor — Environment Diagnosis

A full-environment diagnosis that renders all sections even when the multiplexer is unavailable or the database is missing or stale — no early abort. Diagnosis order: multiplexer, database, coding agents, member permissions. doctor is exempt from the schema-version guard and the stale-assets guard — a missing or outdated database and a stale or missing install are reported, not fatal.

The only flag is the optional --json, a trailing per-subcommand flag.

Text layout

The first output line of the whole report is cafleet <version>. Each section is led by a single-width verdict glyph (✓ U+2713 / ✗ U+2717) plus the section name; detail lines are indented two spaces beneath. A worked example (at-head schema, one stale agent, one superseded record):

cafleet 0.22.0
✓ multiplexer
  backend:   tmux
  session:   main
  window_id: @3
  pane_id:   %0
  presence:  TMUX=/tmp/tmux-501/default,12345,0
✓ database
  schema 12 (head)
✗ coding agents
  ┌──────────────┬──────────────┬────────────────────┬───────────────────────────────────────────────┐
  │ coding agent │ path         │ source             │ setup                                         │
  ├──────────────┼──────────────┼────────────────────┼───────────────────────────────────────────────┤
  │ claude       │ ~/cfg/claude │ $CLAUDE_CONFIG_DIR │ ✓ 0.22.0                                      │
  │ codex        │ ~/.codex     │ default            │ ✗ 0.21.0 → cafleet setup --coding-agent codex │
  │ opencode     │ ~/.opencode  │ default            │ – cafleet setup --coding-agent opencode       │
  └──────────────┴──────────────┴────────────────────┴───────────────────────────────────────────────┘
  note: codex was previously set up at ~/.codex-old
✓ member permissions
  claude: no setting blocks the member broker commands
1 issue found

Multiplexer section

✓ with the five detail lines (backend, session, window_id, pane_id, presence). On any multiplexer or environment failure (no supported multiplexer, ambiguous environment, binary not on PATH, pane not discoverable): ✗ multiplexer with the resolver's error message as the single detail line, and the report continues. One issue.

Database section

One detail line describes the database state (<M> recorded version, <N> embedded head). An empty database has application_id=0 and no non-internal tables. Validate application identity 1128351288 and the migration ledger first, then read the recorded version. For supported versions, validate required table/column, index and foreign-key shapes against that recorded version's migrations. Older supported versions therefore remain eligible for in-place migration. A newer version reports ahead without comparing its unknown shape to the current head. A missing required table (including asset_installs) or malformed shape in a supported version is incompatible even when its ledger version equals head. Compatible auxiliary tables, indexes and triggers remain accepted.

StateGlyphDetail lineIssue
Empty database, or no DB file✗no database — run: cafleet setupyes
Incompatible identity, required shape or ledger✗database format is incompatible at 'PATH'; choose an empty database path and run 'cafleet setup'.yes
Compatible identity/shape and recorded <M> = <N>✓schema <N> (head)no
Compatible identity/shape and recorded <M> < <N>✗schema <M>, head is <N> — run: cafleet setupyes
Valid application identity/ledger and recorded <M> > <N>✗schema <M> is newer than this CLI (head <N>) — upgrade cafleetyes

Connection and SQL inspection failures render ✗ with their actual cause as the detail line (one issue). Doctor completes the coding-agents section for every database result. It reads recorded installs only for a compatible at-head database. Every other database state renders resolvable agents as –, with no recorded versions or superseded footnotes, and contributes one database issue to exit status 1. A dropped asset_installs table therefore produces the incompatible-format diagnosis before any install-row lookup.

Coding agents section

A light box-drawing framed table (┌ ─ ┬ ┐ │ ├ ┼ ┤ └ ┴ ┘), header separator only, no per-row rules. Column alignment uses display width, never byte length. One row per agent in the fixed order claude, codex, opencode.

ColumnContent
coding agentThe agent name.
pathThe resolved identity path (Config-dir resolution), with ~ abbreviation when under $HOME. On a resolution error: the raw invalid variable value.
sourceThe winning origin: $<VAR> (e.g. $CLAUDE_CONFIG_DIR) or default.
setupThe setup state below, keyed on the resolved path only.
StateCellIssue
A row exists at the resolved path, version = CLI version (string equality)✓ <version>no
A row exists at the resolved path, version ≠ CLI version (string inequality, either direction — never semver comparison)✗ <recorded-version> → cafleet setup --coding-agent <agent>yes
No row exists at the resolved path (regardless of rows elsewhere)– cafleet setup --coding-agent <agent> (– U+2013 EN DASH)never
The agent's config-path variable fails validation (caught per-agent, not fatal)✗ <VAR> is not an absolute pathyes

Records at other paths only feed informational footnote lines under the table, one per superseded row, ordered ascending (coding_agent, path), ~-abbreviated:

note: <agent> was previously set up at <path>

Footnotes are informational — they never count as issues.

Member permissions section

Reports every Claude Code setting that would stop a claude member from running its broker commands, so the failure is visible before a spawn. The section runs for claude when the claude assets are installed, and reads each of these files that exists:

FileLocation
User settings<claude config dir>/settings.json, per Config-dir resolution
Project settings<cwd>/.claude/settings.json and <cwd>/.claude/settings.local.json
Managed settings/Library/Application Support/ClaudeCode/managed-settings.json on macOS, /etc/claude-code/managed-settings.json on Linux

Each rule is tested against the broker-command probe registry, maintained as PROBE_COMMANDS in the permission probe source. A representative probe is cafleet message listen 1 --timeout 300. This checks Bash command rules; native Monitor authorization is verified separately.

A rule matches a probe when it is the bare Bash, or Bash(<pattern>) whose pattern matches the probe. * matches any text; a trailing * or the legacy :* also matches the bare command.

FindingCondition
Blocking ruleA permissions.deny or permissions.ask rule in any file matches a probe.
Managed rules onlyThe managed file sets allowManagedPermissionRulesOnly to true and its own permissions.allow does not match every probe.
Unreadable fileA settings file exists but does not parse as JSON. A missing file is expected and is not a finding.

With no finding the section is ✓; otherwise it is ✗ with one detail line per finding, and each finding is one issue:

✓ member permissions
  claude: no setting blocks the member broker commands

✗ member permissions
  claude: ~/.claude/settings.json permissions.deny "Bash(cafleet *)" matches "cafleet message send --from-member-id 1 --to-member-id 2 x"
  claude: <file> allowManagedPermissionRulesOnly is true and its permissions.allow does not match "<command>"
  claude: <file> is not valid JSON

The three ✗ lines are, in order, a blocking rule (naming the file, the list, the rule, and the probe it matches), the managed-rules-only finding (naming the first unmatched probe), and an unreadable file.

When the claude assets are not installed the row reads claude: – not installed and never counts as an issue.

The section cannot see a blocking PreToolUse hook, or a rule added after a member is spawned — see Spawn-time allow rules.

Last line: no issues found, 1 issue found, or <N> issues found (proper pluralization). Exit code: 0 when no issues, 1 otherwise — the – state and footnotes never count. Every failure is a rendered issue; no failure exits before output.

--json

Mirrors the sections with ok booleans, unabbreviated absolute paths, and the issue count. source holds the winning env-var name (no $) or the literal "default"; state is "ok" | "stale" | "not_installed" | "error" ("error" is the per-agent resolution-error state; "not_installed" never contributes to issues). Every agent row carries the same keys. error is the validation message for "error", and otherwise null, without an Error: prefix. Section error fields likewise hold the detail text when ok is false, else null.

{
  "multiplexer": {
    "ok": true,
    "backend": "tmux",
    "session": "main",
    "window_id": "@3",
    "pane_id": "%0",
    "presence_var": "TMUX",
    "presence_value": "/tmp/tmux-501/default,12345,0",
    "error": null
  },
  "database": {
    "ok": true,
    "schema_version": 1,
    "head_version": 1,
    "error": null
  },
  "coding_agents": {
    "ok": false,
    "cli_version": "0.22.0",
    "agents": [
      {"coding_agent": "claude", "path": "/Users/x/cfg/claude", "source": "CLAUDE_CONFIG_DIR", "recorded_version": "0.22.0", "installed_at": "2026-08-12T00:00:00.000000+00:00", "state": "ok", "error": null},
      {"coding_agent": "codex", "path": "/Users/x/.codex", "source": "default", "recorded_version": "0.21.0", "installed_at": "2026-08-01T00:00:00.000000+00:00", "state": "stale", "error": null},
      {"coding_agent": "opencode", "path": "/Users/x/.opencode", "source": "default", "recorded_version": null, "installed_at": null, "state": "not_installed", "error": null}
    ],
    "superseded": [
      {"coding_agent": "codex", "path": "/Users/x/.codex-old", "recorded_version": "0.20.0", "installed_at": "2026-07-01T00:00:00.000000+00:00"}
    ]
  },
  "member_permissions": {
    "ok": true,
    "findings": []
  },
  "issues": 1
}

member_permissions sits between coding_agents and issues. Each element of findings carries the keys coding_agent, file, list, rule, and command, in that order:

Findinglistrulecommand
Blocking rule"deny" or "ask"The matching ruleThe probe it matches
Managed rules only"allowManagedPermissionRulesOnly"nullThe first unmatched probe
Unreadable filenullnullnull

Each finding adds one to issues.

On a multiplexer failure the multiplexer object is {"ok": false, "backend": null, "session": null, "window_id": null, "pane_id": null, "presence_var": null, "presence_value": null, "error": "<message>"}. On an agent resolution error the row is {"coding_agent": "...", "path": null, "source": "<VAR>", "recorded_version": null, "installed_at": null, "state": "error", "error": "<VAR> must be an absolute path (got '<value>')"} — the raw invalid value appears only inside error; path stays null because no path resolved. schema_version contains the recorded version after identity and ledger validation, plus shape validation for supported versions. A newer version retains its recorded version without a head-shape comparison; incompatible or missing state uses null. For every non-ok database report, recorded installs are not read: resolved agents use "not_installed", path errors remain "error", recorded fields are null and superseded is empty. A missing asset_installs table is an incompatible database state. Exit-code semantics are identical to text mode.

cafleet message — Message Broker

message send

cafleet message send --from-member-id ID --to-member-id ID (TEXT | --file PATH) [--json]

Resolve the complete text body before starting the five-second persistence/notification budget, including when --file - waits for stdin. Persist one point-to-point delivery, then drain an ordinary recipient's pending messages oldest-first into its concrete pane within the remaining budget, the new message included. Root-Director messages use native or manual broker reads: sends succeed with notification_sent=false, no pane-delivery diagnostic and no multiplexer requirement. Self-sends persist with no pane input. A committed/persisted send remains successful with exit 0; held/unavailable ordinary-member notifications preserve the stdout record and notification_sent=false.

notification_sent is true exactly when this invocation delivered the newly committed message, including when it was drained after an older one. When another invocation delivered the new message, notification_sent stays false and stderr carries no diagnostic; the recipient still received the line. Messages left pending when the budget no longer covers another submission stay pending with no diagnostic; the next send to that recipient or a message wait rotation retries them. Push notifications specifies the line, the drain and under-lock revalidation.

Delivery outcome

A notification failure prints Message NEW_ID was persisted. followed by its diagnostic on stderr, without suppressing successful stdout. Every per-attempt failure uses this diagnostic:

message MESSAGE_ID was not notified to member MEMBER_ID: CAUSE; the next send to member MEMBER_ID or the next message wait retries it.
FailureCAUSE
The pane input lock stays busy through the lock waitpane input remained busy
Lock acquisition errorpane input: <lock error>
Multiplexer resolution or availability errorThe multiplexer error text
Budget cannot cover literal input, settle and Enter before the first lineinsufficient pane input budget for literal input, settle and Enter
Transport error before or during typingThe transport error text
Database busy or deadline exceeded during the under-lock snapshot or notification stampThe storage error text; names the current candidate, or the candidate from placement revalidation when selection has not completed
message wait attempt fails with database busy or deadline exceeded before selecting a candidateThe storage error text; names the selected rotation entry

A lock wait that ends after another sender delivered every pending message reports nothing. Other failures, including corrupt, incompatible or unreadable storage and a termination-span start failure, retain their causes after the persisted prefix. Storage failure before commit exits 1 with its cause. Consume an existing committed ID once; notification failure supplies no reason to create another delivery.

After a failed delivery the sender sends exactly one follow-up to the same recipient with the body message N was not delivered to your pane; poll your inbox. Its drain retries N first. When the follow-up also fails, the sender stops.

message poll

cafleet message poll MEMBER_ID [--json] returns only incoming input_required records, descending by status timestamp/message ID. Unknown or inactive member: Member ID not found, exit 1.

message wait

cafleet message wait MEMBER_ID [--timeout SECONDS] [--json]

Timeout is an integer in 1..=1800, default 300. Validate an active subject and live fleet. Existing unread deliveries return immediately; otherwise check at one-second monotonic intervals. The invocation is a blocking receive for scripts and manual use and never ACKs messages.

Between inbox checks, retry pending deliveries for at most one ordinary member per interval with an in-memory round-robin cursor. Select concrete ordinary-member placements in the fleet, excluding its root Director, the wait's own subject, self-notifications, ACKed and already-notified rows. Each attempt drains that member's pending messages under the delivery procedure without consulting pane state. One invocation attempts each pending message at most once; a failed message is retried by a later send or wait invocation, while later messages for the same member remain eligible. Recheck the inbox before starting another attempt. Shared input locks and under-lock revalidation keep multiple waiters safe.

Start each receive check or notification attempt before the monotonic receive deadline. An attempt already in flight retains its original five-second budget for the lock wait, revalidation, Escape, typing, settle and Enter. A busy pane lock makes the attempt wait up to 1.5 seconds; a lock still busy then records the not-notified diagnostic in notification_errors. Cap subprocess/database busy waits to its remaining budget and start input only with time reserved for settle and Enter. Mandatory database finalization uses the later of the original deadline and one second after finalization begins, keeping pane transport within its original budget. A receive returns by its deadline plus at most one six-second in-flight attempt/finalization allowance. A snapshot blocked until receive expiry returns timeout with retained notification diagnostics; earlier transient contention can retry before expiry. Corruption and other fatal storage errors retain their causes.

The ordered JSON result is:

{"member_id":41,"outcome":"timeout","messages":[],"notification_errors":[]}

outcome is messages with nonempty full poll records, or timeout with an empty array. Each diagnostic has ordered keys {member_id, message_id, error}. Keep one diagnostic per not-notified message, ordered by message ID.

Pending placement and a placement change under the lock are ordinary holds that keep entries unchanged. A drain that notifies a recorded message removes that message's entry. Reconcile diagnostics with each successful receive snapshot and the typed observations of its owned notification attempt. Remove entries when these observations show that message ACKed, its recipient gone or the message notified by any invocation. After receive expiry, return the last successful snapshot reconciled with the completed attempt's observations. Subsequent external changes become visible to the next invocation; final reconciliation starts no additional I/O or tail budget.

Text is Messages available for member ID. plus normal messages, or Timed out waiting for member ID.; diagnostics go to stderr. Both outcomes exit 0. Deleted subject/fleet or corrupt/unreadable state exits 1 with its cause and retains earlier notification diagnostics on stderr, including when JSON output was requested. Ctrl+C outside a delivery attempt terminates the process normally; inside an attempt it takes effect when the attempt's termination-deferral span ends.

A script or operator uses message wait for finite manual reception and ordinary-member retry recovery, then polls and ACKs consumed messages. Native Director reception retains the existing listener process between events.

message listen

cafleet message listen MEMBER_ID [--timeout SECONDS]

Stream any active member's pending inbox through UTF-8 JSONL. Derive and pin its fleet at startup, using the configured database and ordinary schema/assets guards. Require a live root Director with a concrete registered placement, without resolving a multiplexer or checking its executable/physical pane. The subject's own placement may be absent. Unknown/inactive startup subjects use Member ID not found, exit 1.

SurfaceContract
LeaseOptional integer 1..=1800; absence runs until closure, cancellation or failure
ExpiryOne monotonic lease from startup; activity leaves expiry unchanged
OutputCompact tagged JSON object plus LF, flushed per record; JSON strings escape controls/newlines
StartupValidate/pin identity, then emit and flush ready before replay
IdleCheck immediately, then wait one second after a snapshot emits zero new IDs, shortened by the lease
CompletionFlush closed, then exit 0 for expiry or normal subject/fleet closure
FailureDiagnostic on stderr and exit 1; parser usage errors retain exit 2

The command always emits JSONL; text mode and --json are absent. Stdout contains protocol records only:

{"event":"ready","member_id":1,"fleet_id":1}
{"event":"message","message":{"message_id":12,"from_member_id":2,"to_member_id":1,"created_at":"2026-10-25T00:50:00.000000+00:00","status_state":"input_required","status_timestamp":"2026-10-25T00:50:00.000000+00:00","text":"complete (doc)\nFull original body"}}
{"event":"closed","member_id":1,"reason":"timeout"}

The inner message is exactly the full message record, preserving original text beyond CLI/pane limits. closed.reason is timeout, member_inactive or fleet_deleted; fleet deletion takes precedence when both lifecycle closures are observed. Check normal closures before revalidating a continuing live fleet. Missing persisted rows, changed fleet identity, invalid stored enums/root relationships or missing root placement are fatal errors.

Each short read transaction validates identity and selects every input_required record for the pinned subject ordered by (created_at ASC, message_id ASC). Commit before output or sleep. A later commit with an earlier timestamp emits when first observed. A process-local ID set suppresses already-emitted pending IDs; insert only after the complete record and LF flush successfully. Retain only IDs still pending in successful snapshots; a failed snapshot leaves the set unchanged. A snapshot containing only previously emitted pending IDs waits one second, while newly emitted records permit immediate recheck.

Listening leaves consumption and notified_at unchanged and performs no pane retry, lock or dispatch. Stamped pending self-sends remain stream-eligible. Concurrent listeners are independent read-only observers with no consumer lock; restart replays all pending IDs. ACK-before-snapshot removes a message, while ACK racing with buffered output may leave a stale pending envelope. Reconcile known/replayed IDs with poll --json or show --json before acting, record deferred actions and explicitly ACK consumption. Completed records need no second action or ACK.

Each snapshot has a fresh database deadline at most five seconds away, shortened by the remaining lease. Scoped busy waiting and an execution progress handler every 1,000 VM instructions bound lock/SQL work. Check that deadline before/after prepare and execution, before/after decoding each row and before commit. Expiry discards partial snapshots; interrupted SQL maps to deadline exceeded only when that deadline expired. Restore busy handling and remove the listener-owned progress handler on every path, preserving cleanup failures alongside the original cause. These cooperative boundaries include row collection without claiming hard real-time preemption of one allocation or SQL operation.

Output owns one serialized record at a time and applies backpressure before selecting more messages. Nonblocking filesystem/poll output preserves/restores descriptor flags on normal return, resumes partial writes from their byte offset and checks every write/flush. Its five-second deadline is shortened by the lease. Broken pipe, write-zero, flush failure or output deadline exhaustion terminates visibly with exit 1, even after partial records. Normal lease expiry between records uses a separate bounded final write for closed. Complete records survive a later error; an incomplete final line remains unconsumed and recovers through broker replay. Only the current snapshot, one record and pending emitted IDs occupy listener memory.

Database contention retries stay inside the snapshot budget; exhaustion or another fatal error terminates the stream. The listener retains its connection/PID across healthy events and ordinary signal behavior outside pane termination deferral. Host cancellation may end it without closed. Native owners retain one handle, reconcile durable state after failure and establish old-process termination before replacement. The manual lifecycle explains operation; installed backend instructions own concrete native tool recipes and their evidence limits.

message ack

cafleet message ack MESSAGE_ID [--json] transitions an existing unread message to completed, updating its status timestamp. The recipient/fleet derive from that row. ACK signifies consumption.

message show

cafleet message show MESSAGE_ID [--json] returns one full record. Existence is the read guard.

cafleet member — Member Lifecycle + Pane Interaction

Member targeting and key delivery

Require an active member and placement for pane operations; concrete pane IDs remain opaque. Pending placement is valid during creation and yields contextual prompt/exec/capture errors. Missing placement fails pane actions; list/show retain diagnostic nulls. Prompt and exec reject the root Director before pane I/O; individual member deletion protects it.

member create

Register a member and spawn its coding-agent pane. It takes no identity flag: the acting Director is auto-resolved from fleets.director_member_id first thing, before registration (the resolved id also feeds the member's backend inheritance and the spawn-prompt substitution). A fleet has exactly one root Director by construction, so no override flag exists.

ArgumentRequiredNotes
--fleet-idyesThe fleet the new member joins — a relationship flag; the subject of the command is the member being created.
--nameyesDisplay name — see Known asymmetries for pane-title behavior.
--descriptionyesOne-sentence purpose.
--coding-agentnoOne of claude, codex, or opencode; when omitted, the member — every role — inherits the spawning Director's placement backend. Exits 1 with Error: binary <name> not found on PATH when the binary is missing. The opencode backend additionally requires its agent preset at the resolved preset path (via OPENCODE_CONFIG_DIR — see Config-dir resolution); a missing preset or an invalid variable exits 1 per Error Messages.
--modelnoModel forwarded to the backend binary's own --model flag. The opencode backend additionally requires <provider-id>/<model-id>; per-backend formats and create-time validation are in Model selection.
--effortnoReasoning-effort level forwarded to the backend binary, validated per backend before any side effect. Accepted levels, forwarding forms, and rejection strings are in Reasoning effort.
positional PROMPTone ofInline spawn prompt (backend-neutral template). Exactly one of PROMPT / --file.
--file PATHone ofPath to a UTF-8 file whose contents are the spawn prompt (- = stdin). Follow the shared body-input and transport contract.
--jsonnoOutput as JSON

Spawn command per backend

The per-backend spawn argv and auto-approval flags live in Coding-agent backends.

Spawn-prompt substitution

member create renders its resolved spawn prompt body with the same formatter, substituting exactly four placeholders:

PlaceholderSubstituted valueHow the spawned member sees it
{fleet_id}The member's fleet idFLEET ID: <fleet_id>
{member_id}The member's own newly-allocated idYOUR MEMBER ID: <member_id>
{director_member_id}The fleet's root Director idDIRECTOR MEMBER ID: <director_member_id>
{coding_agent}The resolved backend name (claude, codex, or opencode)CODING AGENT: <coding_agent>

Identity reaches the spawned member as literals rendered into its prompt; the only environment variable forwarded into the pane is CAFLEET_DATABASE_URL. The formatter accepts only the four exact names above and doubled literal braces ({{ / }}), not Python format specifications, conversions, or attribute/index access. An unknown placeholder or malformed brace expression exits 2. Member creation attempts deregistration; fleet creation attempts bootstrap transaction rollback. Cleanup failures follow the primary error (see Error Messages).

The spawn always creates the pane without stealing focus (tmux split-window -d): the Director's pane and active window stay active. In the default output, pane renders (pending) until the pane id is patched onto the placement.

Creation failure compensation

Member creation registers a pending placement, renders the prompt, creates a pane, and patches its id. The CLI owns a registration guard after successful registration and acquires a pane guard only when split_window succeeds. The backend owns the pane before that return; see pane ownership.

Failure pointCompensation orderDB result when compensation succeeds
Member registrationBroker rolls back registration; no pane guard existsNo new member or placement
Member placeholder expansionCLI deregisters; no pane was createdMember becomes deregistered and placement is removed
Member Herdr run after split returned an idBackend tries pane kill, returns the error, then CLI deregistersMember deregistered and placement removed
Member placement update error or missing rowAfter handling the failed SQL, CLI kills pane, then deregistersMember deregistered and placement removed

Continue remaining compensation even if an earlier cleanup fails. A backend PaneCleanup::Attempted result is never killed again by the CLI. A failed split with no confirmed id reports that the pane id is unknown and cleanup is unconfirmed, including for member creation; it does not infer which other pane should be closed. Creation rollback uses kill_pane(id, true).

Keep the primary cause and its exit category. Member split failures retain the primary reason tmux split-window failed: <error>; placement errors retain placement update failed: <error> or placement row vanished before pane-id patch. Placeholder failures retain their usage error and exit 2. Append applicable cleanup diagnostics after the primary error, on stderr:

  • cleanup failed for pane <id>: <detail>
  • cleanup failed for member <id>: <detail>
  • cleanup failed for fleet <id> transaction: <detail>

Report transaction rollback failures explicitly. Existing rollback-success suffixes may describe confirmed compensation; they must not claim success or complete rollback when cleanup failed or pane compensation is unconfirmed. Guards disarm through explicit finish/rollback, preventing repeated kill or deregistration; Drop handles only remaining unhandled ownership. Once a member placement is confirmed , disarm all creation guards before the existing emit call. Successful text/JSON output keeps its shape, ordering, and nulls. No new stdout-failure exit or diagnostic contract is introduced.

member delete

Lock the concrete placement before kill/deregistration. A member without a concrete pane needs no lock. Retry contention every 50 milliseconds against one five-second deadline; expiry exits 1 with member ID's pane input remained busy for 5 seconds; member was not deleted. and leaves state unchanged. Preserve pane/registry errors and layout cleanup ownership.

Revalidate pending or absent placement and deregister atomically. For a concrete pane, retain input ownership while closing it outside a SQLite write transaction, then revalidate and finalize the registry. After successful close, mandatory registry finalization uses the later of the original deadline and one second after finalization begins, allowing short reader/writer contention to clear; actual database failures report that the pane was closed and preserve the database cause. Optional layout work follows mandatory finalization within the original deadline. A failed or expired restoration emits a stderr diagnostic while preserving successful deregistration.

member show

cafleet member show MEMBER_ID [--json] — the positional MEMBER_ID names any active registry entry — placed or placementless (root Director included).

Registry read — no multiplexer requirement. Text is the compact one-line row; the detailed view — including kind (director / member) and the placement sub-dict — is the --json payload (see Output shapes).

member list

cafleet member list FLEET_ID [--json] — the positional FLEET_ID names the fleet whose roster is listed; no identity flag. Lists every active registry entry of the fleet — the root Director, ordinary members, and placementless rows. An empty roster prints 0 members..

Field projection and absent values are in Member list output.

Rows and activity follow the data-model query contract. Text idle values render as Ns / Nm / Nh. Per-member detail such as description and registered_at lives on member show.

member prompt

cafleet member prompt MEMBER_ID TEXT [--json] validates a nonblank line without CR/LF or C0/DEL controls, otherwise exits 2 with text must be one non-empty line without control characters.

A root Director target exits 1 with cannot prompt the Director's own pane before any pane I/O, because Escape would interrupt the Director's own running turn. Otherwise acquire the shared input lock within its bounded wait and revalidate activity/placement. Submit the Director-authored text unchanged with the Escape lead: Escape, settle, literal text, settle and Enter. Escape can interrupt a working turn or dismiss an open prompt in the member pane. Exit 0 means submission only, with {member_id, pane_id, text}.

A lock still busy when the wait ends uses member ID's pane input remained busy; prompt was not dispatched. Pre-write error, including an Escape failure: prompt was not dispatched to member ID: CAUSE. Partial uncertainty: prompt delivery to member ID is uncertain: CAUSE. Inspect the pane before retrying. These exit 1 without a success record.

member exec

cafleet member exec MEMBER_ID COMMAND [--json] or cafleet member exec MEMBER_ID --file PATH [--json]; --file - reads stdin. Exactly one source is required. File/stdin is UTF-8 and strips at most one terminal LF or CRLF. Preserve inline bytes exactly.

Require a nonblank line without CR/LF, NUL or other C0/DEL controls, including tabs. Invalid input exits 2 before pane I/O with command must be one non-empty line without control characters. A multiline task supplies a one-line explicit script invocation.

Resolve an active ordinary member and concrete placement, reject the root Director, lock input within its bounded wait and reload. With the Escape lead, send Escape, settle, type native shell input ! followed by the actual command once, settle and Enter. The backend owns working directory, environment, permissions, output and exit rendering.

Successful exit 0 establishes complete submission/dispatch only. Ordered JSON is:

{"member_id":42,"pane_id":"w1:p2","coding_agent":"codex","command":"printf example","dispatched":true}

Text: Dispatched native command to member ID (PANE). Inspect the pane for its result.

ConditionError body (exit 1)
Root Directorcannot exec in the Director's own pane
Pending placementmember ID has no pane yet (pending placement) — nothing to exec.
Input lock still busy when the wait endsmember ID's pane input remained busy; native command was not dispatched.
Escape or transport failure before typingnative command was not dispatched to member ID: CAUSE
Typing may have begunnative command delivery to member ID is uncertain: CAUSE. Inspect the pane before retrying.

The first text-writing call can partially type even if it fails. Failure after Enter may mean execution began. Inspect native pane output before any newly authorized retry. The command writes no execution ledger, helper script or wrapper and returns only dispatch metadata. The Director authorizes native input under its host rules; visibility establishes no second member-tool permission check.

After native completion, inspect the pane and send an explicit prompt to use the output and continue when the host has not resumed the member.

member capture

cafleet member capture MEMBER_ID [--lines N] [--ansi] [--json] — the positional MEMBER_ID names the target member.

  • --lines: Number of trailing lines to capture (default: 20).
  • --ansi: Preserve ANSI escapes in the raw capture. The default strips ANSI escapes and cleans carriage-return redraws.

Output shapes are in Output shapes; target resolution is shared with the member keystroke verbs — see Member targeting and key delivery. A pending placement is a hard error (see Error Messages).

JSON stamps captured_at from the local UTC clock at the capture read boundary and computes content_sha256 = sha256(content.encode("utf-8")) from the exact emitted content. The default mode hashes the ANSI-stripped, carriage-return-defragmented string; --ansi hashes the ANSI-preserving string. No normalization occurs after the selected mode, and capture content is never stored in SQLite.

The shared CaptureSnapshot::from_raw(raw, ansi, now) supplies this content, timestamp, and lowercase SHA256 hex for both member capture and fleet capture. It hashes the final selected content's UTF-8 bytes, including Unicode and empty captures. Existing line validation/windowing and timestamp format stay unchanged. Text member capture prints content without adding a newline; JSON retains its existing fields and ordering.

Error Messages

Application errors print as stderr text even with --json; the flag selects successful output. Input errors use the documented usage/application category. Dispatch, input-lock, compatibility and deletion-lock errors are specified at their action owners above.

CommandSituationError messageExitNotes
(any surface resolving a config dir)A set config-path variable holds a non-absolute value (empty string and relative paths included)Config-path validation1See Config-dir resolution; doctor renders it as a per-agent issue instead
(any non-setup command)The recorded schema version is behind the embedded headSchema-version guard1See Schema-version guard
(any non-setup command)No schema ledger and no app tables (missing or empty DB file)Schema-version guard1See Schema-version guard
(any non-setup command)No schema ledger but app tables presentSchema-version guard1See Schema-version guard
(any non-setup command)The recorded schema version is ahead of the embedded headSchema-version guard1See Schema-version guard
(any fleet-scoped command)No agent has an asset_installs row at its currently-resolved pathStale-assets guard1See Stale-assets guard
(any fleet-scoped command)An asset_installs row at a resolved path differs from the runtime CLI versionStale-assets guard1See Stale-assets guard
member create--coding-agent opencode with no agent preset at the resolved preset pathError: opencode agent preset not found at <preset>; run 'cafleet setup --coding-agent opencode' first1<preset> is the resolved <preset base>/agents/cafleet.md — see Config-dir resolution
setupNo database remains after a failed db half, or asset_installs is removed after the assets-half format checkthe database schema is missing or outdated; run 'cafleet setup' first1An assets-half failure
(any subject-taking command)Missing positional subject idThe parser's native missing-required-argument error naming the positional2—
(any id argument)A non-integer idThe parser's native invalid-value error2—
fleet createRun outside a supported multiplexerError: cafleet fleet create must be run inside a tmux or herdr session1No DB writes
fleet show / fleet deleteUnknown FLEET_IDError: fleet 'X' not found.1—
member createUnknown --fleet-idError: Fleet '<fleet-id>' not found.2Director auto-discovery runs first thing
member createInto a soft-deleted fleetError: fleet X is deleted1—
member createThe fleet row has no director_member_id recordedError: fleet <fleet-id> has no root Director recorded; re-create the fleet with 'cafleet fleet create'.1Mid-bootstrap corruption
member createWith a placement, when the fleet's root Director is not an active memberError: fleet <fleet-id>'s root Director (member <id>) is not active.1The register_member invariant guard
member deleteAgainst the root Director's idError: cannot deregister the root Director; use 'cafleet fleet delete' instead1—
message pollAn unknown or inactive MEMBER_IDError: Member <member-id> not found1—
message ack / message showAn unknown MESSAGE_IDError: Message <message-id> not found1—
message ackA message not in the input_required stateError: Cannot ACK message in state <state>1—
message sendThe sender is unknown or inactiveError: Sender member not found or not active: <from-member-id>1—
message sendThe recipient is unknown or inactiveError: Destination member not found: <to-member-id>1—
message sendSender and recipient in different fleetsError: members <from-member-id> and <to-member-id> are not in the same fleet.1—
member promptThe target is the fleet's root DirectorError: cannot prompt the Director's own pane1Before any pane I/O
member execThe target is the fleet's root DirectorError: cannot exec in the Director's own pane1—
member capture / member prompt / member execThe member has a pending placementError: member <id> has no pane yet (pending placement) — nothing to <capture|prompt|exec>.1—
member show / prompt / exec / captureAn unknown or inactive target member idError: Member <member-id> not found1—
member prompt / exec / captureA target with no placement rowError: member <member-id> has no placement row; it was not spawned via `cafleet member create`.1—
message send / member createNeither the positional body nor --file, or bothThe parser's native argument-group error2—
message send / member createPositional body empty or whitespace-onlyError: text may not be empty.2—
message send / member create--file <path> to an empty (zero-byte or whitespace-only) fileError: --file <path>: file is empty.1—
message send / member create--file - with empty or whitespace-only stdinError: --file -: stdin is empty.1—
message send / member create--file <path> to a non-existent path or non-regular fileError: --file <path>: file does not exist or is not a regular file.1—
message send / member create--file <path> to an unreadable fileError: --file <path>: file is not readable.1—
message send / member create--file <path> to a file containing invalid UTF-8Error: --file <path>: file is not valid UTF-8.1—
member create--coding-agent opencode --model violating the <provider-id>/<model-id> formatBackend model error2Fires before any side effect
member create--effort with a level unknown to the claude backendBackend effort errors2Fires before any side effect
member create--coding-agent codex --effort with an unknown levelBackend effort errors2Fires before any side effect
member create--coding-agent opencode --effort with any valueBackend effort errors2Fires before any side effect
member createAn unknown {placeholder} in the promptError: Unknown placeholder '<name>' in custom prompt. Supported placeholders: {fleet_id}, {member_id}, {director_member_id}, {coding_agent}. Double literal braces ({{, }}) to keep them as text.2member create attempts deregistration; cleanup failures follow the primary error
member createA malformed brace expression in the promptError: Malformed custom prompt: <detail>. Double literal braces ({{, }}) to keep them as text.2member create attempts deregistration; cleanup failures follow the primary error
member create--coding-agent omitted and the spawning Director not found in the fleetError: cannot resolve the member's coding agent: Director <director-id> not found in fleet <fleet-id>. Re-run with an explicit --coding-agent.1Nothing spawned
member create--coding-agent omitted and the spawning Director has no placement rowError: cannot resolve the member's coding agent: Director <director-id> has no placement row recording its backend. Re-run with an explicit --coding-agent.1Nothing spawned