Here is a support ticket:
Hi, I've been trying to connect my Stripe account for 3 days and the integration keeps failing. I'm losing sales. Please help ASAP.
Three questions about it. Which team should get it, how frustrated is this customer, is it urgent. Ask a language model and it will think out loud for a few thousand tokens, then hand you prose you have to parse. Ask Jev and you get technical at 0.85, a frustration score of 1.0, urgency 1.0 — in one round trip, in under half a second, for sixteen millionths of a dollar.
The model that did that cannot write a sentence. Not "is bad at writing" — cannot. That is the product.
TypeSafe AI came out of stealth on 15 September 2026 with $40M led by DCVC. The founder, Diogo Almeida, co-invented RLHF at OpenAI — the technique that turned language models into chatbots in the first place. So the person who helped build the chat paradigm spent two years building the argument against it.
I read the docs, the independent evals, and I checked their maths. This post is not a review. It is the question I actually care about: where does a model like this go in a system that already has an LLM in it? Six answers, below. But first, thirty seconds on the shape of the thing.
Prefer video? Watch the nine-minute walkthrough here, or open it on YouTube.
The contract
You send one state — text, or a JSON object — and a map of typed questions. Every question is evaluated against that state in parallel, and you get back typed answers with a full probability distribution over the answer space you defined.
Three question types, and that is the entire API surface:
- Noul — a yes/no statement. Returns one number from 0 to 1: the probability it is true. The name is coined; it is not
null, and it does not return true or false. It returns how true. - Choice — pick one of up to 255 options. Returns the winner, a probability for every option, and a confidence number.
- Score — rate against a rubric of 2–10 levels described in words, not numbers. Returns a probability-weighted value that can land between levels.
r = client.system_one(state=ticket, questions={
"department": Choice(instructions="Which team should handle this?",
criteria={"billing": "...", "technical": "...", "sales": "..."}),
"frustration": Score(instructions="How frustrated is the customer?",
criteria=["Calm", "Frustrated but civil", "Very angry"]),
"is_urgent": Noul(instructions="The message conveys urgency"),
})
r.answers["department"].choice # "technical"
r.answers["frustration"].score # 1.0
r.answers["is_urgent"].noul # 1.0
Nothing to parse, because nothing was generated. There is no decode loop — the model reads the state once and scores every question in a single pass, which is where the 70–500 ms comes from. Output tokens are free; input is $0.042 per million. That request was 392 tokens.
Two consequences worth holding on to, because every pattern below rests on them. Marginal questions are nearly free — you pay for the state once, so asking thirteen questions costs barely more than asking one. And every answer carries calibrated uncertainty, which gives your code a second axis: the answer says what, confidence says whether to act.
The number your code actually branches on
Every article about Jev mentions that it returns a confidence score, then moves on. Let's not, because this is the number you will threshold.
Confidence is not a second thing the model predicts. It is a statistic computed from the probability distribution you already received. TypeSafe ships an interactive explainer on their confidence page, and the formula is sitting in that page's source:
def confidence(probabilities: list[float]) -> float:
n, p_max = len(probabilities), max(probabilities)
return max(0.0, min(1.0, (n * p_max - 1) / (n - 1)))
I ran it against all four worked examples published in their own quick start and API reference:
| Probabilities | Formula | Published |
|---|---|---|
| 0.85 / 0.15 / 0.00 | 0.775 | 0.78 |
| 0.00 / 1.00 / 0.00 | 1.000 | 1.00 |
| 0.88 / 0.12 / 0.00 | 0.820 | 0.81 |
| 0.00 / 0.95 / 0.05 | 0.925 | 0.92 |
All four land within 0.01, and the gaps are rounding in the published probabilities. So now you know exactly what the number is. Two things follow that are not in the docs as advice:
It only sees the peak. [0.6, 0.4, 0.0] and [0.6, 0.2, 0.2] return identical confidence. In a router those are completely different situations — one has a close rival, the other is diffuse doubt. If the runner-up matters, compute your own margin from probabilities; TypeSafe hands you the full distribution precisely because their statistic is a convenience, not the truth.
A threshold does not transfer between questions. Confidence is normalised for option count, so confidence > 0.8 needs a peak near 0.87 on a three-way choice and near 0.80 on a forty-way one. Same constant, different operating point. Reusing tuned constants across routers of different width is a silent bug.
And Noul has no confidence field at all — the number is the answer and the uncertainty at once. Never share threshold constants between a Noul and a Choice.
Six places to put it
Jev does not replace the model you run. It goes in front of it, beside it, or after it. Each pattern below is one POST /v1/systemone whose answers your code branches on.
1. A router in front of your LLM
The one most people will ship first. Every inbound message hits Jev with two questions — what is the intent, how complex is it — and your code routes on the answers.
The interesting branch is the last one. A router that cannot say "I am not sure" is a router that guesses, and a guess in a support queue becomes a misrouted ticket nobody notices for two days. Confidence gives you that branch for free:
intent = r.answers["intent"]
if intent.confidence < 0.6:
route_to_human(message) # genuinely uncertain — don't guess
elif intent.choice == "order_status":
return lookup_order(message) # deterministic, no model
elif intent.choice == "product_question":
return small_model(message)
else:
return reasoning_model(message)
At ~400 tokens the router costs less than a thousandth of the reasoning call it saves, and it answers before the big model has finished prefill. Two gotchas: the intent set needs an other option, and the floor is tuned to your traffic mix — both covered further down.
2. A relevance filter between retrieval and the answer
Your search returns thirty passages. Today all thirty go into the prompt, which is slow, expensive, and hands the answering model twenty-five distractions.
One request scores all thirty in parallel — the query and the passages go in the state, and each question points at passages[i] by backtick path. Code keeps the ones above the line. The measured delta is the whole argument: the retriever did not change and the answering model did not change, and top-1 accuracy more than tripled.
One caution: this is filtering, not ranking. Do not sort by probability — see the failure list below. Threshold, then keep the retriever's own order.
3. Guardrails on both sides
A guard has to be faster than the thing it guards, or you have doubled your latency for safety theatre. Two Jev calls at ~100 ms each sit comfortably around an LLM call measured in seconds.
On the way in: is this an injection attempt, is it in scope, is it asking for something we do not do. On the way out: does the answer leak personal data, does it stay on topic, does it contradict the source. The model in the middle never changes, which is what makes this cheap to adopt — you are not touching the thing that already works.
Caveat worth being honest about: Jev does not treat state as hostile by default. The injection Noul is a first line, not the only one. Keep a deterministic check behind it.
4. Verifying the LLM's own extraction
A cheap model extracts an invoice — vendor, date, total, currency. It is usually right, and you cannot tell which times it is not.
Jev gets the source document and one Noul per field: is fields.total supported by document? Fields that come back confident are committed. Fields that do not go back to the expensive model — and only those. The big model sees four fields a month instead of four fields a minute.
Note what Jev is doing here: selecting and verifying, never extracting. The candidate values must already exist. Asking Jev to produce the value is the one thing it is guaranteed to be bad at.
5. Tool and skill selection in front of an agent
This is the honest version of the "Jev + Claude Code" claim doing the rounds. TypeSafe wrote a docs page specifically to say Jev is not a drop-in for the model behind your coding agent. There is no model: "jev-latest" setting that makes Cursor a Jev agent. What you can do is put it in front.
An agent with 182 tools burns real tokens deciding which to load. Hand the task and the catalogue to Jev: a Choice ranks the candidates, and a Noul answers the question a Choice structurally cannot — should we suggest anything at all? A Choice is relative and always picks something; the Noul is what lets you pick nothing.
r = client.system_one(
state={"task": task, "catalogue": skill_names},
questions={
"skill": Choice(instructions="Which skill fits `task`?", criteria=skills),
"any_fit": Noul(instructions="Does any skill in `catalogue` fit `task`?"),
},
)
if r.answers["any_fit"].noul > 0.6 and r.answers["skill"].confidence > 0.5:
agent.load(r.answers["skill"].choice)
Two requests in TypeSafe's own cookbook, well under a second, and the agent loads one skill instead of reading 182 descriptions.
6. Screening at volume
A hundred thousand rows a day — leads, sign-ups, transactions, tickets — and a fixed business question about each.
Do not ask one question per row. Ask thirteen in one request, including the ones you will throw away, because you pay for the row once and the questions run in parallel. Then gate on confidence, per action — and note that the thresholds should differ by blast radius, not by system. Showing a wrong dashboard label is recoverable; auto-refunding a transaction is not.
At 400 tokens a row, a million decisions costs about $17. That number, not the "400× cheaper than a frontier model" headline, is what changes an architecture. A semantic check inside a for loop over 100,000 rows stops being a budget decision and becomes an engineering one.
There is an operational reason to fan out too. The published limits are 250,000 tokens/sec and 1,200 requests/min, and they cross at 12,500 tokens per request. Almost every classification workload sits well under that, so the request cap binds long before the token cap — batching ten questions into one request multiplies your effective throughput by ten and costs nothing.
Where it breaks
TypeSafe publishes a page called jaggedness listing nine failure modes in their own model. Shipping that on launch day is the most credible thing on their site. The ones that will actually bite you:
It reads literally. Negations and scoping words are taken at face value. When you catch yourself explaining what you meant by a question, that explanation is the missing half of the instruction.
It cannot count and it cannot compare dates. Dates are read as text, not ordered quantities. Extract the parts as Choices over closed sets, then assemble and compare in code.
Probabilities are not a ranking. An independent benchmark found heavy ties — 53 of 360 rows at 0.99 — and answers that changed when the batch size changed. Filter with them; do not sort with them.
A forced Choice always returns something. This is the one I would tattoo on a wall. An audit gave Jev an "unknown" option on 300 ambiguous items and it picked unknown 95% of the time — exactly right. Remove that option and accuracy on the same items fell to zero, with 79% selecting the dataset's stereotype. Every Choice in production needs an escape hatch, and your code needs a branch for it.
Thresholds are tuned to a population. A routing study auto-routed 84.75% of queries inside a 5% misroute bound, then missed that bound by 3.6× when out-of-scope traffic rose. Monitor your escalation rate: it is your review cost and your drift alarm in one number.
And one structural trap that is not about failure at all, from TypeSafe's own docs. Ask is the customer asking for a refund? about the ticket "I'm not happy with the fit. What are my options here?" — as a Noul it returns 0.22; as a Choice over yes/no it returns 0.01 for yes, at 97% confidence. Identical English, different questions: a Choice is relative (which option wins), a Noul is absolute (is this true on its own terms). Never carry a threshold tuned on one across to the other.
So is it a new paradigm?
Reading class probabilities off a model in one forward pass is old. Zero-shot classifiers have done constrained-label scoring for years, and an open reproduction of the interface appeared within about a week of launch, reading option logits off a frozen 4B model on consumer hardware with no training at all.
What has not been reproduced is the calibration curve — and with no paper, no weights, and benchmarks written in-house, that claim is currently unverifiable. Which is exactly why the only benchmark that matters is yours: take 300–500 labelled examples from your real distribution, log the full probabilities rather than the winning label, and plot accuracy per confidence decile. If accuracy does not rise monotonically with confidence, do not gate on confidence. That eval costs about one cent. There is no excuse for shipping this on vibes.
My read: the primitive is old, the API is the product, and it is a genuinely good one — three primitives, parallel questions, the full distribution handed back, and a published list of its own failure modes. That is a better structured-output story than most frontier labs ship.
Put it where the question is fixed and the volume is the problem. Keep arithmetic, dates, ranking and generation somewhere else. Whether the winner ends up being a $42-per-billion-tokens API or a small model on your own box is genuinely open — but branching on a judgement should be as cheap and boring as branching on a bit, and that idea is right either way.