Getting started with the Jev backend
Jev is TypeSafe's judgment model. It doesn't write text; it answers yes/no, label and rating questions with calibrated probabilities, in about 0.3 seconds. Use it for the functions that only decide something.
Set it up
-
Install thunc
The
jevbackend is in thunc 0.1.3 and later. It needs no extra Python packages.pip install --upgrade thunc -
Get a TypeSafe API key
Create one in the TypeSafe console. You'll paste it into
jev loginin step 4, and nowhere else. -
Install the jev CLI
On a Mac with Apple Silicon, use TypeSafe's Homebrew tap. Homebrew asks you to trust a tap's formulas before it installs them; trusting only
jevis enough.macOS (Apple Silicon)brew tap model-clis/packages brew trust --formula model-clis/packages/jev brew install jevOn Linux, or a Mac without Homebrew, the install script checks the download's SHA-256 and puts
jevin~/.local/bin. For Windows and other options, see the jev README.Linux and macOScurl -fsSL https://raw.githubusercontent.com/model-clis/jev/main/scripts/install.sh | sh -
Log in
jev loginasks for your key, checks it with TypeSafe and stores it in~/.model-clis/jev/credentials.json, readable only by you.jev loginIn CI or a container, set
JEV_API_KEYinstead. It takes precedence over the stored login. thunc never sendsconfigure(api_key=...)to Jev, because that is usually the key of another backend. -
Check that it works
One call costs a fraction of a cent. A probability near 1 means the login works.
jev noul "Is the sky blue?" --state "A clear summer day"Output{"answers":{"q":{"noul":0.95,"type":"noul"}},"latency_ms":265,"model":"jev-1.13.0","ok":true,...} -
Point thunc at it
Pick Jev for one function with
backend="jev", or for everything withthunc.configure(backend="jev")orTHUNC_BACKEND=jev. thunc never picks it on its own.from typing import Literal import thunc @thunc.function(backend="jev") def team(ticket: str) -> Literal["bug", "billing", "feature-request", "other"]: """Which team should handle this customer support ticket?""" ... team("I was charged twice this month.") # "billing"
What Jev can answer
Jev picks from answers you define, so only these return types work. Any other type raises ThuncError before a request is sent.
| Return type | Jev question | You get |
|---|---|---|
bool | yes/no (noul) | True when a yes is at least as likely as a no |
Literal["bug", "billing", ...] | choice, up to 255 labels | The label Jev chose |
Literal[1, 2, 3, 4, 5] | score, levels lowest first | The most likely level, as an int |
str, int, float, list, dict, dataclasses, T | None | none | ThuncError; use another backend |
For a rating, use Literal[1, 2, 3, 4, 5] instead of int with ensure=.
Use it next to Claude
Jev can't write text, so most programs use it for the decisions and another backend for the writing. Each function picks its own backend. Here Jev filters every message, and Claude drafts a reply only for the ones that need one.
thunc.configure(backend="anthropic") # the default, for text
@thunc.function(backend="jev")
def needs_reply(message: str) -> bool:
"""Does this message ask a question or report a problem we should answer?"""
...
@thunc.function
def draft_reply(message: str) -> str:
"""Write a short first reply to this message. Never promise a refund."""
...
for message in inbox:
if needs_reply(message): # ~0.3 s, fractions of a cent
print(draft_reply(message))How thunc's options behave
- inputs
- Sent as Jev's state. The docstring or instructions become the question.
- system=
- Your own system prompt goes before the question as context. thunc's default prompt is written for text models, so it isn't sent.
- model=
- Ignored. The CLI always uses
jev-latest, which the cache and trace record. - ensure=
- A rejected answer raises
ThuncErrorat once. Asking again would get the same answer. - cache=, trace=
- Work as for any backend.
- thunc.map
- Works as usual. 8 workers stay under Jev's limit of about 20 requests per second.
- agents
- Not supported: an agent run on Jev raises
ThuncErrorbefore calling a backend.
Try the examples
From a clone of the repository, after step 4:
python3 -m examples.jev_hello # a yes/no, a label and a rating
python3 -m examples.jev_inbox # 8 tickets, 24 calls, about 1 s
python3 -m examples.jev_with_claude # Jev decides, Claude Code writes the repliesTo run thunc's live tests on Jev: THUNC_BACKEND=jev pytest live_tests. Tests that need text answers are skipped.
If something goes wrong
| You see | What to do |
|---|---|
`jev` was not found on PATH. | Install the CLI (step 3). If you used the install script, add ~/.local/bin to your PATH. |
Refusing to load formula model-clis/packages/jev from untrusted tap | Run brew trust --formula model-clis/packages/jev, then brew install jev again. |
jev exited 1: Error: API rejected the credentials | Run jev login again. If JEV_API_KEY is set, it wins over the login, so check or unset it. |
The jev backend answers bool, Literal of strings ... | The function's return type isn't one Jev can answer. Use Literal[...], or give that function another backend. |
Unknown backend 'jev' | Your thunc is older than 0.1.3: pip install --upgrade thunc. |