Jev and System One models: fast, typed AI decisions

TypeSafe's Jev, released on 15 September 2026, is worth an engineer's time for an odd reason: it is deliberately worse than the models you use now. It cannot write. It cannot explain itself. It cannot look anything up.
What it does instead is answer bounded questions about a block of data, all at once, in about the time a database needs for a complex join. The company calls this a System One model, after Kahneman's fast, intuitive System 1.
The founder, Diogo Almeida, worked on the instruction-following research behind ChatGPT at OpenAI. He asks: models have been superhuman at chat for years, so where is all the automation?
Key points in 30 seconds
- Jev returns typed answers, not text. You send state and questions. You get a choice, a score or a probability back.
- It is fast and cheap. 70–500ms and $0.042 per million input tokens. Output tokens are free. These are vendor numbers.
- It cannot return an answer outside your schema. It can still be wrong inside it.
- Its confidence is calibrated. In aggregate, higher confidence means higher accuracy. So you can set a threshold per action.
- It does not replace your LLM. Use it to decide which requests need an LLM at all.
- Pilot it in shadow mode first. It is early access, and the evidence is a week old and mostly self-reported.
What does Jev do?
Think of it as a function call with frontier-level understanding. Unstructured state goes in. Typed, probabilistic decisions come out.
response = client.system_one(
state={
"ticket": {"subject": "Duplicate charge",
"messages": [{"from": "customer",
"text": "I was charged twice for order A-104. Please refund."}]},
"order": {"id": "A-104", "charges": [
{"amount_usd": 49, "status": "captured"},
{"amount_usd": 49, "status": "captured"}]},
"refund_policy": "Duplicate charges are eligible for a refund.",
},
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"]),
"refund_requested": Noul(instructions="The customer is explicitly asking for a refund"),
},
)
dept = response.answers["department"]
print(dept.choice, dept.confidence) # "billing" 0.97
print(response.answers["frustration"].score) # 1.035
print(response.answers["refund_requested"].noul) # 0.98
There is no prompt as you know it. There is state (a string, a JSON object or an array of text) and there are questions. Each question declares its own answer space before the model runs. One endpoint, POST https://api.typesafe.ai/v1/systemone, serves all of it.
What are the three question types?
The API has only three question types. TypeSafe says this is the design, not a limit to work around. Tap each one.
Choice
- It asks
- Which one of these options?
- It returns
- .choice, .probabilities for each option, .confidence
- Takes up to 255 options. Each option costs only a few tokens.
- So pass the full list of teams, categories or SKUs, not a short list.
- Add an explicit "other" option, so the model can say nothing fits.
Score
- It asks
- Where on this ordered scale?
- It returns
- .score (a continuous number), .probabilities, .confidence
- Takes two to ten ordered levels, described in words. Level 0 is the first entry.
- The score is continuous. A 1.035 means "just past the second level".
- That lets you set a threshold in code that is finer than the levels.
Noul
- It asks
- Is this statement true?
- It returns
- .noul: one probability from 0 to 1
- Noul is TypeSafe’s word for a probabilistic yes/no.
- It returns a bare number and no confidence field. The number already is the belief.
- It is absolute, so it can be low for every option. A Choice is relative.
The TypeScript SDK infers the result type from your questions. So category.choice is a union of your own option keys, not a plain string.
Why does parallel sampling matter?
This is the core idea. Everything else follows from it.
An autoregressive model writes one token at a time, and each token depends on all the ones before. That is how an LLM can write an essay. It is also why it is slow: token n+1 cannot start until token n exists. Ask an LLM ten questions in one prompt and the tenth answer waits for the first nine.
Jev gives up string generation, and with it the sequential chain. It reads the state once and answers every question in parallel, in a single query. TypeSafe describes a new architecture with a purpose-built parallel sampler that is "incredibly efficient and hardware-aware".
So the rule is: ask everything up front. A new question adds only its own tokens, which are cheap, and almost no time. TypeSafe calls this speculative fan-out. Its cookbook reports that one call with 13 questions about a long article is 12.2x cheaper and 10.0x faster than asking one at a time, with identical answers.
response = client.system_one(
state=ticket,
questions={
"category": Choice(instructions="Broad category of this ticket",
criteria={"bug_report": "Something is broken",
"billing": "Charges, invoices, refunds",
"feature_request": "Asking for new functionality"}),
"bug_severity": Score(instructions="How severe is the issue", # ask anyway, it is nearly free
criteria=["Cosmetic", "Degraded; workaround exists", "Blocking"]),
"has_repro": Noul(instructions="The user describes steps to reproduce"),
"refund_wanted": Noul(instructions="The user explicitly asks for a refund or credit"),
},
)
a = response.answers
if a["category"].choice == "bug_report":
if a["bug_severity"].score > 1.5 and a["has_repro"].noul > 0.6:
escalate_to_engineering(ticket_id, severity="high")
else:
add_to_bug_backlog(ticket_id)
elif a["category"].choice == "billing" and a["refund_wanted"].noul > 0.7:
start_refund_flow(ticket_id)
You are no longer designing a conversation. You are designing a query plan. The branching happens in your code, on data you already have, with no extra round trips.
Size limits. jev-1.13 allows 64k tokens for the state and all questions together, and 32k for the state plus the single longest question.
Does "cannot hallucinate" mean "never wrong"?
No. It is a claim about the output space.
Jev cannot return something outside the answer space you declared. A Choice returns one of your keys. A Score returns a number inside your levels. A Noul returns a number from 0 to 1. It cannot invent an option or break your JSON, because the sampler is limited to that space. It is not just asked politely to stay inside.
TypeSafe is open about this. Schema matching is guaranteed, so its 0% type-error figure "is not empirical": it is a structural property that a single counter-example would disprove. It also flags that its LLM comparison numbers, taken from OpenRouter traffic, carry routing bias.
Why it matters: a bad tool call in an interactive agent is an annoyance a human can fix. The same failure four layers deep in a dependency chain, at three in the morning is an incident. Retry-and-validate loops hide it, but they cost the tail latency you wanted to protect. Removing the failure from the type system is different from making it rarer.
Jev can still be wrong inside the space. For example, it may send a ticket to billing when a person would say technical. That is why the second half of the design exists.
What is calibration, and why does it matter?
Ask a chat model how confident it is and you get a number that sounds like confidence. Models tuned on human preference tend to be overconfident, because assertive text scores better with raters. The cost is high: if a model does a task right 95% of the time but cannot tell you which 5% are wrong, you cannot automate it. You must review everything, and the review cost eats the saving.
Jev is trained with Reinforcement Learning for Calibrated Decisions (RLCD). It tunes probabilities against outcomes, not against preference. The goal is that higher confidence really means higher accuracy across groups of answers.
Two caveats from the docs:
- Calibration is a population property. It does not promise that any single answer is right.
confidenceis derived from the probabilities that the answer already carries. A concentrated distribution gives high confidence. A flat one gives low confidence. You always get the rawprobabilities, so you can compute your own measure.
A flat distribution is a clue. It usually means your options could not be told apart from the state you gave. That is more often a defect in your criteria than confusion in the model.
How do you set a threshold?
Once confidence is trustworthy in aggregate, it becomes control flow. Use one threshold per action, scaled to the cost of being wrong. Do not use one global threshold. Try it below.
1. Pick an action
Moves money. It cannot be undone. Bar to act alone: above 90%.
Ask to confirm
Confidence 75% is above the floor but not above the 90% bar for this action.
action = response.answers["action"]
if action.confidence < 0.5:
route_to_human(user_message) # floor: the model says it does not know
elif action.choice == "check_balance":
show_balance(account_id) # read-only; a wrong screen is recoverable
elif action.choice == "approve_transfer":
if action.confidence > 0.9: # moves money; irreversible
confirm_then_execute(account_id)
else:
ask_user_to_confirm(account_id)
else:
route_to_human(user_message)
Risk tolerance is no longer hidden in a prompt that a non-engineer edited last quarter. It is a number next to the action it guards, in a file with a git history.
Pin the version. Aliases move. jev-latest resolves to jev-1.13.0 today, and answers behind an alias can change without any change on your side. Once thresholds are tuned, pin the version and upgrade on your own schedule.
client = TypeSafeClient(model="jev-1.13.0") # pin, don't drift
How much should you trust the numbers?
Jev (jev-1.13) |
Frontier LLMs | |
|---|---|---|
| End-to-end latency | 70–500ms | 3–329s |
| Input price | $0.042 / MTok | $0.20–$10 / MTok |
| Output price | free | ~5x input |
| Sampling | parallel, single pass | sequential, token by token |
| Structured-output errors | 0% by construction | 0.58%–45.5% (OpenRouter) |
| Rate limits | 250k tokens/sec, 1,200 req/min | varies |
| Context | 64k total; 32k state + longest question | varies |
TypeSafe's headline claims are 193.6x faster and 444.6x cheaper. They come from its own workflow tests. Every model gets the same compute graph and is scored against the average of two frontier models. That method is more honest than most launch benchmarks, because it tests models inside a workflow, not on a leaderboard task. The company also lists the biases itself: the reference answers lean towards the two vendors used as ground truth, and its own capabilities team wrote the workflows.
The right response is neither belief nor dismissal. The numbers are vendor-reported, self-run and not yet independently reproduced. They are a strong reason to run a shadow test on your own traffic. They are no reason to change a production threshold before you do.
Where does Jev break?
TypeSafe publishes a jaggedness page for jev-1.13. It is a list of the model's own failure modes, and it says more about the team than any benchmark. Read it before your design review, not after your incident. Tap each item.
Jev answers the question you wrote, not the one you meant. Scoping words, negations and implied conditions are taken at face value. If you find yourself explaining what you really meant, that explanation is the missing half of your instruction.
Counting, arithmetic and comparing dates are unreliable. Dates are read as text, not as ordered values. Extract parts with a Choice over fixed options (twelve months, thirty-one days) and compare in code.
Questions about colour names work better than questions about hex values. Convert in code, then ask the judgement question.
A property of a property, or a double negative, is measurably worse. Name the relevant part of the state directly.
Accuracy falls as the state fills with material the question does not need. Retrieve and filter first.
Adversarial content written to steer the answer can move it. If you classify text submitted by users, that threat model is yours.
A Noul and a yes/no Choice on the same question return numbers that are not interchangeable. A Noul and its negation do not sum to 1. A Choice is relative (which option wins). A Noul is absolute and can be low for every option. Do not reuse a threshold across the two.
Every item points the same way: keep deterministic work in code, and give the model only the real judgement. That is not a workaround. It is the programming model.
What are four business uses?
1. Support triage as a cascade
The best pattern is not to replace your LLM. It is to decide which requests deserve one. LangChain's write-up frames Jev as part of the agent loop, not a rival to it.
def handle(message):
r = client.system_one(
state=message,
questions={
"intent": Choice(instructions="Primary intent of this message",
criteria={"order_status": "Asking about an existing order",
"product_question": "Asking about a product",
"return_exchange": "Wants to return or exchange",
"complaint": "Unhappy, wants resolution"}),
"complexity": Score(instructions="How complex is this to resolve",
criteria=["Simple lookup or standard procedure",
"Requires judgment or multiple steps",
"Unusual edge case, escalation needed"]),
},
)
intent, complexity = r.answers["intent"], r.answers["complexity"]
if intent.confidence < 0.5:
return route_to_human(message)
if intent.choice == "order_status":
return lookup_order(message) # no model in this path at all
if intent.choice == "product_question":
return handle_with_llm(message, PRODUCT_SPECIALIST)
if intent.choice == "return_exchange":
return handle_with_llm(message, RETURNS_SPECIALIST)
if intent.choice == "complaint":
if complexity.score > 1 or complexity.confidence < 0.5:
return route_to_human(message)
return handle_with_llm(message, COMPLAINT_RESOLUTION)
The business case. One branch never uses a model. Two load narrow specialists, which also improves quality. One escalates honestly instead of guessing. Using TypeSafe's per-case figures, a million tickets through this shape cost roughly $6,480, against $30,400 through a frontier model. Around 800,000 of them are answered in under half a second instead of ten.
The saving is the second-order benefit. The first-order benefit is that escalation is driven by a calibrated number, not a guess. So humans see the tickets that need a human.
2. Retrieve, then judge: documents and claims
Jev knows nothing beyond the state you give it. Combine that with context rot and the lesson is clear: whatever builds the state decides what the model can know. Pad it and accuracy falls. Ground it in a weak source and you get a well-calibrated judgement about bad material.
So use two layers: fetch precisely in code, then judge each item cheaply.
shortlist = []
for doc in retrieve(query, max_results=200): # your search and filters, in code
a = client.system_one(
state={"title": doc.title, "source": doc.url, "content": doc.content},
questions={
"is_relevant": Noul(instructions="This document addresses the question under review"),
"evidence_strength": Score(instructions="How strong is the evidence presented",
criteria=["Anecdotal or indirect", "Circumstantial",
"Direct, single source",
"Direct, corroborated by multiple sources"]),
},
).answers
if a["is_relevant"].noul > 0.7 and a["evidence_strength"].score > 1.5:
shortlist.append((doc, a["evidence_strength"].confidence))
At $0.042/MTok with free output, a relevance filter per item costs less than the context it saves later. For RAG, a Noul per passage is cheaper than the tokens spent sending an irrelevant passage to a frontier model.
The same shape fits insurance claims, KYC document review, contract clause flagging and literature screening. The costly resource is human attention. You are buying a logged, confidence-scored shortlist instead of a pile.
3. Agent guardrails and tool-call gating
Coding harnesses have long had an "is this action dangerous?" check. It mostly lived in the closed part of the harness, because an LLM call per action was too slow and too costly. At 70–500ms with free output, that limit lifts. LangChain already ships middleware on this idea (AutoModeMiddleware in langchain_typesafe). Writing your own gives you the thresholds:
def gate(tool_name: str, args: dict, task_context: str) -> str:
a = client.system_one(
state={"tool": tool_name, "arguments": args, "task": task_context},
questions={
"destructive": Noul(instructions="This call deletes, overwrites or irreversibly modifies data"),
"exfiltrates": Noul(instructions="This call sends data to a destination outside the system"),
"off_task": Noul(instructions="This call is unrelated to the stated task"),
"blast_radius": Score(instructions="How much is affected if this call is wrong",
criteria=["A single scratch file", "One project directory",
"A shared environment or production system"]),
},
).answers
if a["exfiltrates"].noul > 0.5 or a["blast_radius"].score > 1.5:
return "require_human_approval"
if a["destructive"].noul > 0.6 or a["off_task"].noul > 0.7:
return "confirm"
return "allow"
Four independent judgements, one round trip, a fraction of a cent. Note the four separate Nouls instead of one "is this safe?" question. A combined question hides several decisions in one number, and the jaggedness guidance says each question should ask one thing.
One caution from the docs: state is not treated as hostile. A guardrail is exactly where an attacker will aim. Write precise criteria, test edge cases, and treat this as one layer of defence, not a wall.
4. Real-time scoring in the request path
This is the use that did not exist before: AI inside a user-facing request, where a three-second model call was never possible.
Examples: lead scoring at form submission, fraud pre-screening at checkout, content moderation before a post shows, and call routing in a phone menu. The latency budget is a few hundred milliseconds. The old answer was a gradient-boosted model on hand-built features that took a quarter to build and went stale quietly.
Keep the weights in your code:
a = client.system_one(state=lead_payload, questions={
"budget_signal": Score(instructions="How strongly does this indicate real budget",
criteria=["No indication", "Vague interest", "Named budget or timeline",
"Procurement process already underway"]),
"fit": Score(instructions="Fit with a mid-market B2B software buyer",
criteria=["Poor fit", "Adjacent", "Good fit", "Ideal customer profile"]),
"is_spam": Noul(instructions="This submission is spam or automated"),
}).answers
if a["is_spam"].noul > 0.8:
drop(lead)
else:
score = 0.6 * a["budget_signal"].score / 3 + 0.4 * a["fit"].score / 3
route(lead, tier="A" if score > 0.66 else "B" if score > 0.4 else "nurture")
Changing the weights is now a code change with a diff and a test, not a prompt rewrite with unknown effects. You can A/B it and roll it back. Your growth team can read it.
How do you pilot Jev safely?
Follow these steps in order. Tick them off as you go.
Your pilot plan
0 of 6 done
Two honest warnings. Jev is in early access with a waitlist. TypeSafe says rate limits are adjusting while it serves launch demand, which matters for anything headed to production. And all published evidence is a week old and mostly self-reported, including the launch demos. That is not a reason to ignore it. It is a reason to make step 2 longer than you would like.
Why is this more than another model release?
Under the numbers, the argument is about architecture. We have made it to clients for a while: most decisions inside software are System 1 judgements, and we have been renting System 2 to make them.
"Which bucket is this?" "Is this urgent?" "Does this passage matter?" These are not reasoning problems. They went through chat models only because a chat model was the one thing that understood language. The price of that mismatch is paid in latency, retry loops, review queues and AI pilots that worked in the demo and never reached the request path.
Jev is one vendor's early-access bet on this idea, with numbers that need independent checks. The idea looks durable either way: the link between AI and software should be a typed function call with an honest probability attached, not a string you hope will parse.
The name is a clue. Jev is named for William Stanley Jevons, whose paradox says that more efficient coal engines increased coal use instead of cutting it. TypeSafe expects the same for machine intelligence: each tenfold fall in the cost of a decision unlocks far more decisions worth making. If they are right, the question is not what you can make cheaper. It is which decisions you never automated because each one cost a tenth of a cent and three seconds too many.
Frequently asked questions
What is a System One model?
A System One model is an AI model that looks at a state and returns typed answers with calibrated probabilities, instead of writing text. TypeSafe named the class after Daniel Kahneman's System 1, which means fast, intuitive judgement. It is different from the slow, deliberate System 2 reasoning that chat and reasoning models do. Jev is TypeSafe's first System One model, released in early access on 15 September 2026.
How is Jev different from an LLM with structured outputs?
Three things differ. Sampling: an LLM writes tokens one at a time, each depending on the last, while Jev answers every question in a request in parallel, in a single pass. Output: an LLM writes a string that must be parsed and can fail validation, while Jev's answer space is defined in advance, so a schema mismatch is impossible by construction. Training: Jev is trained with Reinforcement Learning for Calibrated Decisions, which tunes its probabilities against real outcomes, so its confidence numbers are meaningful in aggregate.
What can Jev not do?
It cannot write text, code or explanations, and it knows nothing beyond the state you give it. It cannot look anything up. TypeSafe's own jaggedness page for jev-1.13 says it is unreliable at counting, arithmetic, date comparison and numeric forms such as hex colour values. It reads instructions literally, and its accuracy falls when the state holds material the question does not need. It accepts text only: no image, audio or video.
What does Jev cost, and how fast is it?
TypeSafe prices jev-1.13 at $0.042 per million input tokens ($42 per billion), with output tokens free. It reports response times of 70 to 500 milliseconds, against 3 to 329 seconds for frontier models on comparable queries. The headline figures of 193.6x faster and 444.6x cheaper come from the company's own workflow tests. They are vendor-reported, self-run and not yet independently reproduced, so use them as a reason to run your own benchmark, not as a benchmark.
Should Jev replace the LLM in our stack?
No, and TypeSafe does not claim it should. Jev cannot generate anything, so prose, code and customer-facing replies still need a generative model. The useful pattern is a cascade: Jev makes the fast, structured decision (which bucket, how severe, whether to escalate), and a generative model runs only on the branches that need one. The saving comes from the calls you stop making, not from swapping one model for another.
How do we pilot it responsibly?
Pick one high-volume, low-stakes decision that an LLM or a brittle rule makes today. Run Jev alongside it in shadow mode for a week or two, and log both answers plus Jev's confidence. Change no behaviour. This gives you a calibration curve on your own data (accuracy per confidence band), which is the only thing that tells you where to set your automation threshold. Then automate the high-confidence band, route the rest as before, and widen the band as evidence supports it.