Skip to main content
Start with a decision your software or team already makes. Write the question a careful person would answer for one case. Then choose the rows it applies to, the evidence that person would need, and the answers you can check it against. This page builds a spec in that order. The spec reference lists every key.

The rows

A spec needs one row per thing you judge, and a stable id for each row. hunch uses the id to match answers, reviews and diffs across runs. Here each row is a shell command a coding agent is about to run:
model names the engine that answers. source can also read coding-agent sessions (traces(<glob>), one row per command with view: commands) or call a Python function (py(rows.py:load)).

What the model sees

state lists the columns sent with each question. Include what a careful person needs to decide. Extra columns cost tokens and may distract from the evidence that matters.
command is what runs. request says what the developer asked for, so an expected deletion reads differently from a surprising one. cwd is the working folder; without it, the model cannot tell whether rm -rf build stays inside the project. To remove secrets or shorten long columns before they are sent, see redact and clip in the spec reference.

The question

The model never sees the question’s name. To it, destroys means nothing, while “Would running command delete, overwrite or reset files in a way that would be hard to undo?” means everything. Write instructions as the full question, and refer to the columns by name in backticks. Use criteria to describe the boundary between answers. Two careful people may disagree about “hard to undo”; the criteria make your intended boundary explicit.
Choose the type by what the answer means:
  • noul: a yes/no condition. Its output includes the probability of yes; 0.5 means the model gives yes and no similar weight, not that a command is “somewhat destructive”.
  • choice: exactly one option applies, such as what a command is mainly for: build, test, inspect, install. Add none: <when> for rows that fit no option; without it, the model must pick one of yours, and it will pick one confidently.
  • score: a position on an ordered scale. criteria is a list of levels, each described as a concrete situation.
  • multi: any number of options can apply. hunch asks one yes/no question per option.
Ask one thing per question. “Would it delete something or send it somewhere?” is two questions, destroys and sends_out, and a guard that stops a command if either says yes is a rule in your code, not a question for the model.

How you will know it is right

If your data has an answer key, name its column in gold. Set act, the confidence below which a person should look. Put thresholds under tests, and hunch test fails when accuracy drops below them.
Without an answer key, leave gold out. Review a random sample, then test can estimate accuracy on those reviewed rows. See Review. Put important known cases into the spec as examples. test checks those cases on each run, even if the average looks good:
Passing these examples catches changes to these specific cases. It cannot guarantee the same answer on a new command.

Check it before it costs anything

lint catches mistakes before any request is sent. Here, state lists comand instead of command, and lint also notices that the examples no longer supply every state column:
Then read the request that compile prints for the first row. It is what the model will see for that row. If you could not answer the question from it, add the missing context before running the sample.

Start small

The first version of a question is rarely the best one, and every row asked under a changed question is paid for again. So run a sample first (hunch run command_guard.yml --sample 50 asks about the same 50 rows every time, and leaves the full table alone), review twenty rows, and test before you run everything. Change a spec shows how to compare versions.