s1kit
Test, calibrate and route System One decision models on your own data.
Why
Decision models (Jev, Laya, kev, and anything served by llama.cpp or Ollama) all
speak the same /v1/systemone API: you send a state and typed questions, they
send back a choice, a score or a yes/no with a confidence. Swapping models is a
one-line change. Knowing whether you should is not. On day one you need to know:
- Which model is most accurate on my data?
s1kit testruns one suite against every model side by side. - What confidence can I trust?
s1kit calibratepicks a cutoff per question that reaches your target precision. - What happens below that cutoff?
s1kit.Routerasks the cheapest model first and escalates only when it is unsure. - Did my last change make it worse? The GitHub Action fails the build when accuracy drops.
Quickstart
pip install s1kit
s1kit init # writes s1kit.yaml: 10 support tickets, 3 questions
s1kit test
provider question n accuracy errors p50 ms p95 ms
-------------------------------------------------------------------------
keyword mood 8 50.0% 0 0.1 0.2
keyword team 10 100.0% 0 0.1 0.2
keyword urgent 5 80.0% 0 0.0 0.2
keyword: 18/23 correct (78.3%)
23 decisions saved to results.jsonl
That runs offline: keyword is a built-in word-overlap baseline that needs no
model or API key, and it is the bar a real model has to beat. Uncomment a real
model in s1kit.yaml to compare it. Then pick confidence cutoffs:
$ s1kit calibrate results.jsonl --target 0.95
keyword/mood: confidence >= 0.5761 -> 100.0% precise, answers 25% of cases
keyword/team: confidence >= 0.3333 -> 100.0% precise, answers 100% of cases
keyword/urgent: confidence >= 0.7143 -> 100.0% precise, answers 40% of cases
Read it as: trust the baseline on team, but send three quarters of mood
questions to a stronger model.
Write a suite
providers:
- type: keyword # offline baseline
- name: laya
base_url: http://localhost:8000 # laya-serve, or any /v1/systemone server
model: laya
timeout: 120 # seconds; the first request loads the model
- name: jev
base_url: https://api.typesafe.ai
model: jev-latest
api_key_env: TYPESAFE_API_KEY # sent as a Bearer token, read from the environment
questions:
team:
type: choice
instructions: Which team should handle this ticket?
criteria:
billing: Charges, invoices, payment methods
tech: Login problems, bugs, errors
cases:
- state: "I was charged twice for my order"
expect: {team: billing}
choice expects an option name, score a level index or label, noul true/false.
A case only needs to expect the questions you care about.
HTTP providers retry rate limits (429), server errors (5xx) and dropped
connections twice with backoff (set retries: to change it). A server that is
down fails at once with cannot reach ... is the server running? instead of
stalling the run. Use s1kit test -j 8 to send eight requests at a time.
Check accuracy in CI
# .github/workflows/s1kit.yml
on: pull_request
jobs:
s1kit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: Eliot5566/s1kit@v0.2.0
with:
suite: s1kit.yaml
fail-under: "0.9" # fail the job below 90% accuracy
env:
TYPESAFE_API_KEY: ${{ secrets.TYPESAFE_API_KEY }}
The table lands in the job summary. Inputs: suite, fail-under, only,
concurrency, results, python-version.
Route in production
import yaml
from s1kit import Router
from s1kit.providers import HttpProvider
thresholds = yaml.safe_load(open("thresholds.yaml"))
router = Router(
[HttpProvider("laya", "http://localhost:8000", "laya"),
HttpProvider("jev", "https://api.typesafe.ai", "jev-latest", "TYPESAFE_API_KEY")],
thresholds,
)
result = router.decide(ticket_text, questions)
result.answers, result.provider, result.escalations
The last provider always answers, so put your most capable model at the end. If a provider fails, the router moves on to the next one.
Commands
| Command | What it does |
|---|---|
s1kit init [PATH] |
Write a starter suite (default s1kit.yaml) you can run right away |
s1kit test [SUITE] [--only NAME] [-j N] [--fail-under 0.9] |
Run the suite, save every decision to results.jsonl, print a comparison |
s1kit report RESULTS |
Print the comparison again from a results file |
s1kit calibrate RESULTS [--target 0.95] |
Write thresholds.yaml with one cutoff per provider and question |
Compatibility
The HTTP provider is tested against a local server that answers exactly like
laya-serve 0.4 (including its strict Jev mode and x_jev_confidence). It has not
yet been run against every hosted model; if a server's answers do not parse,
please open an issue with a sample response.
Status: alpha (0.2.0). The API may change before 1.0.
Roadmap
- Markdown and JUnit reports, so results show up in pull requests (#3, #4)
- Response cache, so reruns cost nothing (#8)
- Recipes for more servers and ready-made suites for real tasks (#5, #6)
- pytest plugin, TypeScript package, LangChain and n8n integrations
- 1.0: public dataset packs, stable API
Contributing
New provider recipes, integrations, report formats and datasets are all welcome, and most fit in one evening. Issues labelled good first issue are a good place to start. See CONTRIBUTING.md.
License
MIT
Metadata
Release files for s1kit 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 | Provenance | Actions |
|---|---|---|---|---|
| s1kit-0.2.0.tar.gz | 20.2 kB | With provenance | Details for s1kit-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| s1kit-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for s1kit-0.2.0-py3-none-any.whl |
Total release size: 36.2 kB
Release files / s1kit-0.2.0.tar.gz
| Download URL | s1kit-0.2.0.tar.gz |
|---|---|
| Size | 20.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f0c2104854dde63cac1edbd3470cd4f780d6f65012f46ba81a3460008a130ac6
|
|
BLAKE2b-256 checksum How to use checksums |
c39e91094314c11146bc4cb6b34db937b20ed9bae5d577016b287521825b78cb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Oct 28, 2026.
Transparency logRelease files / s1kit-0.2.0-py3-none-any.whl
| Download URL | s1kit-0.2.0-py3-none-any.whl |
|---|---|
| Size | 16.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d07daa1b0aaaa3baa911b99ca9fbf345e117ad92939cf49399d78c8599875fd4
|
|
BLAKE2b-256 checksum How to use checksums |
1ce4a24c64b11beae642dca1ade823ef164a2a7708c890ded89e39f4c92a829b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Oct 28, 2026.
Transparency logSecurity for s1kit 0.2.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for s1kit-0.2.0.tar.gz
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 Oct 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.