Skip to main content

CLI flags

FlagDefaultDescription
--graphgraphify-out/graph.jsonPath to the graphify output graph.json
--docsdocs/Directory containing markdown source files
--passesA,B,CComma-separated passes: A extract, B anchor, C cross-doc relate, D cross-doc concept resolution (opt-in)
--backend(auto)Backend selection (see LLM backend)
--progressautoProgress reporting mode: auto (live line on TTY, heartbeat when piped), plain (heartbeat lines only), json (NDJSON events on stderr), none (silent). stdout stays results only; warnings and progress go to stderr.
--min-confidence0.75Minimum confidence_score for Pass C and Pass D edges
--max-concurrency4Maximum number of concurrent LLM requests
--max-tokens500000Estimated-token ceiling for the whole run (all passes, summed). Enforced three ways (a pre-flight prompt, a mid-Pass-A breaker, and a post-Pass-A checkpoint before Pass B), so a run stays within the estimate it showed you. Nothing is written on an abort; --yes skips only the pre-flight prompt, never the checkpoint. 0 = unlimited. Full semantics in AGENTS.md
--max-cost-usd2.00Cost guard for API backends: prompts if the pre-flight estimate exceeds this (the subscription backend has no per-token bill to guard, so it skips this check; --max-tokens is the guard that applies there). Pre-flight only; the post-Pass-A checkpoint gates tokens, not cost
--yesfalseSkip the pre-flight ceiling prompt (non-interactive / CI); does not skip the post-Pass-A whole-run checkpoint
--dry-runfalseProject calls/tokens/cost/time as JSON and exit: no extraction (one tiny backend liveness ping only). JSON shape documented in AGENTS.md
--no-cachefalseBypass the Pass A cache entirely: no reads, no writes; every section re-extracts. See Caching & resume
--doctor [--json]falseCheck the environment (runtime, backend auth, graph/docs shape, version drift) and exit; --json for machine output. Version drift is advisory only; a stale editable install no longer fails the run
--versionn/aPrint the installed version and exit
Set --backend to subscription, api, or an explicit provider name (see LLM backend). stdout is strictly results-only. The pre-flight projection line (Pass A: ~… tokens (whole run) …), the Pass A: gated N section(s) prefilter notice, and every ceiling/prompt/abort message print to stderr; stdout carries only the per-pass result lines, the sidecar path, and Done..

Exit codes

Stable across releases (src/whyfile/errors.py), safe for scripts/agents to branch on:
CodeMeaning
0Success
1Unexpected error (unhandled exception; never raised deliberately)
2Bad input: invalid --passes, graph.json missing, no .md docs found
3Token/cost ceiling: pre-flight decline, non-interactive over-ceiling, the Pass A budget breaker, or the post-Pass-A whole-run checkpoint before Pass B
4Backend unusable: none configured, the graphify runtime missing, or all Pass A sections failed
5Policy gate: changed --fail-on-constraint (a changed file is governed by a constraint), intent-diff --gate (constraint-governed code changed with no superseding record in the PR), or check (a compiled constraint in intent-rules.json is violated)
See AGENTS.md for the full contract (per-code agent actions, --dry-run/--doctor JSON shapes, progress events, and manifest fields) for driving this tool non-interactively.

Per-pass models (subscription backend)

On the subscription (claude-cli) backend, each pass defaults to a different model rather than one blanket choice, which kills the old Opus-for-everything default:
PassDefault model
A (extract)sonnet
B (anchor)haiku
C (cross-doc relate)haiku
D (concept resolution)haiku
Pass A keeps the stronger model because it does the actual reasoning (deriving a claim, rationale, and alternatives from prose); B/C/D are comparatively mechanical, so haiku carries them at a fraction of the cost. Set GRAPHIFY_CLAUDE_CLI_MODEL to override the model for every pass, e.g. GRAPHIFY_CLAUDE_CLI_MODEL=haiku if your corpus is code-heavy enough that even Pass A doesn’t need sonnet-level reasoning. --max-concurrency changes wall-clock time only, not cost, and only on the API backend. The actual cost levers are the model (per-pass tiering above), the call count (Pass A’s structural gate on trivial sections), and per-call context; raising concurrency just runs the same calls faster in parallel, there. On the subscription backend, claude-cli calls serialize upstream in graphify (a lock around the CLI subprocess), so --max-concurrency has little effect: raising it does not make subscription runs faster.

Outputs

All outputs are written to the same directory as graph.json:
FileContents
.whyfile.jsonSidecar: all intent nodes and edges added across runs
graph.enriched.jsonOriginal graph merged with the intent layer (graphify node-link format)
enrichment_report.mdBefore/after metrics: node/link/isolated counts, intent breakdown by kind, anchored vs orphaned, grounding coverage
.whyfile_progress.jsonlProgress stream (NDJSON, one event per line): run_start, pass_start, tick, unit_fail, pass_end events for agents to tail or poll. Written for any --progress mode except none.
intent_run.jsonPer-run manifest: status/error, metrics, artifacts, and per-pass records (passes[], including s_per_call, cache_hits, and cache_misses; the cache fields are nonzero only for Pass A). Written on every run (independent of --progress mode). At run end, an estimated-vs-actual runtime/duration reconciliation line is printed to stderr.
intent_runs.jsonlHistory: the same manifest object appended as one line per run, oldest first: a run-over-run log without snapshotting intent_run.json yourself.
.whyfile.prev.jsonSnapshot of the sidecar as it was before this run’s merge. Written every run (skipped on the first run). Powers digest --since last-run. Git-ignored under graphify-out/.