CLI Reference
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
Section titled “Common commands”flowctl initflowctl specsflowctl tasks --spec fn-1flowctl ready --spec fn-1flowctl show fn-1.2flowctl start fn-1.2flowctl done fn-1.2 --summary-file summary.md --evidence-json evidence.json# evidence.json: {"commits": ["<sha>"], "tests": ["<command>"], "prs": []}flowctl validate --allDeterministic store for optional pre-capture decision-map discovery. Skill page: Chart. Slash map: Commands.
flowctl chart create --title "Multi-tenant billing" --outcome "..." --initial-map-file map.json --jsonflowctl chart show fn-140 --jsonflowctl chart list --jsonflowctl chart frontier fn-140 --jsonflowctl chart add-decision fn-140 --title "Research provider limits" --type research --jsonflowctl chart claim fn-140.D1 --jsonflowctl chart attach-asset fn-140.D3 --asset-file asset.json --jsonflowctl chart resolve fn-140.D1 --answer-file answer.md --sharpen-file sharpen.json --jsonflowctl chart resolve fn-140.D3 --answer-file answer.md --supersedes D2 --jsonflowctl chart out-of-scope fn-140.D4 --reason "Beyond outcome" --jsonflowctl chart release-claim fn-140.D1 --jsonflowctl chart release-claim fn-140.D1 --break-stale --reason "owner session lost" --jsonflowctl chart park-question fn-140 --body-file q.md --jsonflowctl chart remove-question fn-140 --question <key> --jsonflowctl chart wire-decision fn-140.D5 --blocked-by D1 --depends-on D2 --jsonflowctl chart briefing fn-140 --proposal-file proposal.json --jsonflowctl chart locate "https://linear.app/.../stored-url" --jsonflowctl chart link-spec fn-140 --briefing B1 --spec fn-141 --decisions fn-140.D1,fn-140.D2 --jsonflowctl chart abandon fn-140 --reason "deprioritized" --jsonflowctl 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
Section titled “Spec commands”flowctl spec create --title "Add OAuth" --branch fn-1-add-oauth --jsonflowctl spec create --title "Add OAuth" --plan-file plan.md --json # one-shot create+set-plan (--plan - reads stdin)flowctl task create --spec fn-1 --from-json tasks.json --json # bulk tasks: one call, one lock, all-or-nothingflowctl spec set-plan fn-1 --file spec.md --jsonflowctl spec set-branch fn-1 --branch fn-1-new-name --json # rename an existing spec's branchflowctl spec close fn-1 --jsonflowctl spec ready fn-1 --json # mark ready for execution (human-owned gate, 1.12.0+)flowctl spec unready fn-1 --json # back to draftA 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.
flowctl brief # cold-session orientation, <=2k tokensflowctl brief --full # same sections, no truncationflowctl brief --json # machine form, per-section truncated flagsThe one-shot and bulk forms are the ceremony fast path: a spec with a plan plus its full task set lands in two calls instead of ~eight, with the same validation, atomicity, and receipts as the granular verbs — --from-json takes a non-empty array of {title, description?, acceptance?, satisfies?, deps?, priority?} where deps entries are task ids or 1-based indexes of earlier entries, rejects the whole batch on any invalid item with zero writes, and returns the created ids in input order. Granular verbs are unchanged and remain the editing path.
spec ready / spec unready toggle the spec’s readiness flag — the human-owned “complete enough to hand to an agent” gate. Both are idempotent (no write, no updated_at bump when the flag already matches; --json reports "changed"). The flag is lazy on disk (written only after a toggle; absent reads false) but every JSON read surface (show, specs, list) emits an explicit "ready": <bool>, and ready specs carry a [ready] badge in listings. Orthogonal to status — a ready spec stays open through planning and work. With tracker.readyState configured the tracker is authoritative and overwrites local toggles on sync — see Tracker Sync.
Criteria commands
Section titled “Criteria commands”Thin plumbing for the project’s 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.
flowctl criteria list [--json] # parse + validateflowctl criteria prompt-block # print the completion-review injection block{"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.
Tracker commands
Section titled “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
Section titled “Resolve”flowctl tracker resolve \ [--scope destination|destination.statusIds|destination.stateIds|capabilities] \ [--select KEY=VALUE] [--json]resolve populates or refreshes tracker.resolved. --select persists an explicit choice when discovery finds multiple candidates. Consuming verbs fail unresolved rather than guessing when required facts are absent.
Wire verbs
Section titled “Wire verbs”Wire verbs are locator-addressed and return normalized data:
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
Section titled “Lifecycle verbs and facade”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 Fflowctl tracker sync <spec-id> --op pull --event KEY \ --flow-file F --body-file F --comments-file comments.jsonflowctl tracker sync <spec-id> --op reconcile --event KEY \ --flow-file F --body-file F --source-body-file F \ --comments-file comments.jsonflowctl tracker sync <spec-id> --op comment --event KEY \ --body-file FThe 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.
Result envelope and exit codes
Section titled “Result envelope and exit codes”Success:
{"success":true,"data":{},"degraded":null,"probe":null}Failure:
{ "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
Section titled “State layout”.flow/├── meta.json├── config.json├── specs/├── charts/ # optional chart discovery maps + decision records├── tasks/├── memory/├── bin/└── usage.mdAgents should use flowctl for writes instead of hand-editing state JSON.
CLI responsibility
Section titled “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
Section titled “Agent usage pattern”Agent-facing commands generally follow this sequence:
flowctl ready --spec fn-1 --jsonflowctl start fn-1.2 --jsonflowctl done fn-1.2 --summary-file summary.md --evidence-json evidence.json# evidence.json: {"commits": ["<sha>"], "tests": ["<command>"], "prs": []}flowctl validate --allDirect CLI usage is useful for automation, but human docs should keep teaching the slash-command workflow first.