hunch
Plain functions on Jev. Lists in, lists out.
Jev is TypeSafe's System One model: you send state and typed questions, and you get labels, scores, and yes/no probabilities back. hunch turns that into six verbs you call like any other function. Code owns the workflow. Jev judges. An optional LLM may propose candidates; it never decides.
import hunch
hunch.classify("This product is amazing!", ["positive", "negative", "neutral"])
# 'positive'
hunch.classify(df["JOB_TITLE"], ["Sales", "Engineering", "Marketing"])
# Series of labels, same index
hunch.score("Critical system failure", ["cosmetic", "degraded, workaround exists", "down for everyone"])
# 1.87 (position on the scale, 0 .. n-1)
hunch.check("BUY NOW!!!", "is unsolicited advertising")
# True
Install
pip install hunch-jev
Python 3.10+. Set TYPESAFE_API_KEY, or call hunch.configure(api_key=...). Never put keys in source.
Verbs
| Verb | Jev primitive | Returns |
|---|---|---|
classify(data, labels, multi_label=False, instructions=None) |
Choice, or one Noul per label | label, Enum member, or list of labels |
score(data, levels, instructions=None) |
Score | float position on the scale, or {dim: float} |
check(data, statement, criteria=None, threshold=0.5) |
Noul | bool, or {name: bool} |
pick(candidates, instructions) |
Choice over the candidates | the winning candidate |
rank(candidates, dimensions, levels, weights=None) |
Score per dimension | Ranked rows, best first |
generate(target, n=1, instructions=None) |
your LLM, validated by pydantic | target or list[target] |
Every verb takes a single item or a list / tuple / pandas Series and returns the same shape. Repeated values are asked once. Items run in parallel across max_workers threads. Every verb accepts context= (extra state alongside the input) and client=. Every verb has an _async twin.
labels may be a list, an Enum class (you get members back), or a mapping of label to description. instructions on score and check may be a mapping of name to question; the dimensions go in one request and you get a dict per item.
detail=True
The bare return is the answer. detail=True returns the whole distribution:
| Verb | Detail type | Fields |
|---|---|---|
classify |
Answer |
.label .p .probabilities .confidence .shape .top2 .on() |
classify(multi_label=True) |
MultiAnswer |
.labels .probabilities .threshold |
score |
Rating |
.score .level .normalized .probabilities .legend .confidence .shape .on() |
check |
Feeling |
.p .threshold, truthy at threshold |
pick |
Pick |
.winner .ranked .confidence .shape .on() |
.shape is your policy on the distribution, not a Jev field:
| Shape | Meaning |
|---|---|
sure |
One option dominates |
split |
Two options are close |
unsure |
Flat or weak evidence |
level = hunch.classify(title, ["IC", "Manager", "Director"], detail=True)
seniority = level.on(
sure=level.label,
split=lambda: hunch.classify(title, level.top2), # rematch the top two
unsure="review",
)
Cutoffs live on ShapePolicy. Confidence is how peaked the distribution is, not whether the label is true. Changing the policy never re-runs inference.
Generate, rank, pick
An LLM drafts. Jev scores and chooses. Code keeps the weights.
import hunch
hunch.configure(llm=hunch.openrouter(), cache="~/.cache/hunch")
tweets = hunch.generate(str, n=20, instructions="Tweets introducing hunch to Python developers", context=README)
ranked = hunch.rank(
tweets,
{"hook": "How strong is the first line?", "clarity": "How clearly does it say what hunch does?", "specific": "How concrete, not generic, is it?"},
levels=["weak", "okay", "strong", "excellent"],
weights={"hook": 2, "clarity": 1, "specific": 1},
)
finalists = [row.item for row in ranked[:5]]
winner = hunch.pick(finalists, "the tweet most likely to make a Python developer install hunch")
generate accepts str, int, dataclasses, TypedDicts, pydantic models, list[str], and any other type pydantic can validate. hunch.openai, hunch.cerebras, and hunch.openrouter are OpenAI-compatible adapters; pass llm= on configure() or on generate().
Client
jev = hunch.Client(api_key=..., model="jev-latest", cache="~/.cache/hunch", max_workers=8, policy=ShapePolicy(...))
hunch.classify(x, labels, client=jev)
jev.usage # calls, cache hits, tokens, model
hunch.configure(...) takes the same arguments and sets the default used when client= is omitted. cache= persists raw Jev answers on disk keyed by state and question.
Examples
Each one is a single file with the data inline. The first three need only TYPESAFE_API_KEY.
| File | Shows |
|---|---|
find_angry_reviews.py |
check over a column as a boolean mask, ranking by probability, several checks in one request |
classify_job_titles.py |
classify with Enums, detail=True, and .on() routing sure / split / unsure with a rematch |
triage_tickets.py |
score on two scales in one request, multi-label classify, paging policy kept in code |
introduce_hunch.py |
generate 20 tweets with an LLM, rank them on weighted dimensions, pick the winner |
organize_downloads.py |
An LLM proposes a folder taxonomy, classify assigns every file, the script moves them. --dry-run prints the plan |
What this is not
Jev does not invent labels. labels is the whole set of allowed answers. generate invents candidates; it has no tools and takes no actions. Open-ended writing and multi-step agents are out of scope.
License
MIT. Jev and TypeSafe are typesafe.ai; this library is not affiliated.
Release files for hunch-jev 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hunch_jev-0.2.0.tar.gz | 24.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hunch_jev-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 43.6 kB
Release files / hunch_jev-0.2.0.tar.gz
| Download URL | hunch_jev-0.2.0.tar.gz |
|---|---|
| Size | 24.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
704a8951c6a841eb05681218dff9f61fd2b8bff362354bbc974156aa477fc30c
|
|
BLAKE2b-256 checksum How to use checksums |
353637980bca93d2f94526863ce1d68b515f9d9605d2a31a695b8ecd7bf43848
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency logRelease files / hunch_jev-0.2.0-py3-none-any.whl
| Download URL | hunch_jev-0.2.0-py3-none-any.whl |
|---|---|
| Size | 18.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
96cd16fa1749a12643e62d2c670ade27e8c04435df504c2456857c637e962cf0
|
|
BLAKE2b-256 checksum How to use checksums |
432fdc85e1d11345fbd858998f60fbbe0c05f32f3bd896e68393f0b31b690e3c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency log