IT-RAT the stack/typryx Live demo Guides Console
typed answers · optional add-on

Typryx. A typed answer with a probability, never a guess.

Agents already ask each other, and their models, questions that have exactly one shape: choice (which option), score (how good, on an ordered scale) or yes/no. Typryx takes a question from a versioned template and returns a typed answer read off a probability distribution, or refuses with a named reason instead of inventing one. Only the fields the template names ever leave the box, and every answer, refusal or timeout lands on a hash-chained journal.

releasev0.1.0 · Go 1.27
tests806 tests · httptest fakes, no live calls
depsone direct dependency
spend cap1,000 calls an hour, by default
image16.6 MB · ghcr.io, signed
licenceApache-2.0 · public on GitHub
a measured replay

Every real judgement from one run, replayed in the same order.

Not an illustration: these are the 60 real arithmetic judgements from the calibration table below, qwen2.5:7b run locally on Ollama, wording v2, in the order they were asked (the real run took 9.44 seconds; this replay plays it about 2× slower). Watch the resolved probability, the verdict, and how often "confident" and "right" turn out to be different things.

under the hood

The path of one ask.

An agent reaches typryx over MCP, most often through tokenfuse's broker, both measured. Inside, a call crosses the door, the template lookup, the egress filter and the hourly cap before it reaches a swappable backend; the answer is read off the probability distribution, never taken as the backend's own claim. Everything is journaled. On the right: the calibration loop that scores a later truth, and the consumers, all still planned, that would read the journal.

agent, over MCP measured: Claude Code 2.1.270 tokenfuse MCP broker measured: named upstream, tool_call recorded typryx door template egress filter hourly cap only the fields a template names ever leave 1,000 calls/hour by default, counted past door + template + filter backend, swappable stub openai-logprobs jev answer read from the distribution, never the backend’s claim typed answer + probability or: unanswered, with a reason · wire omits both fields journal + ledger 4 event types · sha-384 of what left the box never the state itself the calibration loop a later truth POST /v1/outcome typryx calibration calibration_drift a bound crossed, per template × version × backend × model planned, none of these consume typryx yet verdryx: a typed grader beside the LLM judge wardryx: a signal that may become a hold, never a deny tokenfuse: router shadow mode costcrew: a suggested class/priority at triage genaryx: a panel, live only when configured engram: an optional importance score journal readers Trailryx, Idryx, Genaryx: launcher wiring planned
every named exit

Where can an ask stop, and what does it leave behind?

Six shapes, exact codes from internal/service/service.go and internal/api/api.go. Pick one.

one ask, five gates answered
door template egress filter hourly cap backend key -> agent:// versioned registry named fields, size cap 1,000 an hour under a timeout 401 404 400 / 413 429 200, unanswered
HTTP 200 answered on the wire

the core of this page

Where Jev meets the stack.

Three question shapes are the whole contract: choice, score, noul (yes/no). A template goes to any backend unchanged, because the templates are the contract and the backend is swappable. Switch the backend and watch what is sent and what comes back change; the typed-answer shape at the far right never does.

one template, three backends stub
eval.outcome_met type: noul fields: task, final_answer used in the calibration run typryx door · template · filter hourly cap same gates for every backend only task + final_answer ever reach the backend below sent → nothing leaves the process stub comes back → typed answer answer, probability or unanswered + reason same shape for all three measured

templatetypeoptionswho would ask itstatus
eval.outcome_metnoul (yes/no)n/aVerdryx's grading; the calibration run below used itplanned
eval.answer_qualityscore4 ordered levelsVerdryx graderplanned
request.complexitychoicecheap / default / hard / reasoningTokenFuse router, shadow mode onlyplanned, shadow only
what leaves the box

Toggle the extra fields. The egress never changes.

Only task and final_answer are in the template's fields, so they are the only two that ever reach the backend, whatever else sits in the state. The type a backend receives is constructible only inside the template package, so a map or raw state cannot reach one even by an implementation mistake.

state, up to 5 fields task final_answer user_email customer_iban api_token egress filter template.Egress, 2 out, always task final_answer → backend, and only there held back, counted held_back_fields: 0 toggle a field on above to hold it back sha-384 of the egress: unchanged the hash covers what LEFT the box, so extra held-back state never moves it

Measured on a live run: a five-field state carrying user_email and, separately, customer_iban, neither ever reached the backend or the record. Through Claude Code over MCP, an extra api_token field never reached the record either (held_back_fields: 1).

Never invents an answer

A backend error, a timeout, missing or malformed probabilities, a cap hit: the answer is unanswered with a named reason, and the wire shape omits answer and probabilities entirely. No renormalizing, no fallback guess.

