All notes

What is a decision model?

A decision model answers a fixed question with one of your options and a probability. That makes it fast and easy to check, if the options are right.

Say you want a program to know whether a coding task is risky. You could ask a chat model, like the one behind Claude Code. It answers in text: a sentence, a paragraph, maybe a list of cases. Your program then has to read that text and work out what it means. What if the model could only answer with one of the words you gave it?

That's what a decision model does: it answers with one of the options you give it, plus a probability.

Part 1, "Who picks the model?", introduced spatz, a proof of concept that recommends a model and an effort level for a coding task. Its command line tool never switches the model itself. Part 6 shows a mod (a plugin that runs inside Claude Code) that can. spatz uses a decision model to understand a task before it recommends anything.

This part explains what a decision model is, why its answers are fast and easy to check, and how one loose description made it rate a simple bug fix as critical.

Text versus a choice

A chat model writes text. The answer can have any length and any words, and you read it like a message from a colleague.

A decision model does not write text. You give it a situation, a question and the possible answers, and it picks from those answers. Jev, the decision model from TypeSafe AI that spatz uses, knows three kinds of questions:

  • Pick one of a fixed set of options, for example the type of a task.
  • Place something on an ordered scale, for example easy, medium or hard.
  • Yes or no.

Every answer comes with a probability, a number between 0 and 1 that says how likely the model thinks an option is. For a yes or no question, Jev doesn't return a plain yes. It returns the probability of yes, and your program decides what to do with it.

TypeSafe calls Jev a "system one model" and describes it as built "to make fast, structured decisions that software can use directly". That's their description, not a measurement, but it names the idea well: the answer is meant for a program, not for a person.

Think of a mail room

Think of a mail room with a wall of pigeonholes. Each hole has a label: "Accounts", "Legal", "Everything else". A clerk reads each letter and puts it into one hole. The clerk doesn't write a reply. They only decide where the letter goes.

A decision model is that clerk. The letter is the task text. The pigeonholes are the options, and the labels are the short descriptions you write for each option.

Two things carry over from the mail room. You can check the clerk's work at a glance, because a letter is in exactly one hole. And the labels steer everything. If one hole is labelled "Anything important", a lot of letters will end up there, and the clerk did nothing wrong.

The analogy stops fitting in one place. A clerk puts the letter into one hole and moves on. The model also tells you how sure it is about every hole, not only the one it picked. A letter that is 0.51 "Legal" and 0.49 "Accounts" looks very different from one that is 0.99 "Legal".

What one answer looks like

Here is one real question from a spike (a short experiment to test an idea, meant to be thrown away). The task was "fix the off-by-one error in the pagination helper". An off-by-one error is a loop or an index that goes one step too far or stops one step too early, and a pagination helper is the code that splits a long list into pages. The task also said that the tests fail.

The question was "Which criticality best describes the changed behavior?" It had four options, each with a description. This is what Jev answered:

OptionDescription in the spikeProbability
noneRoutine internal behavior without business, security, or stored-data impact.0.01
business logicBusiness rules or user-visible functional correctness.0.99
securityAuthentication, permissions, secrets, or vulnerability handling.0
data integrityStored-data correctness, migrations, or protection against data loss.0

The answer is "business logic" with 0.99, plus a probability for each other option. There was no paragraph to read and no "it depends". The same request asked three more questions about the same task, and those answers looked the same way: the task type was a bug fix with probability 1, and the difficulty was easy with probability 1.

Why the answer is fast

spatz asks Jev four questions in one request: the task type, the difficulty, the criticality, and which of the models it was given fits the task best. Over 5 calls in the spike, the median time for that request was 235 ms and the slowest was 255 ms. That includes the trip over the network. Five calls are a small sample, so read these numbers as a first look, not as a benchmark.

One full spatz run took 406 ms. That is the time from starting the program to the printed recommendation, and it included the first download of the model price list. That number comes from a single run.

TypeSafe's own numbers are on its blog (opens in a new tab): a response in 70 to 500 ms end to end, and a price of $0.042 per million input tokens (tokens are the small pieces of text a model counts), with output tokens free. Those are vendor claims. The 235 ms and the 406 ms above were measured for spatz. The vendor numbers were not.

Why the answer is easy to check

Your program knows every possible answer in advance, because you wrote the options. So it can check the result with a plain comparison: is the answer one of my four words? With free text, it would have to search sentences for meaning and handle answers nobody planned for.

TypeSafe goes further and says Jev can't hallucinate strings (make up words that aren't in the options), because its outputs are typed. That is a vendor claim too. In the spike, every answer had the same shape: one option, and a probability for each option.

The probability is useful on its own. spatz uses it for the difficulty: when Jev isn't sure enough which level fits, spatz takes the next harder level, the safer choice.

Easy to check is not the same as right, though. One task and five calls say nothing about how often Jev is right, or whether a 0.9 really means right nine times out of ten. Those questions are still open for spatz.

The descriptions decide the answer

Look at the table again. Was the off-by-one fix business logic? By the description in the spike, yes. A list that shows the wrong items on a page is a user-visible functional error. The model did exactly what the label said, just like the clerk with the "Anything important" hole.

For spatz, that answer matters. A critical task starts with the most expensive model and effort level among the candidates (the pairs spatz may pick from), and a cheaper one has to prove itself with more evidence than elsewhere. With the spike's description, almost every bug fix would count as critical. spatz would then recommend the strongest model for nearly every fix, which is the cannon from the saying that gave spatz its name.

Narrow labels

The fix was to make the descriptions narrower. In spatz, "business logic" now means money, prices, billing, contracts or legal rules. And the description of "none" now says that visible functional errors belong there.

With those descriptions, the same task came back as not critical with probability 0.97, in a single live run. Between the spike and that run, the descriptions changed in two ways: the wording was narrower, and spatz writes its descriptions in German, not English. So the run shows that the descriptions decide the answer, but not which of the two changes did it. The model version was the same in both runs.

Next in this series: Building a model recommender

Update (2026-10-07)

Part 6 still shows the mod that can switch the model, but I've turned it off for now. spatz records outcomes through hooks instead, in Claude Code and in Codex (spatz pull request #101 (opens in a new tab), merged on 2026-10-07). Part 6 explains why.

Back to top