# CLI Reference

Source: https://flow-next.dev/flowctl/cli-reference/

The deterministic Flow-Next CLI.

`flowctl` is the deterministic CLI for `.flow/` state.

Most users should use `/flow-next:*` commands. Use `flowctl` when debugging state, scripting CI, building integrations, or inspecting what the skills wrote.

## Common commands

```bash
flowctl init
flowctl specs
flowctl tasks --spec fn-1
flowctl ready --spec fn-1
flowctl show fn-1.2
flowctl start fn-1.2
flowctl start fn-1.2 --reclaim   # resume your own in_progress task; since 5.5.0 a plain start on it refuses
flowctl done fn-1.2 --summary-file summary.md --evidence-json evidence.json
# evidence.json: {"commits": ["<sha>"], "tests": ["<command>"], "prs": []}
flowctl done fn-1.2 --range BASE..HEAD --test "python3 -m unittest" --summary-file - --json   # 6.1.0: commits from a contiguous range, summary on stdin
flowctl validate --all
```

**`done` checks its evidence (6.1.0).** Evidence must carry at least one of `commits`, `tests`, or `prs`; other keys besides `base_commit`, `files`, and `files_touched` print a warning and are not rendered. `--range BASE..HEAD` derives `commits` and `base_commit` from the range and fails naming any unreachable SHA; repeat `--test` for several commands. Interleaved task histories keep explicit evidence lists. With `planSync.enabled` not `true`, `done` appends the `stage: plan-sync - skipped(config: planSync.enabled != true)` line to the summary itself.

**`show <spec> --json` is smaller (6.1.0).** It omits the review-attempt and tracker ledgers. Read them with `flowctl review-rounds attempts <spec> --kind plan|impl --review-type plan|impl|completion` and `flowctl sync get-state <spec>`.

## Chart

