ai-conductor CLI reference

Every command, subcommand, flag, and exit code of the ai-conductor engine. Commands are grouped operator-first: the ones you type, then the ones the engine invokes on your behalf.

The supported launcher is ai-conductor. The installed conduct alias resolves to that launcher, prints a one-line deprecation warning, and remains available only during the migration window.

Launcher

bin/ai-conductor is a shim. It parses none of its own arguments and passes everything through to the bundled engine at src/conductor/dist/index.js, resolving the dist symlink to a concrete dist-versions/<id>/index.js so a running process is pinned to one engine version. It exports ASDF_NODEJS_VERSION from src/conductor/.tool-versions when asdf is on PATH, then execs node, so the engine’s exit code is the shim’s. The current pin is Node.js 26.7.0, and the engine requires Node >=26.0.0 when the asdf override is unavailable.

Condition Message Exit
dist neither exists nor is a symlink ai-conductor: missing … plus run 'npm run build' in src/conductor/ 1
dist symlink unresolvable or not a regular file ai-conductor: dist symlink is broken (…) 1
Uncaught engine error Fatal: <message> 1

The bundled skills/intake/scripts/intake-file helper, bin/intake-backfill, and bin/quarantine-engineer-signals are separate entry points, not ai-conductor subcommands.

ai-conductor --version

ai-conductor --version
ai-conductor -V
ai-conductor version

Prints one line naming the installed harness and the engine build actually executing, then exits 0:

ai-conductor 0.104.0 (engine 20260830T172539Z-76db750aa2a8)

The first value is the repo VERSION file; the second is the pinned dist-versions/<id> the launcher resolved — the same build id daemon status prints as version:<id> and a shipped record stamps as engine_version. Both are resolved relative to the running module, not the working directory, so the report is correct when the CLI is reached through the installed ~/.local/bin/ai-conductor symlink.

The command is advisory and never fails: an unreadable VERSION file reports 0.0.0, and an unpublished dev/tsx run — which pins no dist-versions/<id> — reports engine dev. All three spellings must be the whole invocation; ai-conductor daemon --version is a daemon invocation, not a version request. Like every other unsanctioned command it is refused inside a daemon-managed session (see Daemon-session refusal).

ai-conductor update

ai-conductor update [args...]

Runs the owning harness checkout’s bin/update from any working directory. It forwards every argument, inherits the terminal, and returns the updater’s exit status. Use the same options as bin/update, for example:

ai-conductor update --set-channel stable

The command exits 1 without starting an updater when it cannot find the harness checkout, its bin/update, or a checkout .git directory. Its diagnostic names the failed path or root.

bin/install

bin/install --channel <stable|tagged|main>

On a first install, --channel records the selected update channel without prompting. It takes precedence over AI_CONDUCTOR_CHANNEL; with neither explicit value, an interactive installer prompts and a non-interactive installer falls back to stable. Empty environment values are treated as unset; an invalid explicit value exits before installation writes global state. The option is first-run only: change an existing selection with bin/update --set-channel.

bin/update

bin/update
bin/update --auto
bin/update --set-channel <stable|tagged|main>

With no arguments, forces an attended check of the configured harness update channel. --auto honors conductor.auto_check and is the startup form spawned by ai-conductor. --set-channel accepts stable, tagged, or main and changes configuration without moving the checkout.

stable is the fresh-install default. It fetches origin/stable, verifies that its head is an exact semver tag, requires a clean local stable checkout and a fast-forward relationship, then prompts before fast-forwarding to that captured commit and running bin/migrate. An untagged target is rejected before local mutation. If migration fails after the fast-forward, the updater restores the prior stable branch head and recorded version.

A stable checkout left in detached HEAD — as a pre-v1 updater’s git checkout vX.Y.Z did — is recovered rather than skipped. When HEAD is detached and is an ancestor of (or equal to) origin/stable, the updater offers to re-attach the stable branch at the approved release commit, then runs bin/migrate; without a TTY it prints git checkout -B stable <sha> && bin/migrate instead. The offer is made even when HEAD already equals origin/stable, because the detachment is itself the defect. A detached HEAD outside origin/stable’s ancestry is a deliberate checkout and is left untouched, and every other guard — exact semver tag, clean worktree, and applying only the approved SHA — is unchanged. tagged follows semver tag checkouts; main follows every merge to the development branch.

bin/migrate

bin/migrate [--yes|-y] [--dry-run]

Runs bin/install --update, then, from a consumer project, finds runnable bash migration fences in each release through the installed target version. If it cannot read the installed-version configuration, it exits non-zero before selecting migrations. On a project’s first run, the lower bound is the recorded currentVersion (or the target version itself, if currentVersion is an unparsable channel identity such as main@<sha>); that bound is then pinned into the ledger as its candidateBaseline and used on every later run, so it stays fixed even as currentVersion advances. It exports HARNESS_DIR to every block. Blocks are ordered by release version and document position.

--dry-run shows the install action and selected migrations without executing or recording them. Without --yes, an interactive run previews each block and accepts yes, no, all, or stop; skipped and stopped blocks remain pending. Without a TTY and without --yes, it executes no project migrations and leaves every block pending. --yes executes each selected block without prompts.

After each successful block, the runner records its release and content digest in a per-project, human-readable ledger under ~/.ai-conductor/migrations/. A recorded digest is already applied; changed content at the same release is a new candidate. A failed block stops the run immediately: earlier successful blocks remain recorded and later blocks remain pending. Unknown flags exit 2. Every run, including a failure, ends with Migration summary: applied=<n> skipped=<n> failed=<n> already-applied=<n>.

Exit code conventions

Code Meaning Where it appears
0 Success, or an advisory command that never blocks most commands
1 Usage error, validation failure, or a refused operation most commands
2 Usage guide printed to stderr task, evidence, derive-feedback

Commands that are advisory by contract always exit 0 regardless of outcome: overlap-scan, kpi, shipped-record, shipment-evidence audit, and render-diagrams in its default (non---check) mode.

Daemon-session refusal

Every provider session the engine dispatches (daemon builds, reviews, interactive-conductor steps, self-host candidates — both providers, invoke and interactive paths) carries CONDUCT_DAEMON_SESSION=1 in its environment. When that marker is present, ai-conductor refuses to run — printing ai-conductor may not be invoked from inside a daemon-managed session; the engine owns all conductor operations for this run and exiting 1 — before any subcommand parsing. This exists because dispatched maker sessions have recursively invoked the conductor (including daemon park/unpark/restart and reseal), corrupting the run that dispatched them; the engine that started the session owns all conductor operations for it. The only exceptions are the session-sanctioned worker commands the harness’s own skills and hooks require a session to run — scoped-run, overlap-scan, plan-protected-targets, manual-test-record, closeout-event, and derive-feedback, scope-check, and task (start/done) — which stay available under the marker. There is no config off-switch; enforcement lives in src/conductor/src/execution/daemon-session.ts.

ai-conductor build-review

ai-conductor build-review findings --feature <slug> [--json]
ai-conductor build-review accept --feature <slug> --lap <lap> --finding <id> --rationale <text>
ai-conductor build-review record-reduced-coverage --feature <slug> --lap <lap> --rubric <rubric> --rationale <text>

findings is read-only and renders the current feature’s raw and effective build-review findings plus autonomous remediation-case outcomes; --json includes those cases under cases. Human output keeps autonomous outcomes separate from operator dispositions and includes each case’s disposition, resolution, source ids, effect state, rationale, and, for a refutation, its claim and assertion verdicts. A missing case store is a successful listing with no autonomous cases. An unreadable or unsupported case store makes findings name the store and exit 1 rather than silently omitting its cases. accept changes state only from an interactive terminal with a resolved local operator identity. It requires the exact current lap identity, canonical finding ID, and a non-empty rationale. Acceptance works on every registered rubric — currently only testQuality — because the identity the engine prints is the identity the disposition store accepts back. Stale, unknown, unauthorized, or non-interactive requests are refused without changing artifacts and exit 1; successful findings inspection and accepted exact-current findings exit 0. A refusal names the check that failed — unreadable aggregate, non-current lap, unknown finding, or a disposition-store rejection — and records the same reason on the feature’s build_review_disposition_refused event. record-reduced-coverage also requires an interactive terminal, resolved local operator identity, exact current lap, named rubric, and non-empty rationale. It derives the closed infrastructure cause from the current review state; callers cannot supply one. It records a decision only when that rubric currently has an exhausted mechanical infrastructure fault, or a current projection-oversized fault (which halts without consuming that allowance). Judged, skipped, duplicate, unknown-rubric, allowance-remaining for every other cause, and stale-review requests are refused without changing the decision state.

ai-conductor scope-check

ai-conductor scope-check <commit-message-path>

This hook-only command is invoked by the generated commit-msg hook for a task-attributed commit. It reads the active in-progress task row from .pipeline/task-status.json, compares its declared files with the staged paths, and prints every undeclared path with a Scope: <path> — <rationale> trailer that can justify an intentional widening. It is not an operator workflow; worktree provisioning wires it automatically.

Exit Meaning Hook behavior
0 Allowed, including a verified violation in the default report-only mode Allows the commit; a reported violation remains visible in containment-floor step output and warnings
2 Positive scope refusal when build_review.scopeContainmentEnforced is true commit-msg converts it to exit 1 and blocks the commit without changing the working tree or index
other Abstention: no Task trailer, unusable/missing task state, or a checker failure Logs the abstention and allows the commit

The report-only default is deliberate. Set build_review.scopeContainmentEnforced: true to enable refusal. A Scope: trailer documents a widening; its path, rationale, task id, and commit SHA are supplied directly to build_review, and it never bypasses the grader’s semantic scope judgment.

ai-conductor inline

Runs the SDLC pipeline in the foreground.

ai-conductor inline [options] "<feature description>"

