Noul, Choice and Score
Every judgment you will ever ask Jev for has to fit one of three shapes. They look interchangeable and they are not: they return different fields, behave differently at the margins, and TypeSafe's own docs publish a worked example where the same question asked two ways disagrees flatly.
By the end you'll be able to
- Choose the right primitive for a given judgment
- Write criteria that don't fight the instructions
- Read probabilities rather than just the summary value
- Avoid the Noul-as-a-spectrum trap
On this page
| Type | Answers | Returns | Limits |
|---|---|---|---|
| Noul | Is this true? | noul (0–1) | no confidence field |
| Choice | Which of these options? | choice, probabilities, confidence | up to 255 options |
| Score | Which level? | score, legend, probabilities, confidence | 2 to 10 levels |
Noul — the probability that something is true#
A Noul is a yes/no question that returns the probability of yes. TypeSafe has never said what the word stands for; treat it as a coined name. instructions is required, criteria is optional and takes a true/false pair when you want to pin down what each side means.
from typesafe_sdk import Noul
questions = {
"refund_requested": Noul(
instructions="Does the customer request a refund?",
),
"policy_covers_it": Noul(
instructions="Does `refund_policy` cover this situation?",
criteria={
"true": "The policy explicitly permits a refund here",
"false": "The policy is silent or excludes this case",
},
),
}Choice — one option from a known set#
A Choice takes a criteria map of {option: description}. The description can be null when the option name speaks for itself. You get back the winning option, the full distribution over every option, and a confidence score.
from typesafe_sdk import Choice
Choice(
instructions="Which team should handle this",
criteria={
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
"sales": "Pricing or account questions",
},
)- 0.85technical
- 0.08billing
- 0.07sales
TypeSafe's guidance is to give the full list rather than a shortlist: options cost only a few tokens each, and the ceiling is 255. Above that cardinality their own sampler runs a two-stage process — score everything independently, then make an explicit pick — which is what causes the occasional slowdown they mention in the Wikiracing demo.
Score — a position along levels you define#
A Score takes an ordered array of level descriptions, low end first, between two and ten of them. The returned score is the probability-weighted position across those levels, so it can land between them: three levels give you a range of 0 to 2, and a score of 1.6 sits between the second and third.
from typesafe_sdk import Score
Score(
instructions="How frustrated the customer appears",
criteria=[
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language",
],
)- 0.050Calm
- 0.301Frustrated
- 0.652Very angry
Picking between them#
TypeSafe's rule of thumb is the useful one: prefer the type whose answer your code can act on directly. A Choice between refund, rebook and information maps onto three branches. A Score maps onto a threshold. A Noul maps onto an if. If two types both seem to fit, the one that needs less translation in your code is the right one.
- Unordered categories — routing, document type, language detection → Choice.
- An ordered spectrum you can describe — severity, frustration, seniority, evidence strength → Score.
- A clean predicate where the probability itself is the signal — does this ask for a refund, does this mention distributed systems → Noul.
The trap: the primitives do not agree with each other#
This is the most important thing on the page, and it is published by TypeSafe rather than discovered by a critic. Ask the same question as a Noul and as a yes/no Choice and you can get answers that point in opposite directions. On the ticket "I'm not happy with the fit. What are my options here?", asked as "Is the customer asking for a refund?":
| Noul `noul` | Choice `yes` | Choice `no` | Choice `confidence` |
|---|---|---|---|
| 0.22 | 0.01 | 0.99 | 0.97 |
And two Nouls that are logical negations of one another do not sum to 1. On "I was charged twice for the same order. Can someone look into this?":
| `refund` | `not_refund` | Sum |
|---|---|---|
| 0.72 | 0.47 | 1.19 |
That difference is usable rather than merely annoying. TypeSafe's skill-suggestion cookbook uses both on the same shortlist: a Choice to pick which skill, and Nouls to decide whether any skill should be suggested at all. Those are genuinely different questions, and the two primitives are how you ask them.
Mix them freely in one request#
Every question in a request sees the same state, is evaluated independently and in parallel, and returns under the key you chose. There is no reason to send them separately.
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient()
response = client.system_one(
state=ticket,
questions={
"department": Choice(
instructions="Which team should handle this",
criteria={
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
"sales": "Pricing or account questions",
},
),
"frustration": Score(
instructions="How frustrated the customer appears",
criteria=[
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language",
],
),
"is_urgent": Noul(
instructions="The message conveys urgency or time-sensitivity",
),
},
)
print(response.answers["department"].choice) # "technical"
print(response.answers["frustration"].score) # 1.035
print(response.answers["is_urgent"].noul) # 0.999Next#
The questions are only half the request. The other half is state, and how you shape it has more effect on accuracy than almost anything else. Continue to Designing state Jev can actually use.
Sources for this page
- TypeSafe — Primitives
- TypeSafe — Choice
- TypeSafe — Score
- TypeSafe — Noul
- TypeSafe — Advanced: structure
- TypeSafe — jev-1.13 jaggedness
- TypeSafe — HTTP API reference
Last reviewed 2026-09-18. Jev is days old and moving — where a claim is TypeSafe's own rather than independently verified, this page says so in the sentence that carries it.