Bauxi-23M

Does this decision still hold, given what just happened?

Bauxi-23M is a small English classifier that reads a decision and a new piece of evidence and answers valid, invalid or unknown. It makes that call in one forward pass on a CPU, with no GPU, no text generation and no network.

Runs in 0.1 of a CPU core and 80 MiB of RAM
Latency 3–6 ms on one core for a typical pair, 35 ms at the longest
Size 22 MiB on disk, INT8
Parameters 22.76 million
Accuracy 90.7% on a sealed 150-case holdout, 71.1% on a later stress test of its weak spots
Use it as A first-pass flag, never as the only check before an action
License MIT, with a clean training lineage

It is the first model from Classifyre.

What it answers

Answer Meaning What your application does
valid The evidence supports the decision, or leaves an unconditional one unchanged. Carry on through your normal checks.
invalid The evidence defeats a prerequisite or withdraws the decision. Pause, and replan or ask for a new decision.
unknown A necessary fact is missing, unresolved, stale or about something else. Get current evidence, or ask.

Real outputs of this model:

Decision Evidence Bauxi Score
Deploy if the integration tests pass. All integration tests passed this morning. valid 0.99
Deploy if the integration tests pass. The integration tests failed. invalid 0.99
Deploy if the integration tests pass. The integration tests are still running. unknown 0.89
Book the hall only if it seats at least 120 people. The hall has 150 chairs, but 40 of them are broken. invalid 0.99
Buy the licence if the total stays at or below 500 euros. The price is 480 euros, but the setup fee has not been quoted. unknown 0.98
Send the contract after legal and finance have both signed. Finance signed. Legal rejected the draft. invalid 0.98
Rename the planning sheet to 'Northwind'. An unrelated printer jam was reported. valid 1.00

And a miss, because you should see one:

Decision Evidence Bauxi Score Right answer
Ship the order before the Friday inspection. The courier confirmed delivery on Wednesday. invalid 0.53 valid

Ordering days of the week is its weakest skill. See limits.

Use it

pip install onnxruntime tokenizers numpy huggingface_hub
import sys
from huggingface_hub import snapshot_download

path = snapshot_download(
    "classifyre/Bauxi-23M",
    allow_patterns=["bauxi.py", "bauxi.json", "tokenizer.json", "onnx/*", "ort/*"],
)
sys.path.insert(0, path)
from bauxi import Bauxi

model = Bauxi(path)
result = model.predict(
    decision="Deploy if the integration tests pass.",
    evidence="The integration tests failed.",
)
print(result.label)  # invalid
print(result.probabilities)  # {'valid': 0.01, 'invalid': 0.99, 'unknown': 0.00}

Bauxi picks the graph built for your machine on Linux (arm64 or amd64) and falls back to the portable ONNX model anywhere else, including macOS and Windows. It checks the hash of every file it loads and uses one CPU thread unless you pass threads=.

Bauxi-23M is not a transformers pipeline model, on purpose. It needs a pair of texts and 346 numeric features computed by bauxi.py, and a stock text-classification pipeline can give it neither. So this repository has no config.json, and loading it that way fails loudly instead of returning worse answers quietly. model.safetensors holds the FP32 weights for fine-tuning.

As a service

curl http://localhost:8080/decide \
  -H 'Content-Type: application/json' \
  -d '{"decision":"Deploy if the integration tests pass.","evidence":"The integration tests failed."}'
{
  "prediction": "invalid",
  "probabilities": { "valid": 0.01, "invalid": 0.99, "unknown": 0.0 },
  "calibrated": false
}

serving/ holds the FastAPI service. GET /health is the probe. Empty, extra or oversized fields get HTTP 422; nothing is ever truncated.

Input rules

  • English, one short decision and one short piece of evidence.
  • 1–800 characters per field, and at most 128 tokens together.
  • Longer input is refused, because truncation could cut the very fact that matters.

Help it by being explicit: name the action, the entity and the condition, and resolve pronouns, dates and units before you call it.

Benchmarks

The full report, with every model and every measurement, is in BENCHMARKS.md.

Quality

All numbers are from the published INT8 model. Predictions for the holdout are in eval/, so you can check them.

Evaluation Cases Accuracy Macro-F1 Invalid recall False-safe Role
Sealed holdout 150 90.7% 0.906 90% 5/50 Final test
Stress test 180 71.1% 0.719 66.7% 20/60 Aimed at known weak spots
Regression set 888 97.1% 0.971 92.2% 5/296 Generated, same grammar as training
Development 660 96.5% 0.964 91.8% 15/220 Used to select the model, so optimistic