Deterministic store for optional pre-capture decision-map discovery. Skill page: [Chart](https://flow-next.dev/skills/chart/).

```bash
flowctl chart create --title "Multi-tenant billing" --outcome "..." --initial-map-file map.json --json
flowctl chart show fn-140 --json
flowctl chart list --json
flowctl chart frontier fn-140 --json
flowctl chart add-decision fn-140 --title "Research provider limits" --type research --json
flowctl chart claim fn-140.D1 --json
flowctl chart attach-asset fn-140.D3 --asset-file asset.json --json
flowctl chart resolve fn-140.D1 --answer-file answer.md --sharpen-file sharpen.json --json
flowctl chart resolve fn-140.D3 --answer-file answer.md --supersedes D2 --json
flowctl chart out-of-scope fn-140.D4 --reason "Beyond outcome" --json
flowctl chart release-claim fn-140.D1 --json
flowctl chart release-claim fn-140.D1 --break-stale --reason "owner session lost" --json
flowctl chart park-question fn-140 --body-file q.md --json
flowctl chart remove-question fn-140 --question <key> --json
flowctl chart wire-decision fn-140.D5 --blocked-by D1 --depends-on D2 --json
flowctl chart briefing fn-140 --proposal-file proposal.json --json
flowctl chart locate "https://linear.app/.../stored-url" --json
flowctl chart link-spec fn-140 --briefing B1 --spec fn-141 --decisions fn-140.D1,fn-140.D2 --json
flowctl chart abandon fn-140 --reason "deprioritized" --json
flowctl chart reopen fn-140 --reason "new constraint" --json
```

| Concern            | Contract                                                                                        |
| ------------------ | ----------------------------------------------------------------------------------------------- |
| Envelope           | `{success, schema_version:1, command, result\|error}`                                           |
| Error classes      | `not_found`, `conflict`, `invalid_state`, `invalid_graph`, `stale_claim`, `validation`, `io`    |
| Size ceiling       | `chart.maxDecisions` (default 12); override only via `--force-size --reason` after consent      |
| Stale claims       | `chart.claimStaleAfter` hours (default 24); `--break-stale` always audited                      |
| Locate             | Local provenance ledger only - no network, no title matching                                    |
| Tracker projection | When bridge active and `tracker.charts=on`; local commit first; remote failure never rolls back |

Decision types: `research|probe|eval|prototype|interview|task`. Attendance derived for the first five; `task` requires `--attendance attended|unattended`.

## Spec commands

```bash
flowctl spec create --title "Add OAuth" --branch fn-1-add-oauth --json
flowctl spec create --title "Add OAuth" --plan-file plan.md --json   # one-shot create+set-plan (--plan - reads stdin)
flowctl spec skeleton [--json]   # print the scaffold spec create writes: templates/spec.md via SPEC.md -> spec.md -> bundled (frontmatter stripped)
flowctl task create --spec fn-1 --from-json tasks.json --json        # bulk tasks: one call, one lock, all-or-nothing
flowctl task create --spec fn-1 --title "implement this spec" --require-empty-spec --json   # mint only while the spec has zero tasks
flowctl spec set-plan fn-1 --file spec.md --json
flowctl spec set-branch fn-1 --branch fn-1-new-name --json   # rename an existing spec's branch
flowctl spec chain fn-2 --json      # read-only: may this dependent spec start now, and on which parent's branch
flowctl spec close fn-1 --json      # close the spec and write every task's final status; the caller commits modified_paths
flowctl spec closed-in-range --base origin/main --json   # read-only: which specs does this branch close
flowctl spec ready fn-1 --json      # mark ready for execution (human-owned gate, 1.12.0+)
flowctl spec unready fn-1 --json    # back to draft
flowctl spec set-no-plan fn-1 --json    # record direct execution consent on a zero-task spec (refused once tasks exist)
flowctl spec clear-no-plan fn-1 --json  # clear the field (always allowed)
```

A cold session orients with `flowctl brief` - session-scope sibling of the task-scope `anchor` bundle. One pure-read call renders open specs (one-line goals), actionable tasks with claim state, the last five completions with evidence flags, the memory index, and go-deeper pointers, deterministically capped at \~2k tokens with explicit truncation markers (`--full` lifts the cap, `--json` is the machine form with identical retained items). No git state, no writes: brief is `.flow/`-only, so identical state always renders identical bytes.

```bash
flowctl brief             # cold-session orientation, <=2k tokens
flowctl brief --full      # same sections, no truncation
flowctl brief --json      # machine form, per-section truncated flags
```

**The ceremony fast path.** A spec with a plan plus its full task set lands in two calls instead of about eight, with the same validation, atomicity, and receipts as the granular verbs. `--from-json` takes a non-empty array of `{title, description?, acceptance?, touches?, satisfies?, deps?, priority?}`, where `deps` entries are task ids or 1-based indexes of earlier entries. Since 6.1.0 `description_file` and `acceptance_file` may replace the inline strings (paths resolve relative to the JSON file, or the current directory for stdin), and `touches` is a single line rendered as the task’s Touches line. It rejects the whole batch on any invalid item with zero writes, names every invalid item and the allowed keys in one error, and returns the created ids in input order. The granular verbs remain the editing path. `--require-empty-spec` refuses, naming the existing task, when the spec already has one; the check runs under the same per-spec lock that allocates ids, so exactly one of N concurrent creates wins. That is the atomic mint behind the [no-plan route](https://flow-next.dev/choosing-your-route/#no-plan-route).

**`spec ready` / `spec unready`** toggle the human-owned readiness flag. Both are idempotent (no write and no `updated_at` bump when the flag already matches; `--json` reports `"changed"`). The flag is lazy on disk, so an absent value reads `false`, but every JSON read surface emits an explicit `"ready": <bool>` and ready specs carry a `[ready]` badge in listings. It is orthogonal to `status`. With `tracker.readyState` configured the tracker is authoritative and overwrites local toggles on sync ([Tracker sync](https://flow-next.dev/integrations/tracker-sync/)).

**`spec set-no-plan` / `spec clear-no-plan`** toggle the sibling human-owned `no_plan` boolean, the durable “skip decomposition” consent behind the [no-plan route](https://flow-next.dev/choosing-your-route/#no-plan-route). Same lazy contract as `ready`: idempotent toggles (`--json` reports `"changed"`), absent reads `false`, and every JSON read surface emits an explicit `"no_plan": <bool>` (`noPlan` on `ready --all` rows). Setting is refused once the spec has any tasks, because a planned spec routes through its tasks; clearing is always allowed (stale-field cleanup). The field is flow-local and never tracker-projected. Two consumers read it: [`flow --auto`](https://flow-next.dev/autonomy/pilot/) classifies a marked zero-task spec straight to the work dispatch, and on a ready zero-task spec with no recorded route it applies the plan-versus-no-plan rule and records the result with these two verbs before any mint; [work](https://flow-next.dev/skills/work/#start-without-a-plan) honors the field as the explicit no-plan instruction.

**`spec chain`** is the read-only chain-eligibility predicate for a dependent spec and the one owner of the rule every consumer applies: `flow --auto` selection in ready and backlog mode, attended flow’s next-item pick, `/flow-next:work` at branch creation, and flowctl’s own task-admission gate (`ready --spec`, `next`, `ready --all`). It returns `{spec, eligible, parent, parent_branch, parent_branch_on_remote, reason}`. `eligible` is true when every dependency is landed (`parent` is `null`, `reason` is `no open dependency`, no remote read), or when exactly one dependency is unlanded with all of its tasks done, every other dependency is landed, that parent’s branch exists on `origin`, and no other unlanded spec is already chained on the same parent. A spec now closes on its pull request branch before the merge, so `done` alone does not mean landed. A locally closed dependency counts as landed when the default base records it as closed. Failing that, flowctl reads the dependency’s spec at the merge-base of its branch and HEAD: a close recorded there means this branch is stacked on unmerged work, and the dependency stays chained. With no close in the shared history it counts as landed, which covers a dependency squash-merged into a non-default integration branch, a deleted branch, and a spec with no recorded branch. A true merge onto a non-default base conservatively stays unlanded. These reads are local and never fetch. Otherwise `reason` is one of `dependency <id> in progress`, `two open parents: <id>, <id>; chains are linear`, `parent branch <b> not on origin; push it or land the parent first`, `dependency <id> closed locally but not recorded at <base>; dependency branch <ref> is in this branch's history; fetch the base or land it`, `parent <id> already chained by <sibling-id>`, `base query failed: <error>`, or `remote query failed: <first stderr line>` (`parent_branch_on_remote: null`; a failed query is never reported as an absent branch). At most one `git ls-remote --heads origin` per invocation, none when the spec has no dependencies, and never `gh`. Exit 0 on any evaluation; exit 2 when the spec or a named dependency does not exist. The task-admission gate treats the chain parent as satisfied and still empties the frontier on every other not-done dependency; task-level `depends_on` is unchanged. Consumers: [work](https://flow-next.dev/skills/work/#dependent-specs-branch-from-the-parent), [make-pr](https://flow-next.dev/skills/make-pr/#dependent-specs-chains-and-stacks), [land](https://flow-next.dev/autonomy/land/#chains-and-stacks).

**`spec close`** closes the spec and writes each task’s final `status: done` into its tracked JSON file, so a fresh clone reads the finished state. It refuses, before any file changes, when a task is incomplete. It writes files and commits nothing: `--json` returns `modified_paths`, naming the spec file and every task file it rewrote, and the caller commits exactly those. [make-pr](https://flow-next.dev/skills/make-pr/#the-spec-closes-at-the-pull-request-head) does this as the last commit before the pull request opens. Creating or starting a follow-up task reopens a closed spec and reports the spec file the same way.

**`spec closed-in-range --base <ref>`** lists the specs a branch closes: `done` at HEAD, absent or not `done` at the merge base with `<ref>`, and with task files the range touches. A close that changes only the spec record is excluded, and so is a sibling whose close belongs to the history of its own still-existing branch. Text output prints one id per line; `--json` returns `{"spec_ids": [...]}` in the same order. It reads local committed objects only and never writes or fetches. [make-pr](https://flow-next.dev/skills/make-pr/#several-specs-in-one-pull-request) uses it to write one body for a branch that closes several specs, hosting on the last id when no spec names the branch.

## PR briefing artifact

`pr-cognitive-aid` validates, stores, selects and renders the one object behind a [make-pr](https://flow-next.dev/skills/make-pr/) body.

```bash
flowctl pr-cognitive-aid validate --file aid.json [--json]      # read-only
flowctl pr-cognitive-aid write <spec-id> --file aid.json --base-sha <sha> --head-sha <sha> [--json]
flowctl pr-cognitive-aid current <spec-id> --base-sha <sha> --head-sha <sha> [--json]
flowctl pr-cognitive-aid render <spec-id> --base-sha <sha> --head-sha <sha>
flowctl pr-cognitive-aid render --file aid.json
```

* **`render` emits one briefing for every diff size.** The sections are Why, What changes for a user or operator, Scope, Blast radius, Verification, Tradeoffs and Open items, and an empty section disappears. There is no compact or full form, no size threshold and no body line budget. Each review step shows at most ten described files as linked rows; further rows are counted. Verification ticks only a cell whose `outcome` is `pass`; `fail` and `unverified` render unticked with their note, and a cell with no outcome is a plain item. Artifact id, base and head ride in one HTML comment.
* **Input may be sparse.** `validate`, `write` and both `--file` readers accept an object that lists only the must-read files and omits each file’s change type, line counts and diff link. flowctl fills those from the diff, appends the remaining files as a rest-of-diff set, and stores the complete artifact.
* **Mentions are made inert, numbers stay live.** `@name` in authored prose cannot ping anyone. Issue and pull request numbers, URLs and commit SHAs remain links, so `fixes #12` still closes that issue on merge.
* **Several specs.** `specIds` lists every spec the body covers, requirement ids are qualified (`fn-250:R4`), and coverage prints one line per spec.
* **The additions are additive.** Four optional authored strings (`userImpact`, `blastRadius`, `tradeoffs`, `openItems`) and the optional `outcome` on a verification cell leave the schema version at 1; stored artifacts stay valid.
* **`write` never overwrites.** It validates and creates one immutable generation under `.flow/artifacts/<spec-id>/pr-cognitive-aid/`. `current` answers `current`, `absent`, `stale`, `unsupported` or `invalid`, and exposes no artifact unless it is current. A sparse artifact at an unchanged base and head is reused.
* **Errors arrive together.** `validate` and `write` report every independent violation with its field path in stable order and exit 2. A summary that is only whitespace is rejected by field name.
* `html-input` was removed with the HTML render lenses in 7.0. For a visual view of a diff, run [`/flow-next:visual`](https://flow-next.dev/skills/visual/).

## Next unit selection

Deterministic “what should run now” for scripted drivers. Attended flow reads it as one hint when it picks the next open spec. `flow --auto` classifies each hop from the flow skill’s routing reference and the spec’s own status fields instead of this verb. Interactive sessions rarely need it; it is the right probe when scripting a loop or debugging why a driver picked (or skipped) a spec.

```bash
flowctl next [--specs-file specs.json] [--require-plan-review] [--require-completion-review] [--json]
```

```json
{"status": "plan|work|completion_review|none", "spec": "fn-12", "task": "fn-12.3", "reason": "needs_plan_review|needs_tasks|needs_completion_review|resume_in_progress|ready_task|none|blocked_by_spec_deps", "blocked_specs": {"fn-12": ["fn-3"]}}
```

Selection walks specs in id order and stops at the first actionable unit. A zero-task spec with explicit `no_plan: true` reports `status: work` with its spec id and no task id; an explicit `--require-plan-review` gate still reports `needs_plan_review` until satisfied. An unmarked zero-task spec reports `status: plan` with `reason: needs_tasks`. Direct work creates the single full-spec execution owner; the selector does not mint one. Existing planned tasks retain their normal selection and review gates.

`--require-plan-review` holds work until the spec’s plan review reaches `ship`. `--require-completion-review` gates spec closure. With all tasks done but `completion_review_status` outside `{ship, not_required}`, it returns `status: completion_review`. An unrecognized or absent value satisfies nothing.

## Unattended-run commands

These verbs serve [`/flow-next:flow --auto`](https://flow-next.dev/autonomy/pilot/). They keep their `pilot` spelling; the `/flow-next:pilot` command itself was removed in 6.1.0.

```bash
flowctl pilot snapshot [--spec <id>] --json      # 6.1.0: everything one hop needs, in one read
flowctl pilot strikes record <spec-id> --stage <stage> --reason "<reason>" [--json]
flowctl pilot strikes list [--json]              # the two-strike ledger flow --auto writes
flowctl pilot strikes clear <spec-id> [--json]   # the human clear after a strike 2/2 verdict
flowctl pilot strikes clear --all [--json]
flowctl pilot-log append --id <id> --action <triaged|advanced|asked|blocked|needs-human> [--stage <stage|->] [--cost-tokens <n>] [--reason "<one line>"] [--json]
flowctl ready --all [--json]                     # backlog-wide eligibility scan for flow --auto --backlog
flowctl ready --spec fn-1 --admit --in-flight fn-1.1 --cap 3 --json   # 6.1.0: rolling admission
```

**`pilot snapshot`** (6.1.0) bundles the run guards, config, candidates with their chain, claim, and strike facts, the selected spec, the review backend, lifecycle and PR observation, branch existence, QA freshness, and the task list before dispatch. One PR listing joins branches to their open, merged, and closed pull requests. A failed probe stays explicit, and the caller ends the hop instead of reconstructing the state.

**`pilot strikes record`** (6.1.0) increments one cumulative counter per spec under the ledger lock; at count 2 it unreadies the spec. `--json` returns `count` and `unreadied`, and an unknown spec fails.

**`ready --admit`** (6.1.0) adds `admitted` and `held` lists to the ready read, with mechanical reasons: dependency closure, missing or overlapping Touches (`touches-missing` when a task has no Touches line), always-serial surfaces, and the `--cap` capacity. JSON task rows carry parsed `touches` and transitive dependency facts. The owner can still hold an admitted task for coupling the Touches lines do not show.

**`pilot strikes`** reads and clears the ledger at `<git-common-dir>/flow-next/pilot-strikes.json`, which `flow --auto` writes when a hop advances nothing. The ledger lives under the git common dir, so worktrees share it and `git add -A` can never commit it. `list` is empty-safe (a missing ledger renders empty at exit `0`). `clear <spec-id>` removes exactly one entry atomically; an unknown id is a not-found exit `3` naming the known entries. Clearing never touches spec readiness in either direction. A `strike 2/2` verdict unreadies the spec and names this command in its reason string, because on a repo with `tracker.readyState` armed the board echo re-grants readiness and cannot clear the strike.

**`pilot-log`** appends one decision-log row per dispatched stage under `.flow/pilot-runs/` when `flow --auto --backlog` reaches a terminal (auto-gitignored, and not a `receipts/` path). `--action` is the frozen enum above; a live run logs only terminal actions and `triaged` is diagnostic-only. `--cost-tokens` is host-reported; flowctl stores the row and never measures cost. `--reason "<one line>"` stores the host’s verdict reason verbatim as `reason` on that row, so a chained dispatch’s row begins `chained on <parent-id>; `; rows written without the flag keep the frozen `{tick, id, action, stage, costTokens}` shape.

**`ready --all`** is the deterministic substrate for `flow --auto --backlog` (or `pilot.autonomy=backlog`). For every open spec it returns `ready`, `noPlan`, `readySignal`, `blockedBy` (unsatisfied dependency spec ids; a chain parent per `spec chain` is not listed), and `hasSpec`, and never a judgment field. Whether an item is workable, thin, or needs a spec is the skill’s agentic read in the triage stage.

## Criteria commands

Thin plumbing for the project’s [standing criteria](https://flow-next.dev/reference/standing-criteria/) in the user-owned `.flow/criteria.md` (G-ID grammar: one line-anchored `- **G<N>:** <criterion prose>` bullet per criterion). Parse and validate only, since judging compliance belongs to spec completion review.

```bash
flowctl criteria list [--json]      # parse + validate
flowctl criteria prompt-block       # print the completion-review injection block
```

```json
{"success": true, "criteria": [{"id": "G1", "text": "Every route change regenerates the API contract."}], "count": 1, "path": "/abs/path/to/repo/.flow/criteria.md"}
```

An absent or empty file returns an empty list (and empty `prompt-block` output) at exit 0 - absence costs nothing anywhere. An **existing** file that is unreadable or invalid fails closed: nonzero exit with the validation errors on stderr and empty stdout, so a careless append cannot inject error text into a prompt file. Ids must be unique, gaps are allowed, and at most 100 active criteria are accepted. `path` is absolute, and `null` when the file is absent.

The RepoPrompt and host completion-review workflows run `criteria prompt-block` before reserving a review round, which turns a broken criteria file into a fast validation error instead of a spent round.

## Feature map

Read-only facts about the committed [feature map](https://flow-next.dev/skills/features/) at `.flow/features/`, so setup, prime, and flow share one recommendation for `/flow-next:features`. flowctl never validates the four-section shape (the skill does) and never edits the map.

```bash
flowctl features status [--repo <path>]... [--json]
```

* **`recommendation`** is `seed` (no map), `maintain` (the map is due), or `none`. **`due`** is true when a map exists and at least one open drift note or stale feature file exists; **`reasons[]`** names each.
* **`features[]`** has one row per feature file (the index `README.md` excluded): `file`, `state` (`proven`, `never-proven`, or `malformed`), `last_proven` (`{date, commit}` or `null`), `measured_from` (`commit`, or `date` when the recorded commit is not in this clone, such as a squashed branch head), `commits_since`, and `stale`.
* **`commits_since`** counts default-branch commits (`origin/HEAD`, then `main` or `master`, then `HEAD`; reported as `base`) after the proof that change at least one path outside `.flow/` that is not documentation. A row is `stale` when that count reaches [`features.staleAfterCommits`](https://flow-next.dev/flowctl/configuration/#feature-map) (default 50, reported as `threshold`), and always when it is never proven or malformed.
* **`--repo <path>`** (repeatable) names a sibling repo that holds product code in a home-base workspace, relative to the repo that holds `.flow/`. Each proven row then adds that repo’s product commits since the proof date (measured from its own default branch) to `commits_since` and reports the split as `commits_since_by_repo` (`"."` is the `.flow/` repo); the output gains `repos`. A path that is not a git repo root, is the `.flow/` repo itself, or has no default branch that resolves exits `2` naming it. Without `--repo` the output is unchanged.
* **`open_drift`** lists active knowledge entries tagged `feature-map-drift` as `{id, title, path}`; it is `null` when memory is disabled or uninitialised, so only the age condition applies.

Exit `0` (or `2` for a bad `--repo`). A repository without `.flow/` has no map and reads as `seed`. The command never dispatches `/flow-next:features`. How the three signals fit together: [Keep the feature map current](https://flow-next.dev/guides/keep-feature-map-current/).

## Judge

`flowctl judge` classifies one supplied state with a bundled TypeSafe Jev preset and applies that preset’s fixed decision rule, so every host computes the same decision from the same answers. The `route` preset is the exception: it is code only and never sends a request, with or without a key, so routing never asks Jev. It is the plumbing behind [Optional Jev judgments](https://flow-next.dev/guides/jev-judge/); the skills call it, and you can call it to inspect a decision.

```bash
flowctl judge --preset <name> --state-file state.json [--json]
flowctl judge --preset route --spec <spec-id> --json        # the live spec's lifecycle, decided in code; sends nothing
flowctl judge --preset tier --task <task-id> --json         # 6.1.0: tier inputs from the task; returns tier_line, spawn_model, implementer
flowctl memory search "windows subprocess" --limit 15 --rerank --json  # BM25, then one rerank request over the top 15
```

Presets: `route`, `fork-gate`, `memory-rerank`, `tier`. The retired `qa-gate` preset is an unknown-preset error: the QA gate never asks Jev. The command reads `TYPESAFE_API_KEY` from the environment at call time; `judge.enabled=false` disables it. Requests go to `jev-latest` with a 10-second timeout and two retries only for HTTP 429 and 529 (after 1 s and 2 s); a request estimated over 32k tokens is rejected without sending. The command never writes state, answers, or credentials to disk.

An available result carries `success`, `available`, `preset`, the returned `model`, typed `answers`, `decision` (`value`, `rule`, `met`), `latency_ms`, and `usage`. Tier decisions add the three leading `candidates` as `[option, probability]` pairs; memory decisions carry every judged entry id and score, reordered, none dropped. `--preset route --spec <spec-id>` always reports `available: false, reason: routing_is_code`, and its `decision` carries `value`, `rule`, `met`, `pr_ref`, and `startable_target_fact` for the tail and QA gates to reuse. It takes `--spec` only: intake routing is the host’s, so a route `--state-file` is a command error.

An unavailable result exits 0 and names the reason so the caller takes its existing fallback. Presets other than `route` omit the decision:

```json
{"success": true, "available": false, "preset": "fork-gate", "reason": "no_key"}
```

Reasons: `no_key`, `disabled`, `http_<status>`, `transport`, `timeout`, `bad_answer`, `over_budget`. A failed PR probe adds `pr_probe_failed: true` so the caller keeps its failure outcome. Unknown presets, unreadable or non-JSON state files, and missing required state fields exit non-zero; one error names every missing field.

`memory search --rerank` sends up to 15 BM25 hits in one `memory-rerank` request and reorders them by Jev score (ties retain BM25 order) without dropping any; `--limit` applies after the reorder. The judge receives each entry’s id, title, track, category, module, tags and snippet, never its path or BM25 score. JSON adds `jev_score` and `jev_rank` to reranked matches and top-level `rerank: "jev"`; an unavailable judge keeps BM25 order and returns `rerank: "bm25"`, and zero hits send no request.

## Rendered artifacts

Since 6.1.0 a skill hands flowctl its judgment and flowctl renders the artifact around it. flowctl derives ids, dates, counts, and commit and branch facts, validates every field, and writes atomically. An invalid payload reports every error together and writes nothing. `--skeleton` prints the exact authoring shape.

```bash
# One-call state reads
flowctl preflight [--spec <id>] --json      # planning config plus independent gate probes
flowctl setup-status --json                 # setup's read-only probes and recorded optional answers


# Artifacts rendered from the host's judgment
flowctl prospect write --skeleton
flowctl prospect write --from-json prospect.json --json
flowctl qa receipt --skeleton
flowctl qa receipt --from-json qa.json [--receipt receipt.json] --json
flowctl memory add --track <track> --category <category> --title "..." --body-file body.md --check-overlap --json
flowctl memory audit-scan --json
flowctl memory apply --plan audit.json --json


# Review plumbing
flowctl review-prompt impl <task-id|branch> --axis correctness --base <ref> --out prompt.md
flowctl review-prompt plan <spec-id> --axis correctness --out prompt.md
flowctl review-prompt completion <spec-id> --axis correctness --base <ref> --out prompt.md
flowctl review-rounds record <spec-id> --kind plan|impl --review-type plan|impl|completion \
  --output-file review.md --reservation-id <id> --attach [--task <task-id>] [--json]
flowctl review-rounds resume-terminal <spec-id> --review-type completion --json


# Scoped reads
flowctl glossary list [--json] --match "<text>"
```

* **`preflight`** returns the config snapshot as `value` plus independent `probes` for config, strategy, glossary, decision entries, tracker, review backend, and memory. Each probe carries `status` and `value`, with an error on failure; each consumer keeps its own fail-open or default behavior.
* **`setup-status`** treats missing or unreadable setup state as a first run. Setup records the optional questions you declined, so a steady re-run asks nothing again.
* **`prospect write`** takes the title, focus, grounding, ranked survivors, and rejected ideas, and derives the artifact id, date, counts, and rejection rate.
* **`qa receipt`** takes `id`, `qa_outcome`, findings, and R-ID coverage, plus optional mode and `BLOCKED`/`NA` reasons. It derives commit, branch, timestamps, counts, and prior-finding lineage. `BLOCKED` or `NA` never closes a prior finding nobody observed, and an invalid payload leaves the previous receipt in place.
* **`memory add --check-overlap`** returns the overlapping entries without writing, so the host can fold a rediscovery into one with `--update <id>`.
* **`memory audit-scan`** returns frontmatter, schema errors, recurrence counts, module existence and change evidence, and whether a hardened rule is present. **`memory apply`** takes the host’s plan (a list, or `{"entries": [...]}`); each entry names `id` and may carry `set`, `stamp`, `body`, `move`, `remove`, and `replacement`. Entries apply atomically one by one, moves and replacements update references, unknown ids are reported while the rest proceed, and a decision record can only be superseded.
* **`review-prompt`** renders the dispatch prompt a host review uses, from the same builders and re-review context as backend review.
* **`review-rounds record --output-file`** derives the verdict, review text, suppressed and classification counts, and unaddressed R-IDs from the review output; structured findings win over prose. A receipt payload that contradicts the output exits 2 before any state changes. `--attach` publishes the journaled receipt in the same call; the matching reservation is still required. **`resume-terminal`** returns `{action, status, exit}` for completion-review re-entry and rejects unknown persisted states.
* **`glossary list --match`** returns only the entries whose term or avoid-alias occurs in the text (whole word, case-insensitive). The worker’s [anchor bundle](https://flow-next.dev/skills/work/#worker-subagent-model) passes it the task’s title and description.

Review commands also need fewer arguments. Codex plan review runs without `--files`, an omitted `--base` resolves to the default branch (`origin/HEAD`, then `main` or `master`), and plan and completion receipts default to `<repo>/.flow/tmp/`. Fan-out saves its round identity before dispatch, so an interrupted round recovers the draws that finished.

A malformed `.flow/config.json` is reported, never reset. Readers name the file and give line and column for a JSON syntax error, `config set` refuses to overwrite it, and `validate` reports a root error. A missing file still means defaults.

## Tracker commands

`flowctl tracker` is the deterministic provider boundary for Linear, GitHub, GitLab, and Jira. Skills supply semantic input files and recovery judgment. The CLI owns credentials, provider requests, pagination, retries, normalization, capability checks, mutations, and transaction boundaries.

### Resolve

```bash
flowctl tracker resolve \
  [--scope destination|destination.statusIds|destination.stateIds|capabilities] \
  [--select KEY=VALUE] [--json]
```

`resolve` populates or refreshes [`tracker.resolved`](https://flow-next.dev/flowctl/configuration/#tracker-bridge). `--select` persists an explicit choice when discovery finds multiple candidates. Consuming verbs fail `unresolved` rather than guessing when required facts are absent.

### Wire verbs

Wire verbs are locator-addressed and return normalized data:

```bash
flowctl tracker wire read           --locator "$LOCATOR" [--json]
flowctl tracker wire update         --locator "$LOCATOR" [--title TEXT] [--body-file F] [--json]
flowctl tracker wire comment-add    --locator "$LOCATOR" --body-file F [--json]
flowctl tracker wire comment-list   --locator "$LOCATOR" [--json]
flowctl tracker wire comment-update --locator "$LOCATOR" <comment-id> --body-file F [--json]
flowctl tracker wire comment-delete --locator "$LOCATOR" <comment-id> [--json]
flowctl tracker wire label          --locator "$LOCATOR" [--add LABEL]... [--remove LABEL]... [--json]
flowctl tracker wire assign         --locator "$LOCATOR" [--add USER]... [--remove USER]... [--json]
flowctl tracker wire list-open      [--json]
flowctl tracker wire list-states    [--json]
flowctl tracker wire relation-list  --locator "$LOCATOR" [--json]
flowctl tracker wire question       --locator "$LOCATOR" \
  --subject-id ID --blocked-stage STAGE --reason-code CODE \
  --question-slug SLUG --body-file F [--json]
flowctl tracker wire attach         --locator "$LOCATOR" --file PATH [--json]
flowctl tracker wire attach-get     <attachment-id> --out PATH [--json]
```

`list-states` (4.1.0) enumerates the destination’s workflow states read-only - Linear workflow states or Jira project statuses as `{"states": [{"id", "name", "type"}], "complete": bool}`. The `complete` flag distinguishes a provably full listing from a truncated one, so a caller can refuse instead of trusting a partial page; GitHub and GitLab have no workflow-state pool and return a typed `capability` error. It never writes config - detection stays separate from `tracker resolve`, which repairs the mapping and writes. `relation-list` returns normalized directed dependency rows for backlog ordering and fails closed when bounded pagination cannot prove the graph complete. `question` computes its marker id from the four stable identity inputs, reads comments before writing, and skips an existing id; free prose travels only through the body file and does not affect deduplication.

Wire verbs are useful for integrations and diagnostics. Lifecycle callers use the facade below because granular verbs do not provide create-if-unlinked, semantic marker deduplication, or aggregate receipts.

### Lifecycle verbs and facade

```bash
flowctl tracker create <spec-id> --title TEXT --body-file F [--event KEY] [--json]
flowctl tracker create-first --title TEXT --body-file F --retry-key <16-hex> [--json]
flowctl tracker persist-external <spec-id> --identifier KEY-N \
  [--id DURABLE-ID] [--url URL] --source mcp [--event KEY] [--json]
flowctl tracker status <spec-id> \
  --to backlog|todo|in_progress|in_review|done|cancelled \
  [--reason completed|not_planned|duplicate|reopened] [--event KEY] [--json]
flowctl tracker relate <spec-id> --blocked-by <dependency-spec-id> [--event KEY] [--json]
flowctl tracker sync-body <spec-id> --flow-file F \
  [--tracker-body-file F] [--direction push|pull] [--event KEY] [--json]


flowctl tracker sync <spec-id> --op push --event KEY \
  [--flow-file F] [--body-file F] [--comment-file F] [--overwrite-diverged]
flowctl tracker sync <spec-id> --op push --status-only --event KEY
flowctl tracker sync <spec-id> --op pull --event KEY \
  --flow-file F --body-file F --comments-file comments.json
flowctl tracker sync <spec-id> --op reconcile --event KEY \
  --flow-file F --body-file F --source-body-file F \
  --comments-file comments.json
flowctl tracker sync <spec-id> --op pull|reconcile --event KEY --prepare   # 6.1.0
flowctl tracker sync <spec-id> --op comment --event KEY \
  --body-file F
```

The facade owns create-if-unlinked, lifecycle ordering, marker deduplication, status, readiness and dependency projection, transaction boundaries, and exactly one aggregate receipt. Pull and reconcile receive the already adjudicated final Flow form as an input file; flowctl never authors the semantic merge.

Since 6.1.0 `push` renders an omitted body from the spec, and an unchanged spec renders identical bytes; `--status-only` needs no body. A body-writing push on a linked spec whose tracker body changed since the last sync returns `conflict` with subtype `tracker_diverged` and writes nothing. `--overwrite-diverged` overwrites it and belongs only after a human confirms ([Edits made on the tracker](https://flow-next.dev/integrations/tracker-operations/#edits-made-on-the-tracker)). `--prepare` on pull or reconcile returns the pre-reduction class, the tracker body with dependencies stripped, the base pair, and the genuine comments in one call, excluding marker comments and their hash matches. Its `files` point to private mode-0600 snapshots that the next facade call consumes; snapshots older than one hour are swept. The agent keeps the conflict and fold decisions.

### Result envelope and exit codes

Success:

```json
{"success":true,"data":{},"degraded":null,"probe":null}
```

Failure:

```json
{
  "success": false,
  "class": "conflict",
  "error": "redacted human-readable summary",
  "retryable": false,
  "details": {"normalized": "todo", "candidates": []}
}
```

`data` is verb-specific. `degraded` records a confirmed capability transition. `probe` records a capability probe outcome without claiming a transition. Failure `details` is typed: rate limits include `retry_after_s`, capability failures include `capability` and `required_plan`, conflicts include `normalized` and `candidates`, and MCP continuations include `action` and `payload`. Branch on `class`, never provider error text.

| Exit | `class`                    | Meaning                                                           |
| ---: | -------------------------- | ----------------------------------------------------------------- |
|    0 | success                    | Completed; inspect `degraded` and `probe`                         |
|    2 | `invalid_input`            | CLI input or local contract is invalid                            |
|    3 | `inactive`                 | Tracker bridge is inactive                                        |
|    4 | `unresolved`               | Required `tracker.resolved` facts are absent or incomplete        |
|    5 | `auth`                     | Credential is absent or rejected                                  |
|    6 | `rate_limited`             | Provider rate limit; retry only when `retryable` is true          |
|    7 | `transport`                | Provider request failed or returned an unusable response          |
|    8 | `not_found`                | Addressed provider object does not exist                          |
|    9 | `capability`               | Requested operation is unsupported by the resolved capability set |
|   10 | `conflict`                 | Durable identity, status mapping, or transaction state conflicts  |
|   11 | `stale_id`                 | Persisted provider identity is stale                              |
|   12 | `external_action_required` | Host must perform the described MCP continuation                  |

## State layout

```txt
.flow/
├── meta.json
├── config.json
├── specs/
├── charts/          # optional chart discovery maps + decision records
├── tasks/
├── memory/
├── features/        # optional user-POV feature map
├── prospects/       # optional ranked idea lists
├── templates/       # optional spec template (spec.md)
├── criteria.md      # optional standing criteria
├── artifacts/       # PR briefing source generations
├── review-receipts/ # review receipt copies
├── pilot-runs/      # gitignored backlog-mode decision log
├── bin/
└── usage.md
```

Agents should use `flowctl` for writes instead of hand-editing state JSON.

## CLI responsibility

| Responsibility    | Why it lives in `flowctl`            |
| ----------------- | ------------------------------------ |
| ID allocation     | Must be deterministic and merge-safe |
| State transitions | Must be machine-readable             |
| Validation        | Must run in CI and local shells      |
| Receipts          | Must survive chat context            |
| Migration         | Must preserve repo-local state       |

Judgment stays in the host agent. `flowctl` should not decide whether a spec is good, whether an architecture is right, or whether a finding is product-important.

## Agent usage pattern

Agent-facing commands follow the sequence at the top of this page, with `--json` on the reads. Direct CLI usage is for automation and debugging; the docs teach the slash-command workflow first because that is the product surface.