The served answer is always read back off the probability distribution itself: the argmax for a choice, the level for a score, probabilities["true"] for a yes-or-no, never from a claim the backend states alongside a disagreeing distribution.

decision speed, measured 2026-09-25

The one-token shortcut is not always faster.

Same 60 items, seed 1, timed end to end from the caller (go run ./examples/speed, typryx f4045e0, one run each, so read the medians as indicative rather than final).

median, with a p95 whisker gpt-4.1-miniPI
way of decidingmodelmedianp95accuracy
typed, one token, through typryxgpt-4.1-mini538 ms795 ms71.7%
text judge, short verdictgpt-4.1-mini723 ms1,012 ms100%
reasoning judgegpt-5.4-mini (current, reasoning)562 ms896 ms100%
typed, one token, through typryxqwen2.5:7b148 ms159 ms66.7% (3 of 60 unparsed, counted wrong)
text judge, short verdictqwen2.5:7b1,509 ms2,103 ms100%
typed, through typryxJevnot measuredbuilt, not run live

Against a gpt-4.1-miniPI the network dominates: on gpt-4.1-mini the shortcut was about 1.3× faster than a short text verdict and gave up about a third of the accuracy, and gpt-5.4-mini, a current small reasoning model, was right on all 60 in about the same time as the shortcut. Locally, on qwen2.5:7b, the shortcut is about 10× faster. A typed decision earns its place by the probability it carries and where it runs, not by speed; vendor speed claims are not on this page.

calibration, measured 2026-09-25

Stated confidence and actual accuracy are not the same number.

Eight groups, 480 judgements, never pooled: typryx calibration --min-n 30 --json over durable ledgers, 60 arithmetic judgements per group, seed 1, template eval.outcome_met, backend openai-logprobs, half the items right and half wrong. Five models: three OpenAI models of the previous generation over the gpt-4.1-miniPI (gpt-4.1-mini, gpt-4o-mini, gpt-4.1-nano, each with two template wordings) and two open-weight Qwen 2.5 models run locally on Ollama (3B and 7B). Every group was 96% to 100% confident on average and right 50% to 73% of the time. Click or focus a dot for its numbers.

reliability, 8 groups all
pick a dot for its numbers

Every group was 96% to 100% confident on average, right 50% to 73% of the time, and the errors do not lean one way: three groups (gpt-4.1-nano in both wordings, and qwen2.5:3b) said "correct" to every one of 60 items, right exactly half the time, the base rate. gpt-4.1-mini mostly passed a wrong answer as right; gpt-4o-mini erred both ways; qwen2.5:7b never passed a wrong answer but failed a third of the right ones. Rewording (v1 to v2) barely moved accuracy, because a one-token judge has no room to work anything out before answering: it suits classification, not verification. OpenAI's current models, gpt-5.x and gpt-6, refuse token probabilities outright (probed 2026-09-25: "'logprobs' is not supported with this model"), so this backend reaches only earlier hosted models and open models.

modelwordingnstatedaccuracyECEBrierrightlenientstrict
gpt-4.1-miniv1600.9900.7330.2670.52544151
gpt-4.1-miniv2600.9580.7330.2430.50544151
gpt-4o-miniv1600.9870.5830.4140.823351114
gpt-4o-miniv2600.9830.6330.3580.71638517
gpt-4.1-nanov1600.999990.5000.5001.00030300
gpt-4.1-nanov2600.99950.5000.5000.99930300
qwen2.5:3bv2600.9980.5000.4980.99530300
qwen2.5:7bv2600.9650.6670.2980.59740020

Exact models: gpt-4.1-mini-2025-04-14, gpt-4o-mini-2024-07-18 and gpt-4.1-nano-2025-04-14 over OpenAI's API; qwen2.5:3b and qwen2.5:7b on Ollama on a development Mac. Wording v1 is the example template (2d3ecbdc), v2 asks plainly whether the answer is exactly correct (781efaaf); the local models ran v2 only. Every figure here is one run of 60 items, reproducible with examples/calibration in the repository.

stated confidence
The probability the model's own answer carried when it was given, averaged over the group.
ECE
Expected calibration error: the average gap between stated confidence and actual accuracy across the bins, 0 is perfect.
Brier
Mean squared error between the stated probabilities and the true outcome; here, multi-class, 0 is best and 2 is worst.
where it plugs in

What each part of the stack would get.

Two edges are measured; the rest are what a later integration would read, not something built. Click or focus a node.

typryx, and nine possible readers solid mint = measured, dashed = planned
pick a node