False-safe means an invalid case answered valid. It is the expensive error, so watch it separately: at 5/50 it is high enough that valid must never be the only thing standing between a model and an action.

On the holdout, per class:

Precision Recall F1
valid 87.5% 84% 0.857
invalid 86.5% 90% 0.882
unknown 98% 98% 0.980

Confusion on the holdout (rows are the truth):

→ valid → invalid → unknown
valid 42 7 1
invalid 5 45 0
unknown 1 0 49

For comparison, the obvious alternative is to take a stock NLI cross-encoder and map entailment, contradiction and neutral onto the three answers. On the same holdout, cross-encoder/nli-MiniLM2-L6-H768 (82 million parameters) scores 43.3%. Whether a statement follows from a text is a different question from whether a decision can still go ahead.

CPU

Bauxi-23M was built for small pods. It was measured as a Kubernetes pod with hard limits of 100m CPU and 80 MiB of memory, on Linux arm64 on an Apple M1 Pro, with the load generated from outside the pod. Peak memory is the cgroup's own charge across startup and every phase.

At the limit: 0.1 of a core, 80 MiB. Peak memory was 66.4 MiB in this run and 76.6 MiB in an earlier one, with zero restarts, OOM kills or memory-limit events.

Workload Requests Throughput CPU used Latency p50 Latency p95
Idle, with health probes – – 2.6m – –
Paced at 5 per second 300 5.0/s 59m 15 ms 100 ms
One at a time, flat out 200 8.0/s 100m 103 ms 201 ms
Five at once 100 9.2/s 100m 505 ms 696 ms
Longest input, 127 tokens 100 2.1/s 100m 496 ms 695 ms

At 0.1 of a core the quota is the bottleneck, so latency climbs as soon as requests queue. Below about 5 requests per second it stays comfortable.

On one full core. The same image in a container limited to one CPU, in process, with no HTTP and one thread:

Tokens Latency p50 Latency p95 Predictions per second
7 2.2 ms 2.6 ms 436
15 3.5 ms 3.9 ms 282
31 6.7 ms 8.4 ms 143
63 14.1 ms 21.0 ms 65
127 35.9 ms 42.7 ms 27

The model loads in about 0.2 seconds. Peak process RSS here was about 90 MiB, which is higher than the pod's charge because shared, memory-mapped pages count differently.

These numbers are from one machine; measure on your own hardware before you rely on them. The amd64 graph was built and verified under emulation, where every holdout label matches, but it has no native x86 benchmark yet. Staying near 80 MiB also depends on the settings in serving/: one process, one worker, one ONNX thread, staged loading and MALLOC_ARENA_MAX=1. Plan for the higher peak: 76.6 MiB is close to the limit, and the gap is not spare capacity.

Compared with hosted decision models

On the same 330 cases, 25 hosted decision models set the bar. They are far larger and need a network; the smallest is about 175 times the size of Bauxi-23M.

Model Size Holdout False-safe Stress False-safe $ per 1,000
Drex Max large 98.7% 0/50 96.7% 1/60 0.010
Mammoth 1 27B 97.3% 0/50 96.7% 0/60 0.017
Jev 1.14 not stated 87.3% 3/50 91.7% 3/60 0.017
Kev 4B 4B 89.3% 3/50 82.2% 6/60 0.004
Bauxi-23M 0.023B 90.7% 5/50 71.1% 20/60 local

Over both sets it places 25th of 26. If your data may leave the machine, a hosted decision model is the better choice. Bauxi-23M is for places where it may not, or where there is no network, no per-call budget, or only a small pod to run in.

What the numbers mean

The 90.7% is a point estimate from 150 cases in 50 scenario families, written by one author. Resampling whole families gives a 95% interval of 85.3–95.3%. The model, preprocessing and temperature were sealed before the holdout was opened, and nothing was tuned afterwards. An earlier model had been scored on the same 150 cases; no error from those cases went into training this one.

The 71.1% comes from 180 cases in 60 families, written later and weighted to the categories that failed on the holdout, so it measures the weak spots and not general accuracy. It is still the more useful warning: most of its 20 false-safes are one mistake, where the condition's words appear in the evidence and Bauxi-23M answers valid. "Until the tank is full" with a full tank is the typical case. Neither set has independent human adjudication, and neither is a promise for your traffic.

How it works

evidence + decision ──► MiniLM encoder (6 layers, 384 wide) ──► pooled text
                                                                     │
numbers, weekdays, clock times ──► 346 relations ───────────────────►├──► head ──► logits
  • Encoder: a six-layer MiniLM, 384 hidden units, 12 attention heads and a 30,522-word vocabulary. Evidence comes first in the pair.
  • Numeric relations: bauxi.py extracts up to six numbers per field and exposes comparisons, differences, sums, weekday and clock order to a learned head. They contain no rules and never pick a label; the head decides what they mean. This is why "26 chairs, four broken" can fail "at least 24".
  • Quantization: dynamic UINT8 on MatMul and Gather. Compared with FP32, 98.8% of labels are unchanged across 664 cases.
  • Temperature: 1.573, fitted on 444 separate synthetic cases. Responses carry calibrated: false because that does not establish real-world calibration: a score of 0.95 is not a 95% chance of being right.

Training

Step Data Device
NLI warm-up, 4 epochs 102,885 WANLI pairs Apple MPS
Decision training, 3,500 of 4,000 steps 51,475 cases Apple MPS

Each decision-training batch of 32 holds 8 task cases, 4 WANLI cases, 10 numeric contrasts and 10 language contrasts, so that the large public set cannot drown the small curricula that carry the hard cases. Weights are an exponential moving average (0.999), and the invalid class has a loss weight of 1.2. The checkpoint was chosen on development data, on 0.3 × generated macro-F1 + 0.7 × hard macro-F1 − 0.2 × hard false-safe rate.

Most of the training data is authored and generated: prerequisites, AND/OR, entity and time scope, unreliable sources, negation, numbers, deadlines and irrelevant updates. Each scenario appears with all three labels, so that no word can stand in for the answer. Training used an accelerator; inference needs only a CPU.

Use it for

Use it to decide what a person or a stronger system should look at first, on your own hardware, with nothing leaving the machine.

  • Agent replanning: a dependency moved, so review the plan before the next step.
  • Approval changes: one of two required reviewers withdrew.
  • Workflow prerequisites: the inspection is still pending, so wait.
  • Memory upkeep: a new update conflicts with a stored commitment, so queue it for review.
  • Document review: check a corpus against a standing decision. In Classifyre it runs as a code detector; every answer on both test sets was reproduced through a full scan, in eval/classifyre-pipeline.json.

Never let valid authorize an action by itself. With thresholds fitted beforehand, requiring P(valid) ≥ 0.995 gave no wrong go-aheads on the 330 test cases, but only 3.6% of cases passed it. So treat invalid and unknown as useful flags, and treat valid as "no flag raised", not as permission. Start in shadow mode and compare it with what your operators decide.

Limits

  • Not an authorization engine. It does not authenticate facts, retrieve anything or grant permission. Real permissions, signatures and arithmetic belong in code.
  • Known weak spots: "either A or B" when both fail (22/36 correct on the stress test), until and while conditions (19/36), and weekday order (28/36).
  • Numbers are bounded. It sees six numbers per field. It does not solve arithmetic in general, relative dates, time zones, unit conversion or business calendars.
  • English only, short pairs only. Long histories, several decisions at once, unresolved pronouns and mixed languages are out of scope and were not evaluated.
  • Probabilities differ slightly between CPU types. Labels on the holdout match between arm64 and amd64, but scores can move by up to 0.1 near a decision boundary.

License and lineage

Weights, code and authored data are MIT. Every input was chosen so that this holds:

Component License
Encoder start: nreimers/MiniLM-L6-H384-uncased MIT
Language data: WANLI CC BY 4.0, attributed in NOTICE.md
Decision data: authored and generated for this model MIT

WANLI was used for training and is not redistributed here. Its labels were renamed and its hypotheses restated as prerequisites; NOTICE.md gives the changes and the citation.

Citation

@misc{classifyre-bauxi-2026,
  title  = {Bauxi-23M: a small CPU classifier for checking decisions against evidence},
  author = {{Classifyre}},
  year   = {2026},
  url    = {https://huggingface.co/classifyre/Bauxi-23M}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Safetensors
Model size
22.8M params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for classifyre/Bauxi-23M

Quantized
(35)
this model

Dataset used to train classifyre/Bauxi-23M

Evaluation results

  • Accuracy on Bauxi-23M authored holdout (150 cases, 50 scenario families)
    self-reported
    0.907
  • Macro F1 on Bauxi-23M authored holdout (150 cases, 50 scenario families)
    self-reported
    0.906
  • Accuracy on Bauxi stress test of known weak spots (180 cases, 60 scenario families)
    self-reported
    0.711