Skip to main content
A folder of specs is a project. A spec can read another spec’s output with ref(...), and hunch runs them in dependency order, like models in dbt. Every command takes a folder as well as a single file. A project fits when a question only makes sense for some rows (“check the fix only where the agent claims one”), or when a hard question is easier as a sequence of smaller ones (“which area?”, then “which intent within that area?”).

Example: a two-step classifier

prototype/examples/banking77_tree/ classifies bank messages into 77 intents in two steps: one of 10 areas first, then an intent within that area, asked only of the rows routed there. The 12 specs are generated by build.py and committed as YAML. The root reads the file:
group.yml
Each specialist reads the root’s answers and keeps only its own rows:
intent_card_payments.yml
A union puts the branches back into one table, so the tree can be tested and diffed as one 77-way classifier:
intent_tree.yml

Keys

Without chain, where is only a filter and confidence is the judgment’s own. In this example chained confidence separated right from wrong answers better than the specialists’ own confidence (AUROC 0.897 against 0.796).

Errors caught before anything runs

  • A cycle names the loop: cycle: a → b → a.
  • A ref(...) to a judgment that does not exist.
  • A column used in where or state that does not reach the spec (lint follows columns through the graph).
  • Union branches whose where clauses overlap.

Commands on a project

compile estimates each judgment’s cost without asking anything. A downstream judgment’s row count depends on upstream answers that may not exist yet. If none are cached, it assumes every row passes where and says so:
If some are cached, it uses their pass rate to estimate the rest, and the total line shows both: # total: ~$0.00474 upper bound, ~$0.00385 expected. --max-cost (or HUNCH_MAX_COST) caps what each set of asks is charged: a judgment’s missing answers, and separately its escalations and test’s order check. One whose estimate is above it asks nothing. Estimates can run low (dense text such as shell commands has more tokens per character), so the cap is also kept while asking: a request goes out only if its worst case still fits, and a judgment that reaches the cap stops, with the answers it got saved. --node <judgment> narrows a command:

What the tree example found

On BANKING77 the tree was 48% cheaper and 8 points less accurate than the flat spec, mostly from messages routed to the wrong area. See Route banking intents.