Skip to main content

Jev-Style

Small, calibrated decision models you run on your own machine, plus the tooling to put them to work in AI agents.

PyPI CI Weights: 0.8B · torch · MLX · GGUF Demo on Hugging Face Spaces Agent skills: 6 License: Apache-2.0

The Playground answering a support-ticket request, then the agent-approval demo allowing, asking about and denying tool calls

Jev-Style is a family of small decision models built on Qwen3.5. The current model, Jev-Style-0.8B-Decision-v3, is 0.53 GB at 4-bit. You give it text or JSON and some typed questions, and it returns a calibrated probability for every option in one forward pass. The server's API follows the public systemone request shape, so clients written for Jev-compatible servers can call your laptop instead.

This repository is the part that makes the model useful day to day:

  • jev-style serve: a local API with a Playground and demos. It picks MLX on Apple silicon and PyTorch on CUDA or CPU; llama.cpp is optional.
  • Six agent skills: install with one npx skills add. They serve the model, call it, evaluate it on your own labels, replace LLM calls that only return a label, add a guard to Claude Code, and add the MCP tools.
  • A Claude Code guard: a PreToolUse hook where the local model checks every tool call before it runs and answers allow, ask or deny.
  • An MCP server: tools decide, noul, choice and score for Claude Code, Cursor, Codex and any other MCP client.
  • jev-style eval: measures accuracy and calibration on your own labelled data, and reports how many decisions you can automate at a 1, 5 or 10 % error budget.

No GPU, no API key and no training needed.

Highlights

  • Three question types in one request. Yes/no (noul), multiple choice (choice, up to 255 options) and ordered ratings (score, 2 to 10 levels). The model reads the text once and answers every question about it.
  • Probabilities, not just labels. Each release ships temperatures fitted on held-out data, so your code can act on confident answers and send the rest to a person or an LLM.
  • Long inputs. Up to 25,600 tokens per call. Nothing is truncated: an input that is too long is rejected with an error that says so.
  • Runs locally. About 0.15 to 0.2 s for a short request with MLX on an M1 Max, after the first call. Nothing leaves your machine.
  • 51 languages evaluated. Training covers 19 languages. On MASSIVE intent the model beats Laya's multilingual checkpoint in all 51 evaluated languages.
  • Built for agents. The skills, the MCP tools and the guard all work with Claude Code, Codex, Cursor and other agents.

Model

Model Size Banking77 (77 intents, never trained) MASSIVE intent, 37 held-out languages tweet_topic, zero-shot JevBench v1.4.1 public (231) Context
Jev-Style-0.8B-Decision-v3 0.8B · 0.53 GB (Q4_K_M) 68.2 % 65.5 % 75.5 % 64.1 % 25,600 tokens
Best official Laya checkpoint 0.8B 49.2 % 36.1 % 63.2 % 58.4 % 1,024 by default

All numbers are from the model card, which gives the full protocol and confidence intervals. The Laya rows are its official checkpoints re-run on the same rows, except tweet_topic and JevBench, which use published numbers. The hosted Jev API has higher accuracy than v3 on every one of these sets where its accuracy is published. Treat v3 as the small local option, not a replacement for the hosted model.

Build Size Used by
safetensors (bf16) 1.50 GB --backend torch (CUDA, Apple MPS, CPU)
MLX bf16 / 8-bit 1.50 / 0.80 GB --backend mlx (Apple silicon; auto picks it there)
GGUF F16 / Q8_0 / Q4_K_M 1.52 / 0.81 / 0.53 GB --backend gguf (llama.cpp through the bundled jev-score scorer)

Each build carries its own runtime file next to the weights. The server downloads a pinned revision and uses that file, so the answers here match what the model card documents. Earlier 2B generations, for use in LM Studio or Ollama without this server: v1 GGUF (LM Studio, llama.cpp) and v2 GGUF (Ollama).

Quick Start

Try it in the browser

The Hugging Face Space runs v3. There is nothing to install.

Run it locally

You'll need Python 3.10 or newer.

pip install "jev-style[mlx]"      # Apple silicon (MLX)
pip install "jev-style[torch]"    # Linux, Windows or an Intel Mac (PyTorch on CUDA or CPU)

jev-style serve          # downloads the model once (~1.5 GB), then serves http://127.0.0.1:8765

To install the command line tool on its own, with the MCP server, use uv: uv tool install "jev-style[all]" on Apple silicon, uv tool install "jev-style[torch,mcp]" elsewhere.

Open http://127.0.0.1:8765 for the Playground and the demos: agent action approval, Snake, and Chinese and 51 languages. In another terminal, send a ticket:

curl -s localhost:8765/v1/systemone -H 'content-type: application/json' -d '{
  "state": "Shoes arrived two weeks late and in the wrong size. Also I see two charges on my card.",
  "questions": {
    "department":  {"type": "choice", "instructions": "Which team should handle this?",
                    "criteria": {"returns":  "Exchanges, refunds, wrong or damaged items",
                                 "shipping": "Delivery status, delays, lost packages",
                                 "billing":  "Charges, invoices, payment problems"}},
    "escalate":    {"type": "noul",  "instructions": "Does this need urgent human attention?"},
    "frustration": {"type": "score", "instructions": "How frustrated is the customer?",
                    "criteria": ["Calm", "Frustrated", "Very angry"]}
  }}'

This is the actual response from v3 with MLX on an Apple M1 Max, with probabilities rounded:

{
  "model": "jev-style-0.8b-decision-v3",
  "answers": {
    "department":  { "type": "choice", "choice": "billing", "confidence": 0.46,
                     "probabilities": { "returns": 0.07, "shipping": 0.29, "billing": 0.64 } },
    "escalate":    { "type": "noul", "noul": 0.45 },
    "frustration": { "type": "score", "score": 1.28, "confidence": 0.36,
                     "legend": { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
                     "probabilities": { "0": 0.07, "1": 0.57, "2": 0.35 } }
  },
  "usage": { "input_tokens": 250, "state_tokens": 25, "output_tokens": 0 },
  "latency_ms": 194.0,
  "backend": "mlx"
}

The ticket raises both a billing problem and a late delivery, and the probabilities show it: billing 0.64, shipping 0.29. That is why the model returns probabilities rather than a single label. Your code can act on the confident answers and hand the rest to a person.

Use it from Python

For a script, one line is enough. The first call loads the model in-process, or uses the server in JEV_STYLE_URL if you set it:

import jev_style

jev_style.classify("Where is my parcel? It was due Monday.", ["billing", "shipping", "tech"])
# {'label': 'shipping', 'confidence': ..., 'probabilities': {'billing': ..., 'shipping': ..., 'tech': ...}}

For several questions about one text, and to choose the engine yourself:

from jev_style import JevStyle, choice, noul, score

js = JevStyle.from_pretrained("chaoliangUNSW/Jev-Style-0.8B-Decision-v3-MLX")   # in-process; the repo picks the backend
# js = JevStyle(base_url="http://127.0.0.1:8765")                                # or a running server
out = js.decide("I was charged twice. Please fix this ASAP.", {
    "billing": noul("This ticket is about billing."),
    "tone":    choice("What is the customer's tone?", ["calm", "frustrated", "angry"]),
    "urgency": score("How urgent is this ticket?", ["can wait", "this week", "today"]),
})
print(out["answers"]["billing"]["noul"], out["answers"]["tone"]["choice"])

from_pretrained takes the main repo (PyTorch), -MLX (precision="8bit" for the 0.8 GB weights) or -GGUF (quant="Q4_K_M", needs the jev-score scorer, see Backends). The client is not tied to this model: JevStyle(base_url=...) works with any server that implements POST /v1/systemone, and a client written for another systemone-compatible server can call http://127.0.0.1:8765 with any API key string.

From the shell

jev-style decide "Refund still missing after 3 weeks" --url http://127.0.0.1:8765 \
  --choice "Which team?::billing,shipping,returns" --noul "The customer is angry"
# without --url (or JEV_STYLE_URL) it loads its own copy of the model

Agent Skills

The skills live in skills/. Each one tells a coding agent how to do one job from start to finish, and ends with a check that the job worked.

npx skills add lawrence3699/jev-style                    # pick skills interactively
npx skills add lawrence3699/jev-style --skill '*' -y     # all six
Skill What your agent does with it
jev-style-serve Installs the CLI, picks the backend for your machine, starts the server, checks it with a real request, and can optionally start it at login.
jev-style Writes code that calls the model: request format, reading the probabilities, turning them into actions with thresholds, limits.
jev-style-eval Builds a labelled JSONL from your data and runs jev-style eval. It reports accuracy, Brier, ECE, how much you can automate at a 1, 5 or 10 % error budget, and a refitted temperature.
jev-style-adopt Scans your code for LLM calls that only return a label, yes/no or a rating, and rewrites them as typed questions. The LLM stays as the fallback below a confidence threshold. It runs in shadow mode, measures agreement, then switches.
jev-style-guard Installs the Claude Code guard hook. It recommends a dry run first, then shows how to tune thresholds and measure them on labelled calls.
jev-style-mcp Registers the MCP tools with Claude Code, Codex, Cursor, Claude Desktop or Windsurf, and checks that a tool call works.

In Claude Code you can also install everything as plugins:

/plugin marketplace add lawrence3699/jev-style
/plugin install jev-style@jev-style          # the six skills + MCP tools
/plugin install jev-style-guard@jev-style    # the PreToolUse guard

Claude Code Guard

Before Claude Code runs a Bash, Write, Edit, Read, WebFetch or MCP call, jev-style guard sends the call to the local model. It asks whether the call is destructive, exfiltrates data, touches secrets or goes outside the project, plus a 0 to 4 risk score. It turns the answers into allow / ask / deny. Regex hard rules in code can only make a verdict stricter. If the server is down, times out or rejects the request, the verdict is ask, never a silent allow.

jev-style guard --check "git push --force origin main"
# decision: DENY   (source: rule, 443 ms)  destructive 0.79 ...
jev-style guard-replay --url http://127.0.0.1:8765     # the 49 bundled labelled tool calls

On the 49 bundled tool calls, which were written and labelled by hand, the default config agrees with the labels on 77.6 %. No call labelled deny was allowed. 2 of the 16 calls labelled ask were allowed. The model alone, with no hard rules, agrees on 61.2 %. Use it as a second line of defence, not as a sandbox. The skill covers installing, dry runs and tuning.

MCP Server

claude mcp add jev-style --scope user -- jev-style mcp       # Claude Code

jev-style mcp is a thin stdio server that forwards to the running jev-style serve, so one copy of the model serves every client. It provides decide (several questions about one input), noul, choice, score and model_info. Setup for Codex, Cursor and Claude Desktop is in the skill.

Evaluate on Your Own Data

The best evidence is your own labelled examples. jev-style eval takes JSONL in the request format, with a label on each question:

jev-style eval examples/support_tickets.jsonl --url http://127.0.0.1:8765
question                   n     acc   brier    ece   automate @1% / 5% / 10% error
team                      30   93.3%   0.077  0.123    90.0% (p>=0.65) /  93.3% (p>=0.57) / 100.0% (p>=0.44)
escalate                  30   96.7%   0.107  0.125    80.0% (p>=0.71) / 100.0% (p>=0.54) / 100.0% (p>=0.54)
mood                      30   73.3%   0.433  0.174    40.0% (p>=0.56) /  40.0% (p>=0.56) /  46.7% (p>=0.54)

The 30 example tickets were written by hand for this repository. They demonstrate the format; they are not a benchmark. Read automate @5%: 93.3% (p>=0.57) like this: if you act only when the top probability is at least 0.57, the model handles 93.3 % of tickets with at most 5 % errors among them, and everything else goes to a person or an LLM. The report also refits a temperature on half the rows and shows its effect on the other half. See the skill for building a proper evaluation set.

Compare engines

Repeat --server to run the same file through several engines: this package's local model, another build or quantisation, or any other server that implements POST /v1/systemone. The first one is the reference.

jev-style eval examples/support_tickets.jsonl --server bf16=local:mlx --server q8=http://127.0.0.1:8799
90 questions answered by every engine; the table and the differences use only those.

engine             answered failed rows     acc   brier log loss    ece   automate @5% error
bf16                     90           0   87.8%   0.206    0.369  0.125    80.0% (p>=0.54)
q8                       90           0   87.8%   0.206    0.370  0.117    78.9% (p>=0.54)

difference to bf16 (95 % paired bootstrap over rows; brier: lower is better):
  q8               accuracy  +0.0 pts [+0.0, +0.0]   brier +0.001 [-0.001, +0.002]

That run compares the MLX bf16 weights in-process with jev-style serve --precision 8bit on an Apple M1 Max. Engine specs are NAME=URL, NAME=local[:backend], NAME=hf:<repo id> or NAME=fake; --key NAME=ENV_VAR sends a bearer token from an environment variable and --model NAME=MODEL sets the request's model field. Every engine is scored on the same questions: if one engine rejects a row (too long, too many options), that row is dropped for all of them and counted under failed rows. --json PATH writes every answer.

API

POST /v1/systemone with {"state": text | object | array, "questions": {id: question}}:

type criteria Answer
noul optional {"true": "...", "false": "..."} noul = P(true)
choice {option: description or null}, 1 to 255 options choice, probabilities, confidence
score 2 to 10 levels, lowest first: "label" or {"label", "description"} score = expected level index, legend, probabilities, confidence

confidence = (k · p_max − 1) / (k − 1) for k options: 0 when the probabilities are uniform, 1 when one option takes all of them. The other routes are GET /v1/models, GET /healthz and the Playground at /. Errors look like {"error": {"code", "message", "question"?}} and use HTTP 422 (invalid_json, invalid_request, invalid_question, input_budget_exceeded), 401 (unauthorized), 404 or 500. Start the server with --api-key-env NAME to require Authorization: Bearer <key>. The full reference is skills/jev-style/reference.md.

Backends

Machine Command
Apple silicon jev-style serve (MLX bf16; add --precision 8bit for 0.8 GB)
NVIDIA GPU jev-style serve --backend torch
CPU only jev-style serve --backend torch --device cpu
llama.cpp build jev-score once (sh build_jev_score.sh /path/to/llama.cpp from the GGUF repo), then jev-style serve --backend gguf --scorer /absolute/path/printed/by/the/script --quant Q4_K_M
Offline jev-style serve --model-dir /path/to/a/downloaded/model/repo
No model (UI or plumbing work) jev-style serve --fake (deterministic, meaningless answers)

Repository Layout

jev_style/           server, client, CLI, guard, MCP server, eval; web/ = Playground + demos
skills/              six agent skills (npx skills add lawrence3699/jev-style)
plugins/             Claude Code guard plugin (the root .claude-plugin/ is the marketplace)
examples/            labelled example data for jev-style eval
space/               source of the Hugging Face Space
tests/               pytest suite, runs on the fake engine (no model download)

Development

git clone https://github.com/lawrence3699/jev-style && cd jev-style
uv venv && uv pip install -e ".[dev]"
uv run pytest -q                # fake engine: no weights, no GPU
uv run jev-style serve --fake   # UI work without the model

Acknowledgements and License

Code: Apache-2.0 (LICENSE). The weights are Apache-2.0 fine-tunes of Qwen3.5-0.8B; the NOTICE in each model repository lists the changes. The typed-question convention follows Laya.

Not affiliated with, endorsed by or connected to TypeSafe or Jev. "Jev-Style" describes the kind of model: a small typed-decision model in a similar style. No Jev weights, code or outputs are included. Not affiliated with Alibaba Cloud or the Qwen team or the Laya authors.

Release files for jev-style 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jev-style 0.2.0
File Size Uploaded
jev_style-0.2.0.tar.gz 213.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jev-style 0.2.0
File Interpreter ABI Platform
jev_style-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 440.5 kB

Release files / jev_style-0.2.0.tar.gz

Download URL jev_style-0.2.0.tar.gz
Size 213.2 kB
Tags Source
SHA-256 checksum
How to use checksums
71442fd87ec466475fc074c80cb7a6b11b142d40a395ce4183db57adfcb86013
BLAKE2b-256 checksum
How to use checksums
1b67d8199beef567b1e31c4bd224cb11a0ac944daf7cc6489ddf43252dcf2a19
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 26, 2026.

Transparency log

Release files / jev_style-0.2.0-py3-none-any.whl

Download URL jev_style-0.2.0-py3-none-any.whl
Size 227.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e37cf989b81ff70979c1ba5aaa5631801eb82312908df6f1f0fb77809b596ec9
BLAKE2b-256 checksum
How to use checksums
4c5de5e2f7cfa3f86553e9b5c1c1415a1b965430b70239525a88f0573d5e729a
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 26, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page