Skip to main content

CLI flags

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: 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

On both backends, each pass defaults to a different model rather than one blanket choice, which kills the old Opus-for-everything default (and, since #55, the API path’s old everything-on-sonnet behavior — measured at ~2.3x the tiered cost): 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. On the subscription backend these are the CLI’s model aliases; on the claude API backend they are real model ids (claude-sonnet-4-6 for A, claude-haiku-4-5-20251001 for B/C/D) threaded into each call. Other API backends (bedrock, gemini, …) have no whyfile tiering, but since #77 whyfile resolves the one model id graphify itself will use (the backend’s model env var, e.g. GRAPHIFY_BEDROCK_MODEL, else graphify’s registry default) and threads it into every pass — so the manifest records the real id and cost is priced by the id’s recognized family (bedrock’s …claude-haiku… ids price at haiku rates). To override the model for every pass: GRAPHIFY_CLAUDE_CLI_MODEL on the subscription backend (e.g. =haiku if your corpus is code-heavy enough that even Pass A doesn’t need sonnet-level reasoning), ANTHROPIC_MODEL on the claude API backend, and the backend’s own GRAPHIFY_<BACKEND>_MODEL env var elsewhere. Explicit env overrides always beat the per-pass defaults. To override a specific pass without an env var (and without every teammate repeating it), commit an intent_models map to whyfile.config.json — see Configuring whyfile (#82). It sits between the env override and the tier defaults above: env override > intent_models[pass] > built-in tier > backend default, applies to any backend (not just claude-cli/claude), and a partial map only touches the passes it lists. --max-concurrency changes wall-clock time only, not cost — on both backends. 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. Concurrent claude -p subprocesses parallelize under one subscription login (measured: 4 concurrent realistic calls at ~3.3× effective concurrency — an earlier claim that graphify serialized them behind a lock is obsolete; current graphify has no such lock). One subscription caveat the meter now makes visible: each claude-cli call carries the CLI’s own context scaffold on its input side (measured at tens of thousands of input tokens per call, mostly cache reads), so the per-pass tokens_in on the subscription backend reads far higher than a lean API call for the same prompt — that is the true figure, not a bug.

Outputs

All outputs are written to the same directory as graph.json: