jevkit — Python client for the Jev decision model
⚠️ Disclaimer: This is a third-party, unofficial wrapper around OpenRouter's Decisions API — not affiliated with, endorsed by, or maintained by OpenRouter or TypeSafe. The API is in alpha and may change without notice.
The first open-source third-party client for OpenRouter's Decisions API (Jev, by TypeSafe) — a calibrated-probability decision model, not a chat model.
Jev answers typed questions with calibrated probabilities — zero text generation. Three primitives: noul (yes/no calibrated probability), choice (pick one), score (scale rating). 70-500ms latency, output tokens free.
Why
Chat models guess; Jev calibrates. If you need routing, classification, or gating decisions ("is this worth doing?"), a chat model wrapped in JSON is slower, uncalibrated, and costs more. Jev is the ultimate classifier:
- Calibrated probabilities — real confidence, not vibes
- 70-500ms — System-1 speed for gating decisions
- $0.042/M input, output free — 14 questions ≈ $0.00004
- Typed questions — noul / choice / score, with explicit criteria
Install
pip install jevkit # (after publish — for now: copy the jevkit/ directory)
export OPENROUTER_API_KEY=<your key> # free from openrouter.ai
Quickstart
from jevkit import Client, gate
client = Client() # reads OPENROUTER_API_KEY
# noul — yes/no calibrated probability
p = client.noul(
name="worth_outreach",
instructions="Is this lead worth cold outreach?",
criteria={
"false": "No budget, or the poster is promoting themselves.",
"true": "Explicit budget + concrete need, reachable for a pitch.",
},
state="HN post: [Hiring] N8n automation expert, $2k budget, urgent",
)
# → 0.63
# gate — confidence-gated decision (act / confirm / escalate)
action = gate(p) # confirm (borderline — flips, don't auto-send)
# choice — pick one from options
r = client.decide({
"category": {
"type": "choice",
"instructions": "What does the customer need?",
"options": ["coding", "design", "content", "infra"],
}
}, state="I need someone to build a checkout flow")
# → {"choice": "coding", "confidence": 0.8, ...}
score — scale rating
r = client.decide({ "urgency": { "type": "score", "instructions": "How urgent is this?", "legend": { "0": "Can wait", "1": "This week", "2": "Blocking revenue now", }, } }, state="Payments are failing for customers right now")
→ {"confidence": 0.99, "legend": {...}, ...}
CLI
jevkit noul "worth outreach?" --state "lead: ..." # → 0.61
jevkit gate 0.63 # → confirm
jevkit decide questions.json --state "..." # → full answers
Gotchas (learned the hard way)
questionsexpects a record ({name: {...}}), not an array- noul's
criteriais{"true": str, "false": str}— descriptions, not options - The response is
answers.{name}.noul— not a top-level probability - Borderline probabilities flip — never auto-act on 0.5-0.7, gate them
- noul(false) + noul(true) don't have to sum to 1
The gate pattern
from jevkit import gate
p = client.noul(...) # System 1: calibrated fast decision
action = gate(p) # act(>=0.7) / confirm(0.5-0.7) / escalate(<0.5)
if action == "act": # only auto-act on high confidence
do_the_thing()
elif action == "confirm":
queue_for_review() # borderline → human or System 2 (LLM review)
Default thresholds: act >= 0.7, confirm >= 0.5 — tuned for the "borderline
flips" property (never auto-act in 0.5-0.7). Override per use case:
gate(p, act=0.8, confirm=0.6) # stricter gate
System 1 (Jev) decides who/what to act on; System 2 (a chat model) handles the acting itself (writing, reasoning). This division keeps costs low and decisions calibrated.
Status
- ✅ Client + CLI + gate pattern (validated with real API calls, R3 read-back)
- ✅ Error handling: RuntimeError on HTTP errors (fallback-friendly)
- 🚧 Tests + CI (in progress)
License
MIT
Metadata
Release files for jevkit 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jevkit-0.1.1.tar.gz | 6.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jevkit-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.9 kB
Release files / jevkit-0.1.1.tar.gz
| Download URL | jevkit-0.1.1.tar.gz |
|---|---|
| Size | 6.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d6fcb9eaa37a33eeeaa39e398a5a4e040640953a0894316dbd52e9c32b958be8
|
|
BLAKE2b-256 checksum How to use checksums |
367daa1903b006a703214d8adf030a6e33b9bf5985136dafcb18caf758c6ceaf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / jevkit-0.1.1-py3-none-any.whl
| Download URL | jevkit-0.1.1-py3-none-any.whl |
|---|---|
| Size | 8.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a930999d4cd4d2f1594e6b47103219f692400bbbf6b4c722d26054a5bfd4c950
|
|
BLAKE2b-256 checksum How to use checksums |
232fed218dd58f2ee954d5ad5f788d4c8385aeb32da46f3026c5af345e871b84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|