path is a spec file or a folder of specs. Use hunch --help to choose a command and hunch run --help (or another command) for its own flags. Commands that evaluate specs lint the project first: warnings go to stderr; an error exits 2. show reads a stored table even if the source file is no longer present.
Commands
Commands ask only for answers the store lacks.
--max-cost 0 guarantees no spend: if anything is missing, the command stops before asking. For suggest, the cap also covers each writer call at its worst case.
hunch ask
<name>.yml in the current folder (the name defaults to the question’s first four words that aren’t filler, command_destroy_data above), runs it like run, prints how the answers split and the ten rows it was least sure of, and writes every row’s answer to <name>.answers.csv, in columns named as run’s tables name them: <name>, <name>_p, <name>_route. The key is the id column, else the first; the model sees --columns, else every column but the key and gold_*. Each question gets act: 0.9, so “unsure” means below 0.9. If <name>.yml exists and differs from what ask would write (another question or columns, or your own edits), it stops: pass --name, or hunch run the spec. A spec that fails lint isn’t left behind.
hunch plugins and hunch install
hunch-engine-<name> on PyPI. hunch is usually a tool with an environment of its own, so pip install elsewhere doesn’t reach it; install does. In a uv tool install, it rebuilds the tool with the plugin added (uv tool install hunch-ai --with … --with hunch-engine-ollama, keeping plugins added before), since a package put beside the tool would be dropped by the next uv tool upgrade. Packages installed from a folder or git are kept as they were; if one was installed editable, it prints the command to run instead. Anywhere else, it installs into hunch’s interpreter with uv pip, or pip without uv. plugins also shows a plugin that failed to load, and one ignored because it claimed a built-in prefix. See Engines from plugins.
hunch init
hunch skill
.claude/skills/hunch/SKILL.md (Claude Code) and .agents/skills/hunch/SKILL.md (Codex; Cursor reads both). It tells the agent how to run the loop (lint, compile, run with a cost cap, test, diff) and what not to do: spend without --max-cost, write *.reviews.csv, or edit .hunch/. Each file prints installed, updated or up to date; an existing copy is replaced, so re-run after upgrading hunch and commit the result.
hunch hook
install copies the command guard (spec, 38 labelled commands, NOTICE) into hunch/, keeping files already there, adds .hunch/ to .gitignore, and adds a PreToolUse hook with matcher Bash and a 30-second timeout to .claude/settings.json and .codex/hooks.json, keeping the rest of each file. It writes nothing if a settings file can’t be read. The hook command finds the spec through $CLAUDE_PROJECT_DIR (Claude Code) or the git root (Codex), and ends in || echo a warning, so a missing or older hunch lets commands through instead of blocking them.
run reads the agent’s event, judges the command with request (the last message the person typed, from the Claude Code or Codex transcript; empty if there is none), cwd, description and command, and logs the row, redacted by the spec’s rules, for --traffic. When any answer is yes or routes to review, it replies ask, or deny with --deny (Codex, which cannot ask yet), with the reasons; otherwise it prints nothing. It never replies allow. On any error it prints a systemMessage warning and lets the command through. HUNCH_MAX_COST defaults to 0.01 per command. See Guard your coding agent.
hunch distill
distill extra. Asks nothing: it reads the store’s answers for --node (default: the last judgment) and writes distilled/<judgment>@<hash>/ next to the spec (meta.json and weights.npz). Per question it trains a linear layer on a frozen MiniLM encoder, class-balanced, on the row’s gold where there is some and the engine’s answer otherwise, holding out a fifth of the gold rows by a hash of their text, and fits a temperature so its confidence is a calibrated probability. It prints each question’s training size and rarest answer, warning under 30 examples, and the lines to measure and use it. See Distill a decision.
hunch docs
<name>.html, one self-contained page with no server or network needed, and <name>.manifest.json. It reads the specs, the results of the last test of the same path and the store’s run log, and never asks the engine. See Share what your judgments decide.
The manifest
Flags
--sample picks rows by a hash of the key, so a repeated sample comes from the store and a later full run asks only the rest. run --sample caches its answers but does not replace any table, since downstream readers would take the sample for the whole.
Exit codes
Reading the output
compile
run
run judges missing answers, caches them, and writes one table per judgment. Its summary starts with rows and answers, then names the table and store:
--sample N caches answers but does not replace a table. The summary says so and does not suggest show as if the sampled rows had been written. A repeated full run can use cached answers. For request timing and tokens, add --verbose.
show
show reads the last materialized table without asking the engine or reading the source file. It names the run ID and warns when the current spec differs from the spec that wrote the table. test and sampled run do not replace that table. The row list shows the source key, answer, confidence and route; --id shows the stored input fields as well. The HTML report below is intended for sharing and excludes input row text.
test
test measures answers against gold and evaluates acceptance checks you wrote under tests:. With no configured bar, it says measured rather than passed:
PASS, WARN, or FAIL with its measured value and limit. If it needs gold that is absent, it appears as NOT ASSESSED; the result cannot be called passing. test exits 1 for a failed check with normal severity. --verbose adds calibration bins, the full threshold dial, baseline comparison, and diagnostic examples. Accuracy estimated from reviewed rows keeps its 95% interval and basis in both modes. See How the numbers work.
The results file
Whentest finishes, it also writes what it printed as JSON, for CI, dashboards and agents (its schema and what may change between versions: Files hunch writes): .hunch/target/<tested path>.json, beside the store, with the path of the tested spec or folder relative to the store’s folder (hunch test examples/tickets/triage.yml writes .hunch/target/examples/tickets/triage.json). With --model, the engine’s suffix is added, as for its tables (triage__deepseek_deepseek_flash.json), so another engine’s results never replace the spec’s own. With --target, its name is added (triage@dev.json), and the file goes in target/ beside the target’s store. test removes the file when it starts, so a run stopped by --max-cost leaves none rather than an old one.
diff
diff compares two versions on the same rows. It leads with changed answers; --verbose adds probability movement, the full gold comparison, and more row examples.
review
See Review for the screen and keys. --list prints one row per item:
- if none), start of the row.
Verdicts saved to <judgment>.reviews.csv (columns qid,row_id,state_hash,verdict,label,reviewer,at,kind):
kind says why the row was reviewed: disputed, audit (a random spot check), uncertain, shadow, or any other name you write when importing verdicts (for example flagged). Only audit rows feed the accuracy estimate; every verdict counts as gold. test also marks a row same_text when it takes its gold from another row with identical text: gold, but not a spot check.