Skip to content
amyrmahdyPublic

About

Small local judges and guards for LLM apps: calibrated decisions, prompt-injection and leak checks on a CPU. English, Arabic, Persian. Runs in your browser too.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

Decima

Small local judges for LLM systems. Give Decima a situation, a question and your options; it returns calibrated probabilities in milliseconds, on a CPU, with nothing leaving your machine.

pip install decima-ai

Or try it first in your browser, nothing to install: Playground · Guard page.

decima on the command line: an agent gate, a knowledge-graph judgment and a custom question, on CPU

$ decima "Your API has been returning 500 errors for an hour and our checkout is down!" --preset triage
decima-base · triage
category   technical                         ███████████████████▌ 0.97
urgency    2 Now: the writer or their busi…  ██████████████████▌  0.92
sentiment  negative                          ███████████████████▍ 0.97

$ decima "rm -rf ~/projects/app" --preset agent-gate
decima-agent · agent-gate
gate       deny   ███████████████████▋ 0.98
read_only  no     ▎                    0.01  p(yes)

$ decima "I was charged twice for my subscription" --question "Which team?" --choices billing,technical,sales
decima-base · 81 ms
answer  billing    ██████████████████▉  0.94
        technical  ▉                    0.05
        sales      ▏                    0.01

(Outputs shortened to the top answer per question; the CLI also prints the runners-up.)

New in 2.3: decima-guard, a guard for LLM apps that covers the OWASP LLM Top 10 and common web attacks, in English, Arabic and Persian (Finglish too). Unlike English-first guards, its injection check doesn't block ordinary Arabic and Persian chat: it lets 99.5% of 589 harmless Arabic messages through, where ProtectAI's detector lets 25.1% through. decima-guard 1.2 is much better at injections hidden in documents and tool results: on the 10 public sets of the Horizon-Labs prompt-injection suite its mean goes from 0.650 to 0.827 (BIPIA 0.346 → 0.694 F1, PIArena 0.310 → 0.770, LLMail-Inject 21% → 80% caught). Part of that is in-distribution (it trained on other splits of BIPIA, LLMail-Inject and OR-Bench); it is not a leaderboard rank, and it gave up a little on chat-message injections (0.910 → 0.902). 1.1 halved the wrong blocks on everyday spoken dialect (39.6% → 19.5% of ordinary lines, Casablanca test set) and 1.2 keeps that (20.0%). Try it in your browser, or see examples/guard_chatbot.py.

decima-guard: prompt injection in English, Finglish and Persian, a SQL injection and an injection hidden in a tool result

New: decima-pii v0.2 finds personal data (names, phones, emails, national IDs, IBANs, cards, addresses ...) in Arabic, Persian, Urdu, Turkish and English, including numbers in Persian and Arabic-Indic digits. 140M, int8 ONNX, about 13 ms per message on a CPU. On an outside clinical test set it never trained on (MultiGraSCCo), v0.2 scores 0.910 F1 against 0.647 for OpenAI's privacy filter: Arabic 0.913 vs 0.581, Persian 0.849 vs 0.508, Turkish 0.928 vs 0.626, English 0.957 vs 0.901 (v0.1: 0.870). On an Arabic test set chosen and frozen before v0.2 was trained, and run once (Sitr), it scores 0.875 against v0.1's 0.856. Preview; limits on the model card. It ships inside decima-ai (find and redact), with a LiteLLM guardrail and a Presidio recognizer. New in 2.5: the package loads decima-pii v0.2 and pins that model tag, so a later model update never changes your results silently; revision="v0.1" gives the previous model. Try it in your browser: the model runs in the tab.

decima-pii in the browser: an Arabic and a Persian message, each item marked, and the redacted copy

Finding personal data in text the model never saw: MultiGraSCCo relaxed typed F1 (lenient) per language for decima-pii v0.2, openai/privacy-filter and Presidio

Decima is the judge, not the writer. Put it next to your LLM, agent or extraction pipeline to decide what is safe, what is true, where a request should go, and when the expensive model is really needed. It speaks TypeSafe's /v1/systemone format (choice, noul, score), so code written for Jev works after a one-line change, and it ships in Ollaya.

  • Local and cheap: int8 ONNX, about 20–50 ms per decision on one CPU core. No GPU, no API key, no data leaves.
  • Calibrated: 0.8 means right about 80 % of the time, so you can threshold, abstain, or escalate to a bigger model.
  • Order-proof: shuffling the options never changes the answer (0 %; other open models in our tests: 10–27 %).
  • Your options, at call time: any labels, any number. Multilingual backbone; evaluated in 20 languages.

Use it

Command line

decima "I was charged twice for my subscription" --question "Which team?" --choices billing,technical,sales
decima --file ticket.txt --preset triage --json
decima presets                                   # triage, routing, moderation, pii, guard, guard-rag, guard-output, guard-web, agent-gate, kg-judge, …

Python

from decima import Router

router = Router()                                  # downloads the int8 model on first use
answer = router.predict(
    {"message": "Someone logged into my account from another country and changed my password."},
    {"team":   {"type": "choice", "instructions": "Which team should handle this?",
                "criteria": {"billing": "charges and refunds", "tech": "bugs and errors", "security": "account takeover"}},
     "urgent": {"type": "noul", "instructions": "The customer needs help within the hour."}},
)
print(answer["answers"]["team"]["choice"], answer["answers"]["urgent"]["noul"])     # security 0.72

Personal data (decima-pii): find and redact names, phones, emails, national IDs, IBANs, cards, passports, addresses, dates of birth and IP addresses in Arabic, Persian, Urdu, Turkish and English.

pip install decima-ai
from decima import PII                             # also importable as DecimaPII

pii = PII.from_pretrained()                        # amyrmahdy/decima-pii v0.2, int8 ONNX, 148 MB, downloaded once
print(pii.redact("اسمي محمود الشمري ورقم جوالي ٠٥٥١٢٣٤٥٦٧"))   # اسمي [PERSON_NAME] ورقم جوالي [PHONE]
decima pii "سلام، من سارا احمدی هستم. کد ملی من ۰۰۱۲۳۴۵۶۷۸ است."     # spans, then the redacted text
cat letter.txt | decima pii --redact-only                          # or --json for {"spans": [...], "redacted": "..."}

pii.find(text) returns [{"start", "end", "label", "text"}]. This is not the pii preset: the preset asks decima-base a yes/no question ("does this text contain personal data, and which kind?"); decima.pii returns the exact spans so you can mask them. The model is pinned to tag v0.2.1 (decoder v2.1: a number right after a phone word such as جوالي counts as a phone); PII.from_pretrained(revision="v0.1") or decima pii --revision v0.1 gives the previous model with its exact output. In front of an LLM: LiteLLM guardrail · Presidio recognizer. pip install decima-pii installs the same package with a decima-pii command.

HTTP server (TypeSafe-compatible, binds to 127.0.0.1)

decima serve --model decima-agent --port 11436

The official typesafe-sdk works against it unchanged: TypeSafeClient(api_key="local", base_url="http://127.0.0.1:11436").

Integrations: LiteLLM proxy guardrail (decima-guard behind LiteLLM's decision_model guardrail, no code) · LiteLLM PII masking (decima-pii masks Arabic/Persian/Urdu/Turkish/English personal data before the model sees it) · Presidio recognizer (decima-pii under Presidio's entity names) · Claude Code hooks (secret and command gates, rules first, fail closed) · MCP server (decima mcp) · LangChain / LangGraph · Docker · examples · Colab quickstart

Presets

