question-kit for Python
The standard library for System One models. For now that means Jev, from TypeSafe.
Built by measurement, not guesswork: the core methods are developed against thousands of labeled cases, from public benchmarks and our own test sets, and tuned on what the results show.
Early release. This is the first piece of the Python port: the core plumbing and a first set of methods. The TypeScript package is the full kit (every core method, the order taker and the service agent), and the rest is coming to Python. APIs may change between 0.x releases; issues welcome.
Jev doesn't write text. You send it some state and a batch of closed questions ("which of these?", "yes or no?") and it returns a probability for every option, fast and cheaply. The hard part is writing the questions well and fitting code around the answers. question-kit does that part: each method writes its own questions, following TypeSafe's cookbooks, and returns a typed result with a confidence.
Install
pip install "question-kit[typesafe]"
Python 3.10 or later. The typesafe extra installs TypeSafe's SDK (typesafe-sdk), which
question_kit.typesafe wraps; leave it out if you bring your own client. Calls to Jev need
TYPESAFE_API_KEY.
A first question
from question_kit import classify, run
from question_kit.typesafe import typesafe_jev
client = typesafe_jev() # reads TYPESAFE_API_KEY
intent = run(client, classify("where is my package? it was due Friday", {
"shipping": "Where an order is, or when it will arrive",
"refund": "Money back for an order",
"account": "Logging in, passwords, account details",
}))
intent.value # "shipping", or "none" when nothing fits
intent.confidence # 0 to 1, by TypeSafe's confidence formula
Several questions about the same text go in one request with run_all, the way TypeSafe recommends:
from question_kit import check, classify, extract_value, run_all
r = run_all(client, {
"intent": classify(text, labels),
"order": extract_value(text, kind="number", role="the order number"),
"upset": check(text, "The customer is upset."),
})
r["order"].value # "4410982": always text that's really in the message
r["upset"].value # True or False, with r["upset"].confidence
What's in 0.1
| Methods | classify (with back-off to a parent label), extract_value (email, phone, amount, number, zip, names, or your own pattern), screen (flags and a policy), rank_by_score (a list in order by levels you write) |
| One-question tasks | check, checks, choose, rate |
| Plumbing | state parts and Refs, choice / noul / score, readings with TypeSafe's confidence formulas, run and run_all, pre-send lint, estimate_cost |
| Clients | typesafe_jev() (retries set for batch work), cached_jev() (record and replay answers on disk), fake_jev() for tests |
The API is synchronous for now.
Compared with the TypeScript package
| TypeScript | Python 0.1 | |
|---|---|---|
| Core methods | all of them | the four above, plus the one-question tasks |
Order taker (question-kit/order) |
✓ | not yet |
Service agent (question-kit/service-agent) |
✓ | not yet |
| Answer cache | ✓ | ✓, the same files and keys |
| Runs in the browser | ✓ | n/a |
The two build byte-for-byte the same requests (a test checks this against requests built by the TypeScript package), so they share one answer cache: answers recorded by either replay in both.
Testing without Jev
from question_kit import fake_jev, run, check
from question_kit.cache import cached_jev
fake = fake_jev(lambda qid, question, state: "yes") # every Noul says yes
run(fake, check("hi", "It's a greeting.")).value # True
client = cached_jev(typesafe_jev(), ".cache/jev") # record: ask once, keep the answer
replay = cached_jev(None, ".cache/jev", mode="replay") # never calls the API; a miss raises
Links
- Docs: docs.questionkit.dev (the Python pages are under Python)
- Source: github.com/Engid/question-kit, in
python/ - TypeSafe's docs: docs.typesafe.ai
MIT licensed. © 2026 Nick Gideo.
Metadata
Release files for question-kit 0.1.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 | |
|---|---|---|---|
| question_kit-0.1.0.tar.gz | 34.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| question_kit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 65.2 kB
Release files / question_kit-0.1.0.tar.gz
| Download URL | question_kit-0.1.0.tar.gz |
|---|---|
| Size | 34.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
67b1f1a8494ee208830a36291aa1b8ab21b3b3a603d70c7b95477990bdba321e
|
|
BLAKE2b-256 checksum How to use checksums |
dd7414a2fffa812e1173645ab878598f3f12734099df534408249771dd88eb52
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / question_kit-0.1.0-py3-none-any.whl
| Download URL | question_kit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 31.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a4a563570d22a00ee64959ea1f0ced87b92d2477a0e30fdf3dcb18c27a336d92
|
|
BLAKE2b-256 checksum How to use checksums |
c7cadbd913c1dc8327d9285bcfd4cbf48007d041647a00dceb10e64f27c72915
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|