The inline token is mandatory. A bare ai-conductor "<feature>" is rejected with three lines of guidance and exit 1. Commander declares an inline subcommand so ai-conductor inline --help renders, but it never dispatches it — the engine strips the inline token first and parses the remainder against a subcommand-less base program, which is why a free-text feature description is never mistaken for an unknown command.

Positional Arity Required Effect
[feature] 0..1 conditional Feature description. Drives slug and worktree naming and auto-resume matching.

A feature description is required unless at least one state flag is present. The state flags are --resume, --status, --cleanup, --reset, --diagnose, --report, and --from. Without one, parsing throws Feature description is required when no state flags are provided and the run exits 1.

Flag Type Default Constraints Effect
--resume boolean false — With a feature description, honored by the auto-resume gate and clamps the start index. Before dispatch, a resumed run whose derived entry is blocked by an earlier unfinished prerequisite moves back to the earliest dispatchable prerequisite. Without a feature description, cleans up merged worktrees, scans .worktrees/, and shows a selection menu (exit 1 when no features are found), then repoints projectRoot, pipelineDir, and the state file at the selected worktree.
--fresh boolean false — Suppresses auto-resume detection so an existing worktree for the same slug is not silently reused. This is its only effect; it is never passed to the engine’s conductor object.
--auto boolean false deprecated; mutually exclusive with --interactive Prints Error: --auto is deprecated. Use \ai-conductor daemon start` instead; see docs/guides/running-the-daemon.md.` and exits 1 before starting the inline pipeline. Use the daemon for unattended execution and retained logs.
--interactive boolean false mutually exclusive with --auto Run mode interactive: opens a Claude REPL for every conversational step except complexity, conflict_check, architecture_diagram, and rebase. dangerouslySkipPermissions stays off, so a human approves each action.
--status boolean false — Prints ## Conductor State and the state file as pretty JSON, then returns. No provider session.
--from <step> string — must be a step name Sets the start index to that step. Also suppresses auto-resume. An unrecognized step name exits 1, printing the invalid value and every valid step name (built-ins plus any config-declared custom steps).
--cleanup boolean false — Scans resumable features, reads pr_url from each conduct-state.json, checks whether the PR merged, and prompts Remove merged worktree "<name>"? [y/n] per merged feature. Prints a count.
--reset boolean false — Writes an empty state object, prints State cleared., and returns.
--diagnose boolean false — Non-mutating. Resolves the worktree, then verifies state completeness. SHIP-gating steps recorded as skipped are satisfied without an artifact check; steps that ran still require their normal evidence. State OK prints State OK… and exits 0; gaps print a gap report plus remediation text to stderr and exit 1; an orphaned state exits 1.
--report boolean false — Read-only. Renders .pipeline/events.jsonl as step durations, retry hotspots, token spend, and kickbacks by source gate (including BUILD re-entries), then exits 0. A report error exits 1. No provider session.
--cooldown <seconds> integer 10 no range check Seconds to pause between steps. A non-numeric value parses to NaN.
--model <name> string — alias or full model ID Overrides the model for every step. Beats every configured source. See models.
--effort <level> string — one of low, medium, high, xhigh, max Overrides the effort for every step. Beats every configured source. An invalid level exits 1, printing the invalid value and the valid levels.
--view <mode> enum full full, focus, log Dashboard layout. Anything other than exactly focus or log silently coerces to full.
--tail-lines <n> integer 20 0 disables the pane Maximum lines of post-step stdout shown in the tail pane.
-h, --help boolean — — Prints help and exits 0.

Passing both --auto and --interactive prints Error: --auto and --interactive are mutually exclusive and exits 1. Passing --auto alone prints its daemon-directed deprecation notice and exits 1.

Inline output includes every event the sink registry declares renderable. Halts, kickbacks, unsatisfied gate verdicts, and gate-loop convergence have dedicated lines; other renderable events are summarized by type.

Auto-resume

When a feature description is given and none of --resume, --fresh, or --from is present, the engine looks for an existing worktree for that slug.

Detection Behavior Exit
Resumable Redirects to the worktree and prints Resuming "<desc>" at <n>/<total> (after <step>). Use --fresh to start over. continues
Complete, evidence intact Prompts Feature "<desc>" is already marked complete (<path>). Start over? [y/N]; anything but y returns 0
Complete, evidence gaps Prints the gap report, prompts Roll back feature_status and resume at the first failing step? [Y/n/q]; the default deletes feature_status, flips each failed step to pending, and resumes continues
Orphaned state Lists the expected worktree locations and two remedies, then refuses 1

Recovery procedures live in worktree and evidence recovery.

Side effects of a run

An inline run creates .pipeline/, ensures .claude/settings.json exists with project-scoped permissions, loads .ai-conductor/config.yml (a non-missing config error exits 1) and the merged user config, reads or creates .pipeline/conduct-session-id, discovers plugins under $HOME/.ai-conductor/plugins and <projectRoot>/.ai-conductor/plugins, appends to .pipeline/events.jsonl and .pipeline/audit-trail/events.jsonl, may run the /bootstrap and /assess prelude, spawns bin/update --auto in the background with all failures swallowed, and creates or cleans git worktrees. OTel export is opt-in and off unless configured.

ai-conductor monitor

ai-conductor monitor all
ai-conductor monitor <project>

Runs the foreground guided-resolution queue for halted features. It does not start, attach to, or dispatch the daemon.

Selector Effect
all Monitor halted features across every registered project.
<project> Monitor halted features in one registered project by name.

The monitor remains active until interrupted (Ctrl-C). It offers one halted feature at a time in a guided session and re-derives the queue between passes, so resolved or parked work is not offered again. An empty queue prints Monitor queue is empty; staying active. and rechecks every second.

Each offer prints <project>: <slug> — <reason> (<halt class>) [<band>; <basis>]. Queue order:

  1. Undeferred halts before deferred halts.
  2. Within each group, the daemon backlog’s priority bands (basis priority-band). When priority labels cannot be read within 2 seconds, discovery order is kept and the basis is fallback.

When a guided session returns, the monitor prompts [skip/continue] on a TTY. skip records a deferral in the project’s .daemon/deferrals.json; any other answer, or no TTY, keeps the item in the queue. A deferral lasts only while the same HALT marker (same size and modification time) remains; a new or rewritten halt is offered as undeferred.

Each pass also runs halt-issues sweep when the project’s origin remote is on GitHub. Sweep failures are reported once per failure kind and do not stop the queue. Offers, session opens, deferrals, and session ends are recorded on the event spine as monitor_item_offered, monitor_session_opened, monitor_item_deferred, and monitor_session_ended.

Condition Output and exit
Valid selector, then interrupt Prints Monitor stopped.; exits 0 unless an inventory error occurred during a pass.
Unknown project, unreadable registry, or unreadable selected project Reports the inventory error; exits 1 after the monitor stops.
Configured provider unresolvable or not built in Prints monitor: unable to resolve provider… or monitor: unregistered provider <name>.; exits 1 before the queue starts.
Missing selector, extra argument, or selector beginning with - Prints Usage: ai-conductor monitor all\|<project> to stderr; exits 1.
Invoked from a daemon-managed session Refused by the daemon-session guard before queue enumeration; exits 1.

monitor is intentionally unavailable to daemon-managed provider sessions. Run it from an operator terminal, not from a dispatched build or review session.

ai-conductor daemon

Runs the background build/ship loop, or manages one. Procedures are in running the daemon; this section is the flag surface.

--help or -h anywhere after daemon short-circuits to daemon help and exits 0. That guard is deliberately checked before every daemon dispatcher — without it, daemon --help would be treated as an unknown flag and launch a daemon run.

A non-flag token after daemon that is not one of status, logs, park, unpark, reclaim-worktree, start, stop, restart, connect, debug, pause, resume prints conduct daemon: unknown subcommand '<token>'. plus the daemon help to stderr and exits 1.

Running the daemon

ai-conductor daemon [--concurrency <n>] [--max-items <n>] [--continuous] [--max-cost <tokens>]
                  [--max-runtime <seconds>] [--idle-poll <seconds>] [--max-idle-polls <n>]
                  [--no-watch] [--completed | --all]
Flag Type Default Effect
--concurrency <n> integer 1 Effective feature-executor pool width. An explicit flag wins over daemon_concurrency; otherwise the configured value wins over the default. Values above 1 run up to that many eligible features concurrently.
--max-items <n> integer unset Stop after this many features.
--continuous boolean false Idle-poll instead of draining the backlog once.
--max-cost <tokens> integer unset Total output-token ceiling for the run.
--max-runtime <seconds> integer unset Wall-clock ceiling for the run.
--idle-poll <seconds> integer 60 Seconds between polls when the backlog is empty.
--max-idle-polls <n> integer unbounded Stop after this many consecutive empty polls; dispatching a feature restarts the count.
--no-watch boolean watcher on Drops the HALT-marker filesystem watcher and relies on polling alone. Not listed in --help.
--completed, --all boolean false Include already-processed features in the startup dashboard’s console output. The persisted log sink never includes them. Not listed in --help.

Known limitation. --idle-poll’s help string reports a default of 5 seconds; the code supplies 60 when the flag is absent, so an unflagged --continuous daemon polls once a minute, not every five seconds. Pass --idle-poll explicitly if the interval matters. Tracked in #1012.

Every integer flag reads the next token, and a token beginning with -- is treated as absent. So ai-conductor daemon --max-items --continuous silently uses the default for --max-items rather than reporting an error.

--continuous with no ceiling — no --max-items, --max-cost, --max-runtime, or --max-idle-polls — prints WARNING: --continuous with no ceiling … runs unbounded; Ctrl-C to stop.

When a tmux session for the repo already exists, a bare daemon run wires a self-restart handler so a queued restart respawns the pane at the next idle boundary instead of exiting.

daemon status

ai-conductor daemon status

Takes no flags. Sweeps the project registry and prints one badge line per repo: state, name, path, pid, since, version:<engine-version-id>, pause metadata, the last log line with its mtime, and session:up or session:down. A row with a dead pane or stale pid also shows its matching witnessed exit (killed by <signal> or exited <code>) when available; every row with a recorded sample shows the latest RSS as mem <MB> at <timestamp>. It then prints a GATED: section from .daemon/gated.json, a BLOCKED section from .daemon/blocked.json, and an attribution agreement: N% (n=…) line from .daemon/attribution-accuracy.jsonl; all are skipped for repos whose path is missing.

BLOCKED is the last completed discovery pass: every line contains the slug, machine-readable reason, and remediation text, followed by the snapshot age. An empty valid snapshot prints that no specs are blocked. If the snapshot is missing, malformed, or unreadable, status reports blocked state unknown rather than implying an all-clear. This is a read-only local-file view: it does not invoke Git, GitHub, or the network. The daemon startup dashboard does not yet render this section; that UI work is tracked in #1332.

For every in-progress feature it also prints a PLAN GROWTH [<slug>]: line reading the feature’s kickback ledger and resolved prd_audit cap: the plan’s authored task count, the number of tasks added so far (broken down by the gate that added them, when any), and how many remain under the cap.

Nine rendered states. restart-pending and dead-pane are overlays: they take precedence in the badge, but the underlying liveness and pause facts stay on the row.

Badge State Meaning
● running running Live pid owns .daemon/daemon.pid.
⏸ paused paused .daemon/PAUSED present, pid alive or absent.
⏸ paused (process dead) paused_dead Pause marker present and the pidfile owner is dead.
○ stale stale Pidfile present, its owner pid is dead and reclaimable.
· stopped stopped No pidfile, or a corrupt one, and no pause marker.
✗ path missing path-missing The registered path no longer exists.
✗ unreadable unreadable The repo’s daemon state could not be inspected.
⏳ restart-pending restart-pending .daemon/RESTART-PENDING is queued. Renders as ⏳ restart-pending (waiting on <slug>) when it names a blocking feature.
⚠ session-up/process-dead dead-pane The tmux session exists but its pane has died. Never the same as running.

Exit 0 for any sweep, including one that reports stale or missing entries. Exit 1 only when the registry itself cannot be read. An empty registry prints No projects registered. Use conduct register [path] to add one. and exits 0.

daemon logs

ai-conductor daemon logs [--repo <path>] [--follow] [--all] [--lines <n>]

Reads .daemon/daemon.log.

Flag Type Default Effect
--repo <path>, --repo=<path> path cwd Repo whose log is read.
--follow, -f boolean false Streams appended lines from the current end of file until SIGINT. -f is not listed in --help.
--all boolean false Iterates the registry, printing a ==> <path> <== header per repo.
--lines <n>, -n <n>, --lines=<n> integer whole file Tail length. A non-integer or non-positive value is ignored and the whole file is printed. Not listed in --help.

--follow with --all prints --follow is not supported with --all; showing a static snapshot. and does not follow. A missing log prints (no daemon log yet for <path>) and contributes 0. Exit 1 when a log is unreadable, or when --all is used and the registry cannot be read.

daemon park and daemon unpark

ai-conductor daemon park <slug>
ai-conductor daemon unpark <slug>

Both act directly on the filesystem before any daemon boot, and both resolve the main repo root via git rev-parse --git-common-dir, so they work from inside any worktree.

park validates the slug — either .docs/plans/<slug>.md or .worktrees/<slug> must exist — and writes .daemon/parked/<slug>. It prints Parked '<slug>' — it will not be dispatched or re-kicked until unparked. plus Marked for park: <path>. An already-parked slug prints '<slug>' is already parked (originally parked at <ts>) — no change. and exits 0. An unknown slug exits 1.

After writing or confirming the marker, park reports the observed work state. A live daemon with a current provider attempt prints `Work for ‘' is still running: step , attempt

.`; no live daemon or a settled attempt prints `Work for '' is fully stopped.`; an unreadable pidfile or attempt history prints `Running work for '' is unknown.` The marker is still written when the result is unknown. A park never cancels an attempt already running. It declines later provider attempts, including serial and parallel-member retries, without consuming their retry budget. See [emergency stop a running feature](../runbooks/emergency-stop-a-running-feature.md) to interrupt a provider call or prepare to change git state. `unpark` resets the no-evidence attempt counter first, then removes the park marker, so a failed reset leaves the marker in place for a retry. A slug that was never parked prints `'' was not operator-parked — nothing to do.` and exits 0. Running either outside a conduct project prints `not inside a conduct project — run 'daemon park ' from the project root or any directory inside it` and exits 1. > **Known limitation.** `ai-conductor daemon park` with no slug does not print park usage. The slug-less > form falls through every daemon dispatcher to the inline refusal and prints `conduct: the inline SDLC > pipeline now runs under the inline subcommand.` before exiting 1 — a message unrelated to parking. > Always pass the slug. Tracked in [#1012](https://github.com/jstoup111/ai-conductor/issues/1012). ### `daemon reconcile-parked` ```bash ai-conductor daemon reconcile-parked ``` Runs the same guarded cleanup the daemon's own idle-tick sweep uses, on demand, for one parked feature. Like `park`/`unpark`, it validates its argument shape and resolves the main repo root before any other work, so it works from inside any worktree. A missing or malformed slug never reaches Git: no slug prints `Usage: conduct daemon reconcile-parked ` and exits 1; a slug that fails `^[a-z0-9][a-z0-9-]*$` prints `Could not reconcile '': invalid-slug` and exits 1. For a valid slug, the command checks whether the slug's work reached `origin/main` — either a `.docs/shipped/.md` record committed there (matched allowing for the `YYYY-MM-DD-` plan-date prefix), or a local branch ending in `/` under any prefix that `git merge-base --is-ancestor` proves is contained in `origin/main`. If neither holds, or the check fails, it prints `Could not reconcile '': ` and exits 1. The refusal reason identifies the proof that is missing: - `branch-missing` — no local branch for the slug is available to prove. - `no-merge-proof` — the branch is not an ancestor and no merged PR proves its current tip. - `unmerged-commits` — the branch has commits the merged PR head does not contain, because it advanced past that head or diverged from it (for example, the PR head was rebased after the last local commit). The command prints up to ten `SHA subject` lines after the refusal, followed by `… and M more` when the list is longer. - `branch-behind-merged-head` — the local branch tip is an ancestor of the merged PR head. Deleting it would drop nothing, but no held proof authorizes the deletion. - `ancestry-check-failed` — Git or merged-PR evidence could not be checked safely. These refusals leave every branch and worktree in place. If the slug is merged but `.docs/shipped/.md` does not exist on `origin/main`, it requests an ST-916 record-repair PR when a merged PR can be found, prints `Could not reconcile '': record-missing`, and exits 1 — the same deferral the daemon sweep applies until the shipped record lands. A shipped record on `origin/main` settles completion on its own, so local per-worktree `.pipeline/` state that still reads mid-build never refuses cleanup. Once merged and recorded, it removes `.worktrees/`, deletes every local branch for the slug, and unparks the slug — the same three steps [park before you touch a feature's git state](/ai-conductor/guides/running-the-daemon.html#park-a-feature-before-you-touch-its-git-state) describes doing by hand. It prints `Reconciled '': worktree-removed, branch-deleted, unparked` and exits 0. When the branch was already deleted at merge — the normal end state for shipped work — the middle step reads `branch-absent` instead. When `.worktrees/` exists on disk but git never registered it as a worktree, the directory is removed outright rather than refused. A failure partway through prints `Could not reconcile '': worktree-remove-failed`, `branch-delete-failed`, or `unpark-failed` and exits 1, leaving whatever steps completed in place. See [park a feature before you touch its git state](/ai-conductor/guides/running-the-daemon.html#park-a-feature-before-you-touch-its-git-state) for the automatic sweep this verb shares its logic with. ### `daemon reclaim-worktree` ```bash ai-conductor daemon reclaim-worktree ``` Removes exactly one named, retained feature worktree — the manual counterpart to the automatic reap described in [retained worktrees](/ai-conductor/guides/running-the-daemon.html#retained-worktrees). It never bulk-deletes: only a single `[a-z0-9][a-z0-9-]*` slug is accepted, so a traversal (`../other`), a glob (`*`), a path (`nested/path`), a list (`one,two`), or more than one argument each print `Could not reclaim-worktree '': invalid-slug` and exit 1. A slug with no `.worktrees/` directory prints `No retained worktree to reclaim for ''.` and exits 0 — reclaiming an already-gone worktree is not an error. A slug with a resume in progress prints `Could not reclaim-worktree '': in-progress` and exits 1, so the verb never races a live build. Otherwise it prints `Reclaiming retained worktree: `, removes the worktree, then prints `Removed retained worktree '': ` and exits 0. A removal failure prints `Could not reclaim-worktree '': ` and exits 1, leaving the worktree in place. Like `park`/`unpark`/`reconcile-parked`, it resolves the main repo root via `git rev-parse --git-common-dir` before doing any other work, so it works from inside any worktree. ### Daemon management verbs ```bash ai-conductor daemon start [-D | --detach] [--attach-into ] ai-conductor daemon stop ai-conductor daemon restart […] [--all] ai-conductor daemon connect [--write] [--attach-into ] ai-conductor daemon debug [--attach-into ] ai-conductor daemon pause […] [--all] ai-conductor daemon resume […] [--all] ``` These drive a tmux-hosted supervisor. All exit 0 on success and 1 on any error, including tmux not being installed. Management verbs and direct daemon runs resolve the main repository root from the current directory before launch; daemon logs, PID files, and other runtime state therefore stay under the root `.daemon/` directory even when invoked from a nested package or linked worktree. | Verb | Behavior | | --- | --- | | `start` | Refreshes a stale install first — a stale install never starts a daemon — then starts the session. Auto-attaches read-only when the terminal is interactive and `--detach` was not passed; otherwise prints `daemon started (detached). Attach with 'conduct daemon connect'.` or `daemon started (no interactive terminal to attach to)…`. `--attach-into ` (see below) always attaches, even with `--detach` or no TTY. | | `stop` | Kills the tmux session. | | `restart` | A paused daemon counts as idle. Busy: writes `.daemon/RESTART-PENDING` and returns `restart queued: daemon is busy on ; it will restart automatically once idle.` Idle: clears a stale lock, reconciles an orphaned process (SIGTERM, 100 ms, SIGKILL, reclaim), relinks skills, and recreates the session. The outcome message always prints, so a degraded restart is visible. | | `connect` | Attaches read-only. Detach with `Ctrl-b d`. Pass `--write` to attach read-write instead — the same subcommand you already reached for to look, now with input, no need to already know about `debug`. | | `debug` | Attaches read-write. Unchanged; kept as a discoverable alias alongside `connect --write`. | | `pause` | Writes the durable pause marker; an already-paused daemon reports `already paused`. Listed in `--help`. | | `resume` | Removes the pause marker; a daemon that is not paused reports `not paused`. Listed in `--help`. | | Flag | Applies to | Effect | | --- | --- | --- | | `-D`, `--detach` | `start` | Skips the auto-attach. Parsed on every verb but only meaningful here. | | `--write` | `connect` | Requests a read-write attach instead of the default read-only. Ignored elsewhere — `debug` is already read-write. | | `--attach-into ` | `start`, `connect`, `debug` | Delivers the attach into an already-open tmux pane elsewhere on the same tmux server — a session, `session:window`, or `session:window.pane` target string — instead of taking over this process's own controlling terminal. Fixes running any of these from a shell that is itself already inside a tmux client, which otherwise hits tmux's own nesting guard (`sessions should be nested with care, unset $TMUX to force`): the attach command is typed into the target pane via `tmux send-keys`, wrapped in `env -u TMUX` so tmux does not refuse it there. Never touches this process's own stdio, so it works with no TTY and bypasses `start`'s `--detach`/no-TTY skip. Example: `ai-conductor daemon connect --write --attach-into mywindow:1.0` to view-and-drive the daemon in a specific pane you already have open. | | `--all` | `pause`, `resume`, `restart` | Applies the verb to every registered repo instead of the cwd repo. Not listed in `--help`. | | `…` | `pause`, `resume`, `restart` | Bare tokens after the verb select named repos from the registry. Not listed in `--help`. | In fleet mode each repo gets its own error boundary, so one failure never aborts the sweep. Per-repo `restart` outcomes are paused → respawn, idle → respawn, busy → queued, stopped with no session → `daemon started (was stopped)`, error → reported and the sweep continues. ## `ai-conductor compose` The interactive idea-to-spec loop plus its deterministic primitives. The procedure is in [the composer loop guide](/ai-conductor/guides/engineer-loop.html). `engineer` remains a deprecated alias for the canonical `compose` verb. Two rules apply to every subcommand. `--help` or `-h` is checked before the subcommand's own logic, so it prints that subcommand's help and exits 0 with zero side effects. Any `--flag` not on a subcommand's allow-list prints `compose : unknown flag '' — run compose --help for usage.` to stderr and exits 1. ### Launching the loop | Invocation | Behavior | | --- | --- | | `ai-conductor compose` | Spawns an interactive `claude` session with inherited stdio and the `/composer` prompt. | | `ai-conductor compose --idea ""` | Same, with the idea appended to the prompt. The idea is one-shot — it applies only to the first session. Not declared in `--help`. | | `ai-conductor compose <free text…>` | A bare non-flag positional that is not a known subcommand is joined into an idea string. Not declared in `--help`. | | malformed or unknown flag form | Prints the guide text and exits 0. | The spawn is `claude --permission-mode ''`, where `` comes from [`CONDUCT_ENGINEER_PERMISSION_MODE`](/ai-conductor/reference/environment.html). If `CLAUDECODE` is set the launch refuses to nest a second interactive session, prints guidance to run `/composer` directly, and returns 0. Before each fresh session, and only when no idea came from the CLI, the loop polls GitHub issues into the durable inbox and prints `Intake: N issue(s) queued.` for a non-zero N. That poll is skipped entirely while a background brain loop is alive. Ordinary poll failures print and never block; a corrupt ledger is the exception — it fails closed and exits 1 (see the subcommand table below). A registered project whose path is absent is skipped without running GitHub; its first skipped poll in an absence episode prints `github-issues: skipping : missing path `. Restore or correct the registered path to resume polling it. After each session exits, the loop prompts `Process another idea in a fresh session? [Y/n]` on a TTY. Non-TTY stdin answers no, so the loop never runs unattended. The child's exit code is returned; a spawn failure — `claude` not on `PATH`, for instance — prints an actionable message plus the guide and returns 1. ### `compose` subcommands | Command | Syntax | Purpose | Exit codes | | --- | --- | --- | --- | | `projects` | `compose projects` | Prints the registry as JSON. Read-only. | 0; 1 on unknown flag | | `worktree` | `compose worktree --project --idea "" [--source-ref ] [--body ]` | Resolves the project, resolves the target repo, and creates the per-idea git worktree and branch. Prints `{kind, slug, branch, worktreePath, reconcile}`. With `--source-ref` and no `--body`, loads the Desired-outcome body from the persisted claim record or, if no record exists, from the referenced GitHub issue. A resolved empty or bulletless body stages the source reference with zero outcome bullets. An unreadable, missing, or unparseable source leaves no outcomes file and prints a diagnostic, without failing worktree creation; `--body` takes precedence. | 0; 1 on project not found, target resolution error, or worktree creation error | | `land` | `compose land --project --idea "" --worktree [--source-ref ]` | Reads machine owner config, performs a fail-fast identity check, then commits the authored spec artifacts in the worktree onto `spec/`. With `--source-ref`, comments on the issue and advances the ledger to `routed` — advisory, so a `gh` failure never fails the land. On failure the worktree is kept and its path is reported. | 0; 1 on project not found, unresolved identity, or a land failure | | `handoff` | `compose handoff --project --branch --worktree [--source-ref ]` | Opens the spec PR with the `spec` label and with `gh` running inside the per-idea worktree, then removes the worktree and prints `{kind:'pr-opened', url}` or `{kind:'local-commit', branch, repoPath, reason}`. `--branch` must be `spec/`, where `` is 1–50 lowercase alphanumeric segments joined by single hyphens; one trailing hyphen is permitted. Then starts the target repo's daemon, fire-and-forget. With `--source-ref`, writes back to the ledger, applies the `engineer:handled` label, and mirrors the issue's `priority: ` criticality labels onto the spec PR (fail-open — a read or write failure logs one `[pr-criticality]` line and never fails the handoff). On failure it records branch evidence and keeps the worktree. | 0, including when worktree removal fails (warned); 1 on project not found, target resolution error, or PR open failure | | `poll` | `compose poll` | One synchronous sweep of the GitHub issues adapter, enqueuing every returned envelope into the durable inbox. A registration whose path is absent is skipped without a GitHub call, while other registrations continue polling. Prints `{kind:'poll', enqueued, sourceRefs}`. No routing, no timer, no detached process; the ledger dedups, so a second poll enqueues nothing new. | 0; 1 on unknown flag | | `claim` | `compose claim` | Claims the oldest unblocked inbox entry. The whole claim walk holds the inbox lease (`/inbox.lease`) and waits up to 5 minutes for a concurrent claim. It first returns inbox envelopes left `.claimed` while their ledger entry is still pending, reporting `released stranded intake claim(s)` on stderr. Before selecting work, it also reaps stranded `claimed` entries older than `stale_claim_window_hours` (24 hours by default), returns them to pending, and may serve a reaped entry in that same claim. Builds a fresh blocker resolver per call and reads issue labels uncached. Prints `{empty:true}`, `{allBlocked:true, entries:[…]}`, or the claimed envelope. A real claim acks the queue, moves the ledger to `claimed`, and persists a claim record for a later `worktree --source-ref`. | 0 for each printed outcome; 1 on unknown flag, corrupt intake ledger, lease wait timeout (`engineer claim: Intake claim in progress: …`), or stranded-claim recovery or queue read fault (`engineer claim: `), with nothing claimed | | `forget` | `compose forget [--resolved-by ]` | Drops the ledger entry and strips the `engineer:handled` label so `poll` sees the issue again. With `--resolved-by`, it first comments the supplied resolving reference on the originating GitHub issue and closes it; without that explicit flag it never closes the issue. A missing entry is an error when `--resolved-by` is supplied and otherwise reports `{found:false}`. Label removal is best-effort. | 0 on a completed drop; 1 on an unknown flag or a refused/failed resolved-by close | | `unclaim` | `compose unclaim ` | Single-entry maintenance: returns a `claimed` ledger entry without a recorded PR to pending while preserving its original capture time, so it can be claimed again. Missing, non-claimed, or PR-delivered entries report a non-error result and are left unchanged; resolve or forget a delivered entry instead. | 0 for handled or refused entries; 1 on unknown flag | | `requeue` | `compose requeue --stale [--older-than ]` | Bulk maintenance: returns stale claimed entries without a recorded PR to pending; PR-bearing claimed entries are reserved for `resolve`/`forget` and never touched. Without `--older-than`, it uses `stale_claim_window_hours` (24 hours by default); the flag supplies a one-run duration override. Entries whose source issue is confirmed closed are removed instead; unconfirmed liveness failures are reported without removal. | 0 after the sweep; 1 on an unparseable `--older-than` or unknown flag | | `resolve` | `compose resolve --pr-url [--branch ]` | Recovers a stranded entry that is `claimed` but never delivered by transitioning it to `done` with `{prUrl, branch}`. The branch is preserved when `--branch` is omitted. A missing entry reports `{found:false}`. | 0; 1 on a `--pr-url` that does not match `^https?://`; 1 on unknown flag | | `migrate-issue-deps` | `compose migrate-issue-deps [--confirm]` | One-time prose-to-structured-link dependency migration over open issues. Dry-run by default: prints the proposal, writes nothing, and reports `Dry run — no links written. Re-run with --confirm to apply.` With `--confirm`, applies the links and prints `N link(s) created, M already present.` | 0; 1 when the repo or issue list cannot be resolved; 1 on unknown flag | `--source-ref` on `worktree`, `--body` on `worktree`, and the `--idea` and free-text launch forms are all accepted by the code but absent from the root `--help` output. Every subcommand that touches the ledger — `launch`'s pre-poll, `land`, `handoff`, `claim`, `forget`, `unclaim`, `requeue`, and `resolve` — fails closed on a corrupt ledger: exit 1 with `compose : intake ledger is corrupt at ; quarantine path: ; ledger was not modified.` The ledger itself is left untouched for repair. See [corrupt intake ledger or stuck ledger lease](/ai-conductor/runbooks/corrupt-intake-ledger.html). > **Known limitation.** Omitting a required flag or positional on `worktree`, `land`, `handoff`, > `forget`, or `resolve` prints the full guide text and exits **0**, not a usage error. A script that > checks only the exit code will read a malformed invocation as success. Check for the expected JSON on > stdout instead. Tracked in [#1012](https://github.com/jstoup111/ai-conductor/issues/1012). `compose land` keeps amendments to artifacts that already existed at the branch's merge base under their original feature names. Those amendments remain in the commit and applicable ADR/coherence checks, but cannot replace the current feature's required artifacts. New paths, including rename destinations, must still satisfy the current feature's naming contract. Commit tracked amendments before invoking land; its clean-worktree guard remains in force. > **Known limitation.** `compose land --help` states that land pushes the branch and opens the spec > PR. It does not — `land` only commits spec artifacts onto `spec/`; opening the PR is > `compose handoff`. Run `handoff` after `land` or no PR is ever created. Tracked in > [#1012](https://github.com/jstoup111/ai-conductor/issues/1012). ## `ai-conductor register` ```bash ai-conductor register [path] ``` Validates that `path` is an existing git repository, derives `{name = basename, path = absolute, remote = redacted origin URL}`, and upserts it into the project registry with status `registered`. `path` defaults to the current directory; a relative path resolves against it, and a leading-`-` token is never taken as the path. Prints `Registered ().` and exits 0. Exits 1 when the path does not exist, is not a git repository, or the registry write fails. A rejected validation leaves the registry byte-unchanged. ## `ai-conductor create` ```bash ai-conductor create [--remote ] ``` No-clobber scaffold: creates the directory, runs `git init -q`, writes a skeleton `CLAUDE.md`, a `.gitignore` containing `.pipeline/`, `.daemon/`, and `.worktrees/`, and `.ai-conductor/config.yml` from `templates/project-config.yml.template`, optionally adds the origin remote, and upserts the project with status `created`. | Flag | Type | Default | Effect | | --- | --- | --- | --- | | `--remote `, `--remote=` | string | — | Adds `origin`. Never pushes. The registry record stores a redacted form of the URL. | Prints `Created ().` and exits 0. Exits 1 when the target directory is non-empty — writing nothing — or when the scaffold or registry write fails. Omitting `` falls through to the inline refusal and exits 1. ## `ai-conductor config init` ```bash ai-conductor config init ai-conductor config init [--test-suite-mode <aggregate|scoped>] [--test-suite-drift-budget <strict|tolerant>] [--test-suite-command ] [--test-suite-scoped-command ] ``` Initializes the current Git repository's `.ai-conductor/config.yml` from `templates/project-config.yml.template`. A first run prints the created path and exits 0. If the file already exists, it reports that path, preserves the file byte-for-byte, and exits 0. When any verification option is present, the command records a `test_suite` block in the new config. `--test-suite-command` records the project's aggregate command as a YAML scalar without running it; it must be non-empty and single-line. `--test-suite-mode aggregate` is the default; `scoped` also writes a `scoped_command` with the required `{selectors}` placeholder. `--test-suite-drift-budget strict` is the default and tolerates no drift; `tolerant` permits unlimited `additional_inputs` drift and up to 20 changed `source` paths. Supplying one option uses the default for the others. See [test_suite configuration](/ai-conductor/reference/configuration.html#test_suite) for the resulting fields and constraints. The command exits 1 without writing when the current directory is not a Git repository or when the template cannot be resolved or written. Invalid option values exit 1 without creating a config: the modes are `aggregate` and `scoped`, the drift-budget presets are `strict` and `tolerant`, and test commands must be non-empty single lines. An unrecognized `--` option also exits 1 before any file is created. ## `ai-conductor config read` / `ai-conductor config write` / `ai-conductor config set` ```bash ai-conductor config read ai-conductor config write <markdown_viewer|mermaid_renderer>set> ai-conductor config set conductor. ai-conductor config set spec_owner ``` `read` resolves the effective configuration at ``. From a directory with a project `.ai-conductor/config.yml`, it deep-merges user config with project config and lets the project value win; when there is no project config, it reads user config only. `write` remains user-scoped `~/.ai-conductor/config.yml` behavior for the markdown viewer and mermaid renderer, while `set` updates the user-scoped update flow's `conductor:` block. `read` prints the value at `` (e.g. `markdown_viewer.command`) to stdout, joining an array value with spaces, and prints an empty line for a missing key. It exits 1 and prints the relevant project or user config read error to stdout when parsing fails. `write` sets `markdown_viewer` or `mermaid_renderer` to `{preset, command, args, mode}` — `` is a single space-separated argument, split on whitespace — preserving every other top-level key already in the file. It exits 1 and prints the config path and error to stderr when the existing file fails to parse or the write fails (e.g. an unwritable directory). `set` updates exactly one user-scoped setting without replacing other user configuration. Supported `conductor` keys are `update_channel`, `auto_check`, `current_version`, and `last_checked_at`. `conductor.auto_check` accepts only `true` or `false` and is stored as a YAML boolean; the other keys are stored as strings. `spec_owner` stores a non-empty operator identity only in `~/.ai-conductor/config.yml`; project configuration rejects that key to prevent identity leakage. The command validates both the existing and prospective value before writing, so invalid channels, empty identities, unknown keys, malformed user YAML, and write failures exit 1 without changing the file. Use `config read conductor.` or `config read spec_owner` to inspect the stored scalar. ## `ai-conductor task` ```bash ai-conductor task start ai-conductor task done [--done-when =]... ai-conductor task done --plan-gap --reason ``` Exactly two positionals: the verb and a task id matching `[A-Za-z0-9._-]+` (for example `7` or `rem-fr10-1`). A missing or unknown verb, or a missing id, prints the guide to stderr and exits 2. `start` reads `.pipeline/task-status.json`, flips the matching row's status to `in_progress`, writes it back atomically, then writes the id into `.pipeline/current-task`. It exits 1 when the status file is unreadable, corrupt, not an object, or has no `tasks` array; when the id is not found (the error lists the valid ids); or when either write fails. `done` reads `.pipeline/current-task`, but the stamp is attribution telemetry rather than close authority. With or without a stamp, a task whose active plan declares `Done when:` checks records the supplied evidence for every check and marks its row `completed`; missing evidence refuses the close and names the check. Without a stamp, re-closing an already `completed` or `skipped` row with no open repair exits 0 without rewriting `task-status.json`. `--plan-gap --reason ` halts the task with or without a stamp; when no active plan is recorded, it resolves the plan from the feature slug. A legacy task with no `Done when:` checks keeps its prior exit-0, no-write behavior. A stamp holding a different id prints `cannot clear task ; current stamp is ` and exits 1 with both the stamp and `task-status.json` untouched. A matching stamp is removed after a successful close. See [gates](/ai-conductor/explanation/gates.html). ## `ai-conductor test-suite` ```bash ai-conductor test-suite ``` Runs the aggregate verification gate between BUILD and SHIP against the `test_suite` block in [configuration](/ai-conductor/reference/configuration.html). Takes no arguments; any extra argument prints `Usage: ai-conductor test-suite` plus `Remove extra arguments and rerun. If verification blocks, return to /tdd or /pipeline before SHIP.` to stderr and exits 1. | Outcome | Output | Exit | | --- | --- | --- | | Pass | `: full test suite PASS (fingerprint , duration ms)` on stdout | 0 | | Fail | `FAILED: full test suite evidence=[ freshness=]. [entry #/ failed;] Return to /tdd or /pipeline, fix the failure, then rerun ai-conductor test-suite.` on stderr | 1 | Failure reasons and their guidance: | Reason | Guidance | | --- | --- | | `missing_config` | Declare `test_suite.command` or `test_suite.commands` in `.ai-conductor/config.yml`. | | `invalid_config` | Fix the `test_suite` block in `.ai-conductor/config.yml`. | | `invalid_input` | Fix the declared test-suite inputs. | | `unlaunchable` | Make the declared aggregate command launchable. | | `timeout` | Fix the suite timeout or the command that exceeded it. | | `signal` | Fix the suite process termination. | | `nonzero_exit` | Fix the aggregate suite failures. | | `preflight_failed` | Fix the full-suite preflight failure. | | `internal_error` | Fix the full-suite verifier failure. | This command is dispatched before every other detector and sets the process exit code rather than exiting immediately. It does not appear in `--help`. For an ordered `test_suite.commands` list, successful entries run in declaration order. The first failed entry stops the collection; failure output identifies its ordinal and includes the bounded per-entry diagnostic context. Later entries do not run. ## `ai-conductor scoped-run` ```bash ai-conductor scoped-run ``` Runs the configured scoped test command for one or more selectors. It expands the selectors only at the `{selectors}` placeholder in `test_suite.scoped_command`; see [configuration](/ai-conductor/reference/configuration.html). It does not run the aggregate `test_suite.command` or create, replace, or reuse aggregate verification evidence. The command runs in `test_suite.working_directory` (project root when unset), the same directory the aggregate `test_suite.command` runs in. Selectors are named the way the repository names them — relative to the project root — and a selector that only resolves from the root is rebased onto the working directory before expansion. A selector that already resolves from the working directory, an absolute path, a flag (leading `-`), and a non-path name pattern all pass through unchanged. At least one non-blank selector is required. An empty selection exits 1 and directs the caller to the shared aggregate verifier. If `test_suite.scoped_command` is not configured, it exits 1 without falling back to the aggregate command. A selected-test failure returns that command's nonzero exit code; a successful selected run exits 0. This command does not appear in `--help`. ## `ai-conductor shipped-record` ```bash ai-conductor shipped-record --slug --pr <url|local> ``` Writes and commits `.docs/shipped/.md` on the current branch. Run it in the feature worktree, on the implementation branch, before the final push, so the merge that lands the code atomically lands the fact that the spec shipped and the daemon stops re-dispatching it. Never run it for a `keep` or `discard` finish — nothing shipped, so there is no record. | Flag | Type | Required | Effect | | --- | --- | --- | --- | | `--slug ` | string | yes | The plan stem to record. | | `--pr <url\|local>` | string | yes | The PR URL, or the literal `local` for a merge-local finish. | It resolves the plan identity, hashes `.docs/plans/.md` and its stories file — the plan's `**Stories:**` reference first, then `.docs/stories/.md` — and renders the record with a cost block when one can be computed. Only a byte-identical complete record produces no duplicate commit; changed `## Cost` or `## Time` totals are committed with the current record. Otherwise it `git add`s the file and commits it as `shipped record: ` when the staged content changed. It also appends a `## Time` block computed independently from `.pipeline/events.jsonl`, reporting `state: measured|partial|unavailable` with `active_ms`, `provider_active_ms`, and `no_provider_active_ms` when measured. A `partial` block adds `reason: ` when the rollup identifies its downgrade route; records shipped before this field existed simply omit the line. A missing or corrupt event ledger, or any timing-computation failure, never blocks the Cost block or the commit — the record ships with `state: unavailable` instead. The frontmatter also carries `engine_version`: the engine build id that shipped the feature — the same value `ai-conductor daemon status` prints as `version:`. It is resolved from the running engine's own module path, so a published build records e.g. `20260727T234833Z-b5b34bb9f015` and an unpublished source checkout records `dev`. Resolution never throws and never blocks the record. Records written before this field existed simply omit the line, and `ai-conductor kpi` reports those as `engine=unknown`. Either flag missing prints the usage guide to stderr and exits 1. Success is reported on **stdout** (`✓ shipped record committed: `, or `✓ shipped record already committed: ` on an idempotent re-run); only failures — the usage guide, a degraded cost or timing rollup, and the write-failed warning — go to stderr. The daemon calls this command in-process and tees `console.error` into `.daemon/daemon.log` tagged `[error]`, so a success line on stderr would make every completed ship read as a failure. Every other failure exits **0** with one warning and no record written, so the exit code cannot be used to detect success. See [shipped-record reconciliation](/ai-conductor/runbooks/shipped-record-reconciliation.html#recovery). Does not appear in `--help`. ## `ai-conductor kpi` ```bash ai-conductor kpi ``` Read-only report over the cost blocks in committed `.docs/shipped/*.md` records. Accepts and ignores any trailing arguments. Always exits 0: a missing or empty `.docs/shipped` prints a friendly message rather than an error, and malformed records do not throw. Does not appear in `--help`. Each per-feature row carries `engine=`, the engine build that shipped it, so ships can be attributed to a daemon build. A record written before engine-version stamping reports `engine=unknown` rather than omitting the field, keeping unattributed ships visible in the report. Rows also show token, cache, dispatch, retry, halt, duration, and cost totals. Cost-unmetered dispatches are marked `COST-PARTIAL`, retain their tokens, and render their cost as unavailable; truly unmetered dispatches remain excluded from both aggregates. Provider rows attribute tokens, cost, cost-unmetered dispatches, and dispatch counts by provider. Each row also reports engine-observed execution time, parsed from the record's `## Time` block independently of Cost: `time=measured active_ms= provider_active_ms= no_provider_active_ms=` splits durable feature wall-clock time into time spent inside a provider process versus engine/code time; `time=partial` (optionally with `active_ms`) adds `reason=` when the rollup identifies the downgrade route: `empty-active-union`, `active-evidence-incomplete`, `open-executions:`, `provider-outside-active-union`, or `provider-evidence-incomplete`. Records shipped before the reason field existed simply omit it and report `time=partial` without a route. `time=unavailable` marks evidence that could not be trusted, and a record with no `## Time` block — including every record shipped before this section existed — reports `time=unavailable`. The aggregate line adds `timing measured= partial= unavailable=` counts and `avg_active_ms`/`avg_provider_active_ms`/`avg_no_provider_active_ms`, averaged only over measured features. ## `ai-conductor memory setup` ```bash ai-conductor memory setup [dir] ``` Prepares the memory store for a project. `dir` defaults to the current directory; a relative path resolves against it. | Existing `.memory/` | Action | | --- | --- | | A real directory | Copy-verify-swap migration, logging `conduct memory setup: migrating existing .memory/ in ` | | Absent, or already a symlink | Creates the canonical store and symlink; idempotent | Prints `conduct memory setup: .memory/ is ready at ` and exits 0. Exits 1 when the directory does not exist or anything throws. Only the exact two-token form `memory setup` matches. Does not appear in `--help`. ## `ai-conductor halt-issues sweep` ```bash ai-conductor halt-issues sweep --repo-dir --gh-repo <owner/name> [--monitor-log ] [--ledger ] [--dry-run] ``` Parses the halt monitor log, loads or rebuilds the ledger, stamps, resolves, or closes each entry against the issue tracker, writes the ledger atomically, and prints a summary. Automatic closure requires a canonical millisecond UTC halt timestamp (`YYYY-MM-DDTHH:mm:ss.sssZ`) and shipping evidence whose modification time is strictly later than that instant. An older, equal, missing, or imprecise legacy timestamp remains open and is counted as guarded; the sweep never guesses a time or timezone. When the current monitor log supplies a precise timestamp, it replaces a legacy truncated ledger value before that same sweep evaluates evidence. Dry runs use the same comparison but write neither the ledger nor the issue tracker. | Flag | Type | Required | Default | | --- | --- | --- | --- | | `--repo-dir ` | path | yes | — | | `--gh-repo <owner/name>` | string | yes | — | | `--monitor-log ` | path | no | `~/.ai-conductor/halt-monitor/monitor.log` | | `--ledger ` | path | no | `~/.ai-conductor/halt-issues/ledger.json` | | `--dry-run` | boolean | no | `false` — with it, the ledger is not written | `--help` or `-h` prints usage to stdout and exits 0. A missing required flag or any unrecognized `--flag` prints usage to stderr and exits 1 — a misused subcommand never falls through to the pipeline launcher. Otherwise the exit code is the sweep's own; an unrecoverable error prints `halt-issues sweep failed: ` and exits 1. Requires network access through `gh`. ## `ai-conductor overlap-scan` ```bash ai-conductor overlap-scan [--files <a.ts,b.ts>] [--source-ref <owner/repo#N>] [--base ] [--cwd ] ``` | Flag | Type | Default | Effect | | --- | --- | --- | --- | | `--files ` | comma- or space-separated paths | none | Candidate paths. Consumes every following argument up to the next `-`-prefixed one; each is split on commas, trimmed, empties dropped. | | `--source-ref ` | string | unset | Linked issue reference swept for open blockers. | | `--base ` | string | the origin default branch, else `main` | Base ref used to find each sibling branch's merge base; the scan compares only paths that branch contributed after that point. | | `--cwd ` | path | current directory | Repository to scan. | Candidate paths are matched repo-relative against the checkout's tracked and untracked, non-ignored files. The report adds one `Advisory:` line per case: | Case | Advisory line | | --- | --- | | No candidate paths supplied | `nothing was scanned for overlap: no candidate paths were supplied` | | Candidate not in the checkout | `candidate path is not present in the checkout: ` (once per distinct path) | | `git ls-files` fails | `candidate-path classification failed: git ls-files exited ` | Absent paths are still compared against sibling branches. Advisory by contract: it always exits 0. Even an unexpected error prints `overlap-scan: unable to complete scan ()` and still returns 0. Reads git and queries `gh`; writes nothing. ## `ai-conductor plan-protected-targets` ```bash ai-conductor plan-protected-targets .docs/plans/.md ``` Blocking plan-authoring check for tasks that name another feature's artifact under `.docs/architecture/`, `.docs/decisions/`, `.docs/plans/`, `.docs/specs/`, or `.docs/stories/`. It reads the named plan, resolves each task's `**Files:**` set (including `same` inheritance), and writes nothing. Own-feature paths and unsealed `.docs/` paths pass. Every task's prose is also scanned, whether or not it has a `**Files:**` line: a protected artifact cited in a backtick path (e.g. `` `.docs/specs/other-feature.md` ``) is reported alongside any declared `**Files:**` violation, since a `**Files:**` declaration does not resolve a foreign protected reference elsewhere in the task. | Outcome | Output | Exit | | --- | --- | --- | | No violations | `No protected-target violations found.` | 0 | | Violation | One line per offending path: `Task : — return this amendment to DECIDE; BUILD tasks must not target protected artifacts.` | 1 | Run it before committing a plan. Correct the accepted artifact during DECIDE and re-author the task; do not hand the amendment to BUILD. The land gate repeats this check when a spec is landed. ## `ai-conductor kickback-budget` ```bash ai-conductor kickback-budget inspect --feature [--format human|json] ai-conductor kickback-budget raise --feature --gate --by --rationale "" ai-conductor kickback-budget reset --feature --gate --rationale "" ``` Use this operator-only command to inspect or authorize one recovery from a budget-cap halt. `raise` and `reset` require a local interactive terminal, a live HALT, matching cap evidence, and a machine-scoped operator identity resolved from your user config's `spec_owner` and otherwise from the `gh`-authenticated login — no environment variable names the operator. The rationale must be non-empty and at most 2000 bytes. They record an auditable authorization for the daemon to consume. The authorization is durably staged before its event is written, so an interrupted command is reconciled exactly once on the next command entry. The daemon consumes a matching authorization on its next loop iteration; it does not wait for an unrelated base-branch advance. Supported gates are `build_review`, `prd_audit`, and `architecture_review_as_built`. Inspect always lists all three gates; JSON renders an empty `adjustments` array for a valid gate with no adjustment history. Inspect also performs that reconciliation, so it is safe as the first command after an interrupted `raise` or `reset`. Inspect reports each gate's resume authorization against the live halt generation. Human output prints one `Resume authorization:` line per gate: | Line | Meaning | | --- | --- | | `none` | The gate has no recorded authorization. | | `consumed` | The daemon already used this authorization. | | `awaiting daemon sweep` | The authorization and the gate's cap evidence both match the live halt generation; the daemon consumes it on its next loop iteration. | | `stale (bound to halt generation ; live halt generation ); the daemon will not consume it` | The authorization or the gate's cap evidence names a different halt generation, or no halt is live. The daemon logs it as stale and never consumes it. | JSON adds a `resumeAuthorization` object to a gate that has one: `{ state, adjustmentId, boundHaltGeneration, liveHaltGeneration }`, where `state` is `consumed`, `awaiting-sweep`, `stale`, or `pending`. `pending` means the live halt was not read; inspect always reads it. `liveHaltGeneration` is empty when no halt is live. When several gates hold unconsumed authorizations, the daemon consumes only the one bound to the live halt generation. The eligible live halt class is per gate: `build_review`'s cumulative convergence cap halts `needs-human`, while the `prd_audit` and `architecture_review_as_built` remediation-lap caps halt `kickback-cap`. A `raise` or `reset` naming a gate whose live halt carries the other class is refused and changes nothing. `raise` follows the exhausted allowance in the live cap evidence: for a lap halt it increases that gate's effective lap limit by `--by`; for a plan-growth halt it increases the feature's effective plan-growth cap by `--by`. `reset` returns only a gate's lap count to zero without lowering an already authorized effective limit, and refuses plan-growth evidence; use `raise` for that recovery. Inspect shows the effective plan-growth cap and whether it is config-derived or raised. For either mutation, the command temporarily parks an unparked feature while it records the authorization and removes that temporary park after success. It preserves a park that already existed; unpark that feature when ready, otherwise the daemon leaves the authorization unconsumed. ## `ai-conductor decide-grant` ```bash ai-conductor decide-grant --slug --step --reason "" ``` Records one explicit authorization for an autonomous run to enter a named DECIDE step. Run it from any directory inside the repository, including a linked feature worktree; the command resolves the main repository checkout before writing `.daemon/grants/.json`. The daemon never creates this artifact itself. Outside a repository, the command exits non-zero and records no grant. The grant lives in the daemon-owned `.daemon/` directory, **outside every feature worktree**, and that placement is the authorization boundary. It previously lived at `.worktrees//.pipeline/decide-grant.json` — inside the directory a build agent writes all build long — so the subject of the authorization could write its own permission slip. A `decide-grant.json` inside a worktree authorizes nothing. | Flag | Required | Effect | | --- | --- | --- | | `--slug ` | yes | Feature worktree slug. A slash, `.` or `..` is rejected. | | `--step ` | yes | Exact DECIDE step to authorize. The grant does not authorize any other step. `plan` is rejected — see below. | | `--reason ` | yes | Operator's reason for allowing this one DECIDE entry. | **`plan` can never be granted.** The command exits non-zero when `--step plan` is passed, and the entry policy refuses `plan` before it consults a grant at all, so no grant of any provenance admits it. A daemon that re-plans rewrites an approved DECIDE artifact with no human at the gate — the same class of failure the re-entry was meant to repair. Drive the plan revision interactively, then resume the feature. The matching grant is consumed immediately before the provider dispatches the named step. A stale, malformed, mismatched, or already-consumed grant authorizes nothing and the run remains fail-closed. Clearing `.pipeline/HALT` or `.pipeline/HALT.class` is not an authorization; use the [DECIDE-entry recovery procedure](/ai-conductor/runbooks/stalled-or-stuck-feature.html#the-halt-refused-a-decide-entry). ## `ai-conductor halt clear` ```bash ai-conductor halt clear --feature --rationale "" ``` Clears a live halt after recording who authorized it and why — the audited alternative to removing `.pipeline/HALT` and `.pipeline/HALT.class` by hand. Run it from any directory inside the repository; it resolves the main checkout and the worktree `.worktrees/`. | Flag | Required | Effect | | --- | --- | --- | | `--feature ` | yes | Feature worktree slug. A slash, `.`, or `..` is rejected. | | `--rationale ` | yes | Operator rationale. Must be non-empty and at most 2000 bytes. | **Interactive-operator only.** The command requires `process.stdin.isTTY` and a machine-scoped operator identity resolved like [`kickback-budget`](#ai-conductor-kickback-budget): user-config `spec_owner`, otherwise the `gh`-authenticated login. In order, it: 1. Appends a `halt_clear_authorized` event (feature, operator, rationale, halt class, and the recorded `last_step`) to the worktree's `events.jsonl` and an `operator`-origin record to the audit trail. The audit writer is fail-closed: if either write fails, the command refuses and leaves the halt in place. 2. Removes `HALT.class`, then removes `HALT` — except for an `over-scope` halt, whose body is **renamed** to `.pipeline/HALT.cleared` so the next `prd_audit` lap can harvest the edited `over-scope-decisions` block. Edit that block before running the command. 3. Supersedes the feature's halt record with cause `operator`. A record failure prints `halt clear: warning — halt record …` but does not undo the clear. | Exit | Meaning | | --- | --- | | `0` | Halt cleared. | | `1` | Worktree missing, feature not halted, no operator identity, or the authorization event could not be recorded. Nothing is cleared. | | `2` | Non-interactive terminal or invalid rationale. Nothing is cleared. | Any halt class is accepted, including `kickback-cap`. A direct clear changes no budget, so an exhausted allowance halts again on its next cap check; use [`kickback-budget raise` or `reset`](#ai-conductor-kickback-budget) to recover a budget halt. The command grants the daemon no clearing authority. Fix the halt's cause first — see [clear a halt and let the feature resume](/ai-conductor/runbooks/stalled-or-stuck-feature.html#clear-a-halt-and-let-the-feature-resume). ## `ai-conductor rewind` ```bash ai-conductor rewind --to ``` Returns a halted feature to an earlier pipeline step. Run it from that feature's worktree, for example `cd .worktrees/`, after identifying the step that must run again. `--to` is required and must name a step in the resolved registry that is strictly earlier than the feature's recorded `last_step`. The command refuses an unknown, current, or later target without mutating state. It also refuses if the state changed while the rewind was being applied. On success, it marks the target and every later non-skipped step `stale`, clears their gate verdicts, then clears both `.pipeline/HALT` and `.pipeline/HALT.class` atomically. It emits an `operator_rewind` event and prints `Rewound to .` The next daemon dispatch begins at the rewound step. Do not edit `conduct-state.json`, gate files, or halt markers by hand; use this command instead. If clearing the derived records fails, `rewind` exits non-zero and restores the recorded step state, halt markers, and any gate verdicts it staged for removal, so the feature remains retryable. It reports the failure that stopped the rewind first; a subsequent `rewind: rollback failed:` message means that the corrective restoration also failed and needs operator attention. ## `ai-conductor reseal` ```bash ai-conductor reseal --slug --path [--path ...] --reason "" [--clear-halt] ``` Re-fingerprints named protected DECIDE artifacts against the current commit after an operator has reviewed and approved an amendment committed after first BUILD entry — the audited alternative to hand-editing `.pipeline/protected-artifact-seal.json`. Run it from the main repository checkout, not from inside the feature worktree. | Flag | Required | Effect | | --- | --- | --- | | `--slug ` | yes | Feature worktree slug (`.worktrees/`). A slash, `.`, or `..` is rejected. | | `--path ` | yes, repeatable | A protected artifact path to reseal. Every occurrence reseals one more path; at least one is required. | | `--reason ` | yes | Operator rationale for the reseal. A missing or blank rationale is refused and audited. | | `--clear-halt` | no | Also clear a resolved protected-artifact HALT in the worktree after resealing. | **Interactive-operator only.** The command refuses with `requires an interactive terminal` unless `process.stdin.isTTY` is true, so it cannot be reached from a `build`/`SHIP` step subprocess, an autonomous provider session, or a script piping stdin — only a human at a terminal can reseal. **Scoped, not a full rebaseline.** Only the listed paths are re-fingerprinted; every other protected path must still match its existing baseline or the whole reseal is refused — an operator cannot use `--path` to launder unrelated drift into the seal. Each listed path must already be protected and sealed, resolvable at the current commit, not deleted, and free of uncommitted changes (commit the amendment first). Refusal conditions — unknown worktree, missing rationale, non-interactive terminal, missing seal, an unlisted-path violation, or an invalid reseal target — are each written to the audit trail as `protected_artifact_reseal_refused` before the command exits 1; a successful reseal writes `protected_artifact_reseal` with the resealed paths' prior and new fingerprints. Both are audited with an `operator` origin, distinct from step-attributed records. See [artifacts](/ai-conductor/reference/artifacts.html#write-guards) for the seal format and [the stalled-feature runbook](/ai-conductor/runbooks/stalled-or-stuck-feature.html#the-halt-is-a-protected-artifact-violation) for the full recovery procedure. When the changed resealed path is a current coverage-binding DECIDE input, a completed coverage-binding result is invalidated. The next re-kick runs coverage binding before BUILD; its amendment judgement can reopen only completed tasks that the changed DECIDE obligation contradicts. No task is reopened merely because an operator resealed an artifact. The `--reason` rationale is not just an audit-trail entry: the next `build_review` on this feature renders every `operator-reseal`-triggered entry, with its paths, rationale, and commit range, in the grader's prompt as evidence to judge — see [operator-authorized protected-artifact reseals](/ai-conductor/explanation/gates.html#operator-authorized-protected-artifact-reseals). On success the command prints `Resealed protected artifacts: ` and exits 0. With `--clear-halt`, it additionally clears the worktree's `HALT`/`HALT.class` markers when a halt is present and its class is the protected-artifact class, and reports the outcome (`No halt to clear.`, or why a present halt was not cleared) on a second line. ## `ai-conductor evidence` ```bash ai-conductor evidence ``` The `evidence judge` gate was removed — per-task commit stamping is telemetry, not a gate, and citation-quality sampling now runs as a non-blocking spot audit. The command survives only so the token resolves to a clear message instead of an unrecognized-command error. Any argument form prints the retirement notice and exits **2**. The help string does not mention the non-zero exit. ## `ai-conductor closeout-event` ```bash ai-conductor closeout-event ``` Records one pipeline closeout timing event. `` must be one of `evaluator`, `simplify`, `architecture-diagram`, `memory`, `summary`; `` and `` are millisecond epoch timestamps. An unrecognized obligation prints the valid list to stderr and exits 1; otherwise it appends a `pipeline_closeout` event to the pipeline-owned sibling ledger, `.pipeline/pipeline-events.jsonl`, and exits 0. This command is called by a closeout obligation itself (for example the `evaluator` gate in the [pipeline skill](/ai-conductor/reference/skills.html)), not typed by an operator, so it never starts a conductor or daemon and works identically whether `pipeline` is running under the engine or invoked inline in a bare session. The sibling ledger is a separate single-writer file from `.pipeline/events.jsonl` — when a `build` step is running under the engine, a tail reader re-emits each recorded event onto the live bus for the daemon log, terminal UI, and OTel export, but `pipeline_closeout` is never persisted a second time into `.pipeline/events.jsonl`. ## `ai-conductor build-tail` ```bash ai-conductor build-tail [worktree] ``` Renders a read-only task/remediation/closeout timing rollup for one `build` step, decomposing its single opaque provider session into task execution, kickback remediation, and closeout ceremony. `[worktree]` defaults to the current working directory. Always exits 0. The rollup reads and merges the engine ledger (`.pipeline/events.jsonl`) and the pipeline-owned sibling ledger (`.pipeline/pipeline-events.jsonl`) for the given worktree, and reports one of three states: | State | Meaning | | --- | --- | | `measured` | At least one complete `build` window (`step_started`/`step_completed`) was decomposed. Reports, per window, its classification (`first-pass` or `re-entry`), task execution duration, post-resolution tick counts split into remediation and closeout, and closeout duration with a per-obligation breakdown — plus an aggregate across all windows. | | `partial` | The ledgers are readable but a window is unterminated, malformed, or an inline pipeline run (no engine) produced closeout events with no engine window boundaries. When closeout events exist, the closeout-only timeline is still rendered. | | `unavailable` | No `build` window and no closeout events were found. | A window's first tick determines its classification: if it already reads `resolved == total`, the window is a re-entry (the task graph was complete on entry); otherwise its task-execution segment ends at the first tick where `resolved == total`. Post-resolution ticks with `headMoved: true` classify as remediation; closeout classification comes from the merged `pipeline_closeout` timeline. See `.docs/architecture/build-post-task-tail-telemetry.md` for the full model. ## Internal commands, invoked by the engine These are dispatched by skills, hooks, and the daemon rather than typed by an operator. None appear in `--help`. They are listed so a name found in a log or a hook script is findable. | Command | Syntax | Purpose | Exit codes | | --- | --- | --- | --- | | `intake-loop` | `ai-conductor intake-loop --continuous \| --once [--interval-ms ]` | Polls registered repos into the durable inbox, notifies through the status surface, and reconciles closed GitHub issues each tick so a closed issue cannot be re-claimed. Never spawns a provider session and never opens a PR. `--interval-ms` defaults to 300000. Exactly one of `--continuous` and `--once` is required. | 0 on completion; 1 for the usage guide | | `brain start\|stop\|status` | `ai-conductor brain ` | Host-wide singleton that hosts `ai-conductor intake-loop --continuous` in the tmux session `cc-brain-conductor`. `start` is idempotent; `status` prints `brain loop: running\|stopped`, then the current durable `pending`, `claimed`, and `stranded` intake-ledger counts. When available, it separately prints the recorded prior notification batch as `last notification: at `; that batch is not current queue depth. | 0; 1 on a tmux error or when `status` cannot read the intake ledger | | `render-diagrams` | `ai-conductor render-diagrams … [--check]` | Renders the Mermaid blocks in each file using the configured `mermaid_renderer` preset. `--check` parse-checks blocks without opening them. | Default mode always 0. `--check`: 1 when any block fails to parse or a file is unreadable; 0 when everything parses, there are no diagrams, or `mmdc` is unavailable. Zero files: 1 | | `rate-card` | `ai-conductor rate-card refresh [--model ]…` · `ai-conductor rate-card show` | Maintains `/.ai-conductor/rate-card.json`, the committed per-model token price card the harness prices dispatches from for providers that report token counts but no cost (codex, and Pi messages without a provider cost). `refresh` fetches LiteLLM's public `model_prices_and_context_window.json`, prunes it to the models the provider model policies route to and supported opt-in models (plus any `--model`), and rewrites the card with a fresh `as_of`; commit the result. `--model` is repeatable. `show` prints the committed card. The fetch lives here, never on the dispatch path. `.github/workflows/rate-card-refresh.yml` runs `refresh` daily and opens a bot PR on the `automation/rate-card` branch when the published rates actually change — a run that finds identical rates discards its own `as_of`-only diff and opens nothing. A failed fetch, an unparseable payload, or a payload pricing none of the requested models leaves the committed card byte-for-byte unchanged. | 0 on success; 1 for the usage guide, a failed refresh, or a missing/unreadable card under `show` | | `shipment-evidence` | `ai-conductor shipment-evidence --pr [--event ]` · `shipment-evidence reconcile --pr --shipped ` · `shipment-evidence audit [--report ]` | Classifies, repairs, or audits the association between a PR and its shipped record. `audit` is report-only and never writes records. `reconcile` requires `GITHUB_REPOSITORY`. | check: 0 valid or not-applicable association, 1 otherwise. reconcile: 0 unless unresolved. audit: 0. Malformed: 1 | | `finish-record` | `ai-conductor finish-record --choice <pr\|keep> [--pr-url ] --pipeline-dir ` | Records the finish choice. `--choice pr` requires `--pr-url`; `--choice keep` must not carry one; `discard` is not accepted. `--pipeline-dir` must be an absolute path to an existing directory, checked before any spawn or write. The `pr` path is fail-closed across seven checks — PR binding, upstream push, state readability, branch shape (`spec/`, `feature/`, or the daemon's `feat/daemon-` — a bare `feat/` is refused), slug derivability, `git rev-parse HEAD`, and a valid shipment-evidence verdict. | 0; 1 on any guide or failed check | | `github-boundary-audit` | `ai-conductor github-boundary-audit [--root ]` | Read-only static audit of the shipped runtime's GitHub and remote-Git invocation sites. Reports one `file:line:column: message` diagnostic per site that bypasses the guarded operation interface. The integrity suite runs it. | 0 clean; 1 on any finding or unreadable root | | `manual-test-record` | `ai-conductor manual-test-record --skip --reason --pipeline-dir ` · `ai-conductor manual-test-record --results <path\|-> --pipeline-dir ` | Appends a `## Attempt N` section to `/manual-test-results.md`, atomically. `--results -` reads stdin; an exact `WARN` result cell stamps the attempt with ``. `--skip` and `--results` are mutually exclusive and one is required. `--pipeline-dir` must be absolute. | 0; 1 on a usage error, an empty results payload, or any read/write error | | `derive-feedback` | `ai-conductor derive-feedback --sha [--plan ]` | Read-only advisory check for whether commit `` carries `Task: ` evidence, or touches files declared under a task in the given plan. Prints one JSON line. Never writes task status or the evidence sidecar. | **0 evidenced, 1 not evidenced, 2 usage.** Informational only — the calling hook must not propagate them | | `build-auth-status` | `ai-conductor build-auth-status` | Reports the self-host build auth mode and token state as `build-auth-status: mode= state=[ path=][ ()]`. Probes the real dispatch auth path when a token is present. | 0 when the mode is not `daemon-token` (`state=api-key`) or the token is `valid`; 1 for `missing`, `unreadable`, `invalid`, or `unverifiable`, each with a remediation message |

This site uses Just the Docs, a documentation theme for Jekyll.