Preset Decides Model
triage team, urgency, sentiment of a ticket or message decima-base
routing cheapest LLM tier that can answer well: small / medium / frontier decima-base
moderation which policy a post breaks, and how badly decima-base
pii is there personal data, and of which kind (yes/no; to find and mask the values, use decima-pii) decima-base
guard prompt injection or jailbreak, harmful request, toxicity, which OWASP LLM risk decima-guard
guard-rag indirect injection in a document or tool result; answer grounded in the source; tool call beyond the request decima-guard
guard-output the reply leaks the system prompt or secrets; output unsafe for HTML / SQL / shell; harmful reply decima-guard
guard-web is this HTTP input an attack, and which kind (SQL injection, XSS, path traversal, …) decima-guard
guardrails prompt injection or jailbreak, personal data, toxicity before a prompt reaches an LLM decima-agent
agent-gate allow / ask / deny a shell command, secret in an edit, model tier for a task decima-agent
kg-judge is a fact asserted, hypothetical, denied or planned; are two records one entity; how two things relate decima-agent

Presets are JSON files in decima/presets; write your own with any questions.

Models

Model Size For
decima-agent 2.3 321M agent gates and knowledge-graph judgments; states up to 8,192 tokens
decima-guard 1.2 preview 321M OWASP LLM Top 10 and web-attack checks, injections in documents and tool results; English, Arabic, Persian
decima-pii 0.2 preview 140M personal-data detection and redaction; Arabic, Persian, Urdu, Turkish, English
decima-guard-small preview 140M the same checks, faster, a few points lower
decima-base 2.0 321M general decisions, multilingual
decima-base-clean 321M no non-commercial training data; truly zero-shot on BTZSC
decima-small 1.1 122M the smallest CPUs and the browser

How good is it

Honest numbers, on data the models never trained on unless stated.

Against the same-size open models, all re-run by us on one harness:

decima-base decima-small Laya Laya-multilingual Kev-0.8B
Parameters 321M 122M 421M 322M 753M
jabr/classifier-benchmark v2, 49 tasks (zero-shot) 0.673 0.616 0.583 — —
Kev's published protocol, 8 suites 0.790 0.762 0.681 0.580 0.794
Answer changes when options are shuffled 0 % 0 % 27 % 21 % 10 %

Decima trained on the train splits of some suites in Kev's protocol (test rows differ); jabr is zero-shot. The frontier is much higher: Jev scores 0.966 on jabr v2, and 4B–27B open models (Kev, SemIf-OpenJev) report Jev-level accuracy on their own tests. Decima wins on cost, speed and locality, not on hard open-ended judgment.

As a guard (decima-guard, int8, CPU), on frozen held-out sets that are public with every prediction (decima-guard-bench):

decima-guard ProtectAI prompt-injection-v2
Prompt injection / jailbreak, 6,532 examples: accuracy 0.902 0.784
Attacks missed, of 2,290 515 431
False alarms on 4,242 harmless messages 125 979
Ordinary Arabic chat messages, injection check: let through (589) 99.7% 25.1%
Ordinary Persian chat messages, injection check: let through (205) 100% 20.5%

Against Qwen3Guard-Gen-4B on the same rows: injection 0.902 vs 0.767, harmful requests 0.878 vs 0.911. On injections hidden in documents (Horizon-Labs suite, 10 public sets) it catches 53% of BIPIA's attacks and 63% of PIArena's, up from about 1 in 5 in 1.1. It still misses a fifth of real attacks translated into Arabic dialects, and on everyday spoken dialect (Casablanca test set) the full guard still blocks 20.0% of ordinary lines (1.0: 39.6%), mostly on the toxic question. Keep hard rules first, and see the limitations.

