What Are the TypeSafe Patterns in 2026?
TypeSafe documents four architectural patterns for building systems around its primitives: speculative fan-out, confidence-gated routing, composite scoring, and intent routing. Each one is a way of composing typed answers in code, and the company frames the underlying skill plainly: learning to think in terms of discrete, atomic decisions that compose into complex system behaviour is what gets the most out of the model.
| Pattern | What it does | Benefits TypeSafe claims |
|---|---|---|
| Speculative fan-out | Send many questions in a single call, including speculative ones, and let your code decide what is relevant | Cost, speed |
| Confidence-gated routing | Use confidence as a second decision axis to build safer systems | Reliability, safety |
| Composite scoring | Combine several dimensions of analysis into a single score | Cost, reliability, speed |
| Intent routing | Classify a user's intent and route to the appropriate handler | Cost, speed |
Explain It Like I Am Five: The Airport Desk
Picture the person at the front of an airport who sorts everyone out before they go anywhere.
You walk up. They ask you several quick things at once: where are you flying, do you have bags, is this a connection, do you need help getting to the gate. It takes about four seconds, because they ask all of it in one go rather than sending you round the corner and back for each question.
Some of what they ask will turn out not to matter. They ask about bags even if you have none. That is fine. Asking is quicker than working out whether asking was worth it. That is speculative fan-out.
Then they point. Bag drop, security, or the special assistance desk. That is intent routing.
If they cannot work out what you need, they do not guess and send you somewhere random. They wave over a supervisor. That is confidence-gated routing.
And if the airline needs to decide who gets the last upgrade, they do not ask one big question. They take a few small scores, frequent flyer level, fare type, how full the cabin is, and add them up with their own rules. That is composite scoring.
Four patterns. Ask everything at once, point people the right way, call a supervisor when unsure, and add small numbers together with rules you wrote.
How Does Speculative Fan-Out Work in 2026?
Put every question your system might need into one request and use code to decide what is relevant afterwards. All questions are evaluated in parallel, so adding more usually has little effect on response time, and each extra question only costs its own tokens.
TypeSafe's worked example is support ticket triage. A ticket needs a category, and if it is a bug report it also needs a severity. Rather than asking for the category first and the severity in a follow-up, you ask for both at once and ignore the severity if the ticket turns out not to be a bug. The documented request carries five questions: a Choice for the category, a Score for bug severity, Nouls for reproducible steps and for a refund request, and a Score for frustration.
category = response.answers["category"]
bug_severity = response.answers["bug_severity"]
bug_repro = response.answers["has_reproducible_steps"]
refund = response.answers["refund_requested"]
frustration = response.answers["frustration"]
if category.choice == "bug_report":
if bug_severity.score > 1.5 and bug_repro.noul > 0.6:
escalate_to_engineering(ticket_id, severity="high")
else:
add_to_bug_backlog(ticket_id)
elif category.choice == "billing":
if refund.noul > 0.7:
route_to_billing_with_flag(ticket_id, refund_likely=True)
else:
route_to_billing(ticket_id)
elif category.choice == "feature_request":
log_feature_request(ticket_id)
# Frustration is useful regardless of category
if frustration.score > 1.5:
flag_for_priority_response(ticket_id)
Everything needed for the full decision tree comes from one call. Two of those five questions are speculative: bug severity and reproducible steps only matter for a bug report, and the refund question only matters for billing. When they are irrelevant, the code ignores them. When they are relevant, you have saved a round trip.
The economics are measured rather than asserted. TypeSafe's parallel questions cookbook ran a 13-question regulatory briefing over the GDPR Wikipedia article and reported one batched call at 0.000497 US dollars and 0.27 seconds against 13 separate calls at 0.006090 US dollars and 2.71 seconds, making batching 12.2 times cheaper and 10.0 times faster with no change in answers. The reason is simply that the separate calls re-send the article 13 times.
How Does Intent Routing Work in 2026?
Classify the incoming request first, then send it to the right handler: deterministic code, a specialist model, or a person. TypeSafe positions this as putting a fast, cheap classifier in front of everything else rather than sending every message through an expensive model just to work out what kind of request it is.
The documented example is customer service routing, and it asks two questions: a Choice for intent across order status, product question, return or exchange, and complaint, plus a Score for complexity.
def route_ticket(ticket_id, response):
intent = response.answers["intent"]
complexity = response.answers["complexity"]
if intent.confidence < 0.5:
# Not enough confidence to classify: route to a human agent
return route_to_human_agent(ticket_id)
if intent.choice == "order_status":
handle_order_status(ticket_id)
elif intent.choice == "product_question":
handle_with_llm(ticket_id, PRODUCT_SPECIALIST)
elif intent.choice == "return_exchange":
handle_with_llm(ticket_id, RETURNS_SPECIALIST)
elif intent.choice == "complaint":
low_confidence = complexity.confidence < 0.5
if complexity.score > 1 or low_confidence:
# Too complex for safe automation, or unsure about complexity
route_to_human_agent(ticket_id)
else:
handle_with_llm(ticket_id, COMPLAINT_RESOLUTION)
Look at where each branch goes. One intent reaches deterministic code with no model involved at all. Two reach different specialist models loaded with different context. One uses a complexity score to choose between a model and a person. The classification is a single quick call, and the expensive resources only get invoked for the requests that genuinely need them.
The detail most people miss is the second confidence check. The code does not only gate on intent confidence; it also escalates when the complexity answer itself is uncertain. TypeSafe's note is that it is always important to consider what a low confidence score means in the context of the system and the stakes of the decision.
How Does Confidence-Gated Routing Work in 2026?
Treat confidence as a second axis. The answer tells you what; confidence tells you whether to act on it. TypeSafe's example is a voice banking interface, chosen because the available actions have obviously different consequences, and one Choice question feeds several different thresholds.
action = response.answers["intent"]
if action.confidence < 0.6:
route_to_support_agent(account_id)
elif action.choice == "check_balance":
# Low stakes. 0.6 confidence is sufficient.
show_balance(account_id)
elif action.choice == "approve_transfer":
if action.confidence > 0.85:
approve_transfer(account_id)
else:
ask_user_to_confirm("Just to confirm: you would like to approve this transfer?")
else:
route_to_support_agent(account_id)
The 0.6 floor catches anything genuinely uncertain. Checking a balance clears at 0.6 because the worst case is a customer hearing their balance needlessly. Approving a transfer needs above 0.85, and anything in between triggers a confirmation rather than an action or a refusal. The risk tolerance is encoded in your code, where it can be reviewed, rather than in a prompt.
Our confidence and calibration guide covers how to pick those numbers from your own labelled data rather than by feel.
How Does Composite Scoring Work in 2026?
Break a complex judgment into independent dimensions, score each one separately, and combine them with weights you control in code. TypeSafe's worked example is resume screening, asking four Score questions in one request: Python depth, team leadership, system design, and generalist breadth, each on a five-level rubric.
py = response.answers["python_depth"].score / 4
lead = response.answers["team_leadership"].score / 4
arch = response.answers["system_design"].score / 4
general = response.answers["generalist"].score / 4
# Senior IC
ic_score = (0.40 * py) + (0.10 * lead) + (0.40 * arch) + (0.10 * general)
# Engineering Manager
em_score = (0.15 * py) + (0.40 * lead) + (0.20 * arch) + (0.25 * general)
Each score is normalised to 0 to 1 by dividing by the top level number, then weighted. One set of model answers produces two different rankings for two different roles, because the weights differ and the weights are yours. TypeSafe's stated benefit is visibility: you can see exactly how the final number is made, and when the top-ranked candidates do not match expectations you adjust the weights rather than rewriting a prompt.
The same shape appears in the Score documentation for ticket priority, combining severity, frustration and report quality at 0.6, 0.3 and 0.1 with a comment explaining that a detailed report helps an engineer investigate, so it raises priority slightly. That comment is the point of the pattern: the reasoning is in the code, in words a colleague can argue with.
Ask "rate this candidate out of 10" and you get one number whose internal reasoning you cannot inspect, adjust, or explain to a hiring manager. Ask four dimensions and weight them, and every part of the result is visible, tunable, and separately testable. TypeSafe makes the same argument about startup pitches: ask about market size, technical feasibility and differentiation separately, then combine with your own formula.
How Do the Patterns Combine in a Real System?
They stack, and in most production systems you will use three of the four in a single request. The fan-out is how you get the answers cheaply, intent routing is what you do with the categorical ones, composite scoring is what you do with the ordinal ones, and confidence gating sits over all of it deciding when code acts alone.
| Stage | Pattern | What happens |
|---|---|---|
| 1. One request | Speculative fan-out | Every question the workflow might need, including ones that only matter for some inputs |
| 2. Safety check | Confidence-gated routing | Anything below the floor goes to a person before any branch runs |
| 3. Branch | Intent routing | Categorical answers select the handler: code, a specialist model, or a human |
| 4. Prioritise | Composite scoring | Ordinal answers combine with your weights into a rank or a priority |
| 5. Act | Confidence-gated routing again | Each action clears its own threshold, higher for irreversible operations |
What Is the Design Process TypeSafe Recommends?
Its build guide sets out an ordered workflow, and the order matters as much as the content. The summary line is that you build a normal software workflow and insert System One only where AI is needed.
- Use code when you can. Keep deterministic work in code because it is reliable and cheap, and avoid agent while loops when a software workflow expresses the same behaviour.
- Decompose the input state. Include only the context relevant to the current questions, and do not rely on knowledge stored in model weights when current information can come from your own knowledge base.
- Use structure in the input state. Nested JSON, with questions pointing at specific values by backticked path when that removes ambiguity.
- Decompose the questions. Ask the most explicit, narrow, specific, atomic questions you can, breaking complex judgments into separate questions that each evaluate one property.
- Use structure in the questions. Keep them short; add object or array structure when a question needs supporting data or several kinds of guidance.
- Ask a lot of questions. Many narrow independent questions about the same state in one request, which is how you maximise intelligence per dollar.
- Combine outputs in code. Deterministic rules, weighted sums, or the probabilities as features in a downstream classical machine learning model.
- Route on uncertainty. Different actions for confident and unconfident answers, with thresholds tested by plotting confidence against accuracy on your data.
What Are the Common Pattern Mistakes in 2026?
- Making one call per question. The pattern the other three are built on is batching. Everything else assumes it.
- Gating everything at one confidence number. A read-only action and an irreversible one should not share a threshold.
- Ignoring the second-place probability. A runner-up with meaningful share is often worth acting on, such as copying a second team.
- Hiding the weights in a prompt. The entire benefit of composite scoring is that the weights are readable code.
- Routing everything to a model. In the documented routing example one branch touches no model at all, and that is the cheapest branch you have.
- Only gating the headline answer. The documented example also checks the confidence of the complexity score before trusting it.
- Treating the escalation path as a dead end. If uncertain cases land somewhere nobody looks, the safety design is decorative.
Key Takeaways for 2026
- Four documented patterns: speculative fan-out, confidence-gated routing, composite scoring, and intent routing.
- Fan-out is the foundation. One request, every question you might need, and code decides what is relevant. Measured at 12.2 times cheaper and 10.0 times faster than separate calls in TypeSafe's own cookbook.
- Intent routing puts a cheap classifier in front of expensive handlers, including branches that use no model at all.
- Confidence gating makes the threshold match the stakes, with a floor for genuine uncertainty and a higher bar for irreversible actions.
- Composite scoring splits a judgment into dimensions and combines them with weights that live in reviewable code.
- In production you will usually use three of the four in one request.
- TypeSafe's design order is code first, then a filtered state, then atomic questions, then composition, then uncertainty routing.
Distk designs these flows with teams, including the part that decides which branches need no model at all, which is usually where the cost savings actually come from.