Click or focus a node above for what typryx gives it, which template, and what happens with typryx absent.

what typryx gives itstatus
MCP clients (Claude Code and others)a typed answer with a probability, per call, over MCPmeasured
TokenFuse, as brokera named upstream; one tool_call recorded against the agentmeasured
TokenFuse, router shadow modethe class it would have routed to, alongside cost, recorded onlyplanned
Verdryxa typed grader beside the existing LLM judgeplanned
Wardryxan optional signal that may become a hold, never a denyplanned
CostCrewa suggested class or priority at triage; a person still decidesplanned
Genaryxa panel, live only when GENARYX_TYPRYX_URL resolvesplanned
Engraman optional importance scoreplanned
Journal readers (Trailryx, Idryx)the same agent-event envelope; Idryx will never call typryx, its detection stays deterministicplanned
what it holds to

A probability, never an enforcement decision.

No deny from a probability

Not here, and not in a consumer. The planned Wardryx rule may turn a signal into a hold, which a person releases; nothing turns a probability into a deny.

Calibration, never pooled

typryx calibration groups by template, template version, backend and model, never averaged across any of the four. Two models under the same question with opposite calibration would otherwise cancel out on paper while neither is fine.

A later truth, scored honestly

An outcome posted later is scored against the exact template version an answer was asked under, read from the ledger's own record, never against whatever the live template says today. A second outcome for the same answer is refused.

One direct dependency

agent-stack-go, the stack's shared envelope library, is the only import beyond the standard library. A hostile-input sweep runs against the backends that parse bytes from outside the process, and the ledger survives a torn write mid-crash without losing the record after it.

Spend capped by default

1,000 calls an hour by default, counted only against calls that got past the door, the template lookup and the egress filter. Disabling it logs a warning at boot rather than doing it quietly.

Offline by default

The stub backend is deterministic and free, for tests and demos, and every answer it gives says so. The suite itself runs against httptest fakes; nothing in the test run reaches a live network.

in the stack

Optional, and it changes nothing when it is absent.

Typryx sits behind TokenFuse's MCP broker as a named upstream, so a call an agent makes is priced and recorded there before it ever reaches typryx's own door; the request.complexity template maps directly onto that router's own task classes, in shadow mode only, planned rather than built. A typed grader beside Verdryx's existing LLM judge is on the planned list above, not built: a typed answer is a single number a policy can threshold, calibrated against real outcomes rather than assumed honest, and it does not replace the judgement Verdryx already makes. If Wardryx ever reads a typed signal, the planned rule may turn it into a hold, which a person releases; nothing here or in a consumer turns a probability into a deny.

Without it, the rest of the stack behaves exactly as it does today: nothing here is consumed by anything else unless an operator wires it in.

status

Released as v0.1.0 on 2026-09-25: a signed image on ghcr.io for amd64 and arm64, and a release page with SBOMs; public on GitHub, CI green. Built and tested: the HTTP and MCP surfaces, the stub and openai-logprobs backends, the journal and ledger, calibration. The jev backend is built and tested against the documented wire shape, not yet run live: TypeSafe AI paused new signups on 2026-09-25.

Not yet: any launcher wiring (stack-single, stack-up, stack-k8s), agent-passport registration of its four event types, and every consumer in the tables above.

common questions

A typed answer, and what it does and does not do

Is typryx required to run the rest of the stack?

No. It is an optional add-on, and every other service keeps its current path unchanged when it is absent. Nothing in this repository or a planned consumer is built to depend on it.

What leaves the box when I send it a state?

Only the fields the template's own fields list names, held by the type system rather than a promise: internal/backend.Backend.Ask takes a template.Egress, a type constructible only inside the template package. Measured on a live run: a state carrying user_email and, separately, customer_iban, neither reached the backend or the record.

Can a probability block anything?

Not here, and not in a consumer. A probability is a signal a policy can threshold; the planned Wardryx rule may turn one into a hold, which a person releases, never a deny.

How do I know a probability is honest?

Not from the number alone, which is the finding of the calibration run below: every group was 96% to 100% confident on average and right 50% to 73% of the time. typryx calibration groups by template, version, backend and model, never pooled, and prints accuracy, mean confidence, ECE and Brier against a later truth posted to /v1/outcome, so calibration is measured rather than assumed.

Does typryx need Jev to be useful?

No. Jev is one backend behind one interface, not the contract; the stub backend answers deterministically for tests and demos, and openai-logprobs reaches any OpenAI-compatible server, including a local model. Jev is built and tested against the documented wire shape but not yet run live, since TypeSafe AI paused new signups on 2026-09-25.