As a local stand-in for Jev in a published knowledge-graph pipeline (William Lyon's notebooks, same questions):

Jev decima-agent 2.2 (CPU)
Planted "maybe / denied / planned" facts caught 8/11 11/11
Entity matching (Beer, 450 pairs), AUC 0.992 0.972
Assertion gate over extracted edges, F1 0.404 0.368
Extraction ∪ relation selection, gated, F1 0.343 0.364

As a gate for a coding agent, on 40 cases written after training with no copies in any training data: decima-base 0.60 → decima-agent 2.2 0.85. Keep hard rules first; the hooks do.

It also plays games from text sensors, one decision per move: Snake, 42 apples a game (6 of 10 games alive at the 600-move limit); a side-scrolling platformer, 9 of 10 levels.

decima-agent playing Snake on CPU

Limitations

  • Fuzzy, knowledge-heavy or multi-step decisions belong to a bigger model. Use Decima's confidence to know when.
  • States are limited to 512 tokens (decima-base, decima-small), 2,048 (decima-guard) or 8,192 (decima-agent); longer input is refused, never silently cut.
  • A model can be confidently wrong. For safety gates, keep rules first and Decima second.
  • decima-base trained on some non-commercial datasets; see release/LICENSING.md before selling a product built on it.

Reproduce Decima's numbers

Every system's predictions, including Decima's and the competitors', are downloadable in decima-bench-predictions, with the scores and a text-free manifest of every item; its card has the commands to re-score every table without running a model. Decima's predictions can also be regenerated from the released weights and the frozen item builders:

uv sync
# item sets (calibration items per suite: kev/laya 300, decima 500, typed 1000, others none)
uv run python -m bench.items --suites 'kev/*'    --calib 300  --out runs/items/kev.jsonl
uv run python -m bench.items --suites 'laya/*'   --calib 300  --out runs/items/laya.jsonl
uv run python -m bench.items --suites 'decima/*' --calib 500  --out runs/items/decima.jsonl
uv run python -m bench.items --suites 'jevbench/*' 'typed/*' --calib 1000 --out runs/items/jevtyped.jsonl
uv run python -m bench.items --suites 'btzsc/*'               --out runs/items/btzsc.jsonl
# predictions (int8 ONNX, 1 thread) and scores, one set at a time
for s in kev laya decima jevtyped btzsc; do
  uv run python -m bench.predict --items runs/items/$s.jsonl --system onnx --checkpoint export/v1i-int8 \
      --threads 1 --out runs/preds/$s--decima.jsonl
  M=acc; [ $s = btzsc ] && M=macro_f1
  uv run python -m bench.score --items runs/items/$s.jsonl --metric $M --preds decima=runs/preds/$s--decima.jsonl
done
# audit numbers: overlap, confidence intervals, headline calibration
uv run python scripts/audit/overlap.py && uv run python scripts/audit/bootstrap.py && uv run python scripts/audit/calibration.py

export/v1i-int8 is the int8 ONNX export; the same files are onnx/int8/ in the model repository (hf download amyrmahdy/decima-small --include 'onnx/int8/*' --local-dir decima-small, then pass --checkpoint decima-small/onnx/int8). Parameter counts for every system: uv run python scripts/audit/params.py. Competitor predictors (Laya, Kev) run in their own environments: bench/external/. Training recipe, data builders and every experiment — including the ones that failed — are in the technical report.

Repository

decima/ ONNX runtime, Router, presets, CLI, server, MCP, LangChain helpers; model, export, int8 quantisation
integrations/ Claude Code hooks, MCP, LangChain
examples/ runnable examples and a Colab quickstart
train/ training (distillation + gold labels, crash-safe checkpoints)
teacher/ teacher data generation and gold-label builders
bench/ evaluation harness: one item format for every system, scorer, speed
docs/ technical report, evaluation audit, benchmarks

License & citation

Code and model: Apache-2.0. Synthetic dataset: CC BY 4.0. Training-data licences (some non-commercial) are disclosed in the model card and release/LICENSING.md. Predictions dataset: CC BY 4.0.

If you use Decima, please cite it (GitHub's "Cite this repository" reads CITATION.cff):

@misc{madani2026decima,
  title  = {Decima: A Small, Calibrated, Permutation-Invariant Decision Model via Late-Interaction Distillation},
  author = {Madani, A. M.},
  year   = {2026},
  howpublished = {\url{https://github.com/amyrmahdy/decima}},
  note   = {Models: \url{https://huggingface.co/amyrmahdy}}
}

Questions and problems: GitHub issues.

About

Small local judges and guards for LLM apps: calibrated decisions, prompt-injection and leak checks on a CPU. English, Arabic, Persian. Runs in your browser too.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages