Skip to main content

Sooth

LLMs generate. Sooth verifies.

Claim-by-claim fact-checking for AI output, designed for CI. Sooth checks every sentence in a draft against your source material and returns PASS / FAIL / REVIEW with calibrated probabilities and the exact source line behind each verdict.

PyPI Python License: MIT CI

See it catch a hallucination

pip install sooth
sooth demo        # no API key needed

Real output — seven claims in an AI-written news summary, three numbers quietly wrong:

# Sooth

**PASS 2 · FAIL 3 · REVIEW 1 · UNCHECKABLE 1** — threshold 0.70

| # | Claim | Verdict | P | Why (P distribution) | Evidence |
|---|-------|---------|---|----------------------|----------|
| 1 | Aturan baru BEI menurunkan batas bawah harga saham menjadi Rp 1 per saham mulai 28 September 2026. | ✅ PASS | ████████ 1.00 | supports 1.00 / not_found 0.00 / contradicts 0.00 · details 0.98 | `examples/news-1.md:3` "Saham-saham Grup Bakrie kembali menjadi sorotan menjelang…" |
| 2 | Menurut analis Bumiputera Sekuritas, aturan ini berlaku untuk seluruh emiten di BEI. | ✅ PASS | ████████ 1.00 | supports 1.00 / not_found 0.00 / contradicts 0.00 · details 0.82 | `examples/news-1.md:7` "Ia menyebut aturan ini berlaku untuk seluruh saham di BEI…" |
| 3 | BNBR baru menuntaskan rights issue bernilai besar di harga Rp 33. | ❌ FAIL | ████████ 1.00 | supports 0.00 / not_found 0.00 / contradicts 1.00 · details 0.01 · missing #s: 33 | `examples/news-1.md:25` "Saham ini juga baru menyelesaikan rights issue dalam juml…" |
| 4 | Saham VIVA disuspensi di harga Rp 50. | ❌ FAIL | ████████ 1.00 | supports 0.00 / not_found 0.00 / contradicts 1.00 · details 0.02 |  |
| 5 | BUMI hanya perlu turun sekitar 10% untuk menyentuh level Rp 50. | ❌ FAIL | ████████ 1.00 | supports 0.00 / not_found 0.00 / contradicts 1.00 · details 0.01 · missing #s: 10 | `examples/news-1.md:23` "Adapun PT Bumi Resources Tbk (BUMI) di sekitar Rp192 haru…" |
| 6 | BEI juga menetapkan batas atas harga saham Rp 5.000 per saham di pasar reguler. | ⚠️ REVIEW | ████████ 1.00 | supports 0.00 / not_found 1.00 / contradicts 0.00 · details 0.02 · missing #s: 5.000 |  |
| 7 | Para investor ritel sangat senang dengan aturan baru ini. | ➖ UNCHECKABLE | ██░░░░░░ 0.25 | P(checkable)=0.25 |  |

## Needs review

- line 13: BEI juga menetapkan batas atas harga saham Rp 5.000 per saham di pasar reguler.
- line 15: Para investor ritel sangat senang dengan aturan baru ini.

Every verdict carries its probability distribution and the source span it was judged against. When Sooth is unsure, it says REVIEW instead of guessing.

Why

AI writes fast, nobody checks. Claims ship wrong — usually a number, a hedge, or a name that drifted. Asking another LLM "is this right?" just produces more prose.

Sooth takes a different bet: the model makes typed judgments, code makes the decision. Every rule that turns a probability into a verdict is a readable line of Python, not a prompt.

Install

pip install sooth
export TYPESAFE_API_KEY=...       # get one at console.typesafe.ai

Usage

sooth --source docs/policy.md --source tickets/t123.md --text draft-reply.md

# CI-friendly exit codes
sooth --source policy.md --text draft.md --format plain
#   0 = clean  ·  1 = any FAIL  ·  2 = any REVIEW  ·  3 = usage/config error

# Options
#   --confidence T   REVIEW below this confidence (default 0.7)
#   --format md|plain
#   -o FILE          write report to file
#   --log FILE       append full judgment trace (one JSONL line per run)

Use it in CI as a quality gate for generated content:

- name: Verify AI output
  uses: naufalhilmiaji/sooth@v0.2.3
  with:
    source: docs/policy.md
    text: generated-reply.md
  env:
    TYPESAFE_API_KEY: ${{ secrets.TYPESAFE_API_KEY }}

source takes newline-separated paths when you have several documents. The step fails the build on any FAIL — and on any REVIEW, so add continue-on-error: true if you only want to block on hard contradictions. The full report is appended to the job summary.

Prefer plain shell? sooth --source policy.md --text draft.md gives the same exit codes.

How it works

  1. Draft is split into claims (one sentence each).
  2. Each claim gets four questions to Jev, fanned out in parallel batches: is this checkable?, does the source support it? (supports / contradicts / not_found), do all details match exactly?, and which source span is the evidence?
  3. Verdicts are mapped in code: uncheckable → UNCHECKABLE; low confidence → REVIEW; then PASS / FAIL. Safeguards demote PASS to REVIEW when details drift or claim numbers are absent from the source (checked in plain code).
  4. The report shows the full probability distribution per claim — not just a label.

The decision logic lives in src/sooth/verify.py in a dozen readable lines. Change thresholds and rules there, not in prompts.

Judgments come from Jev (TypeSafe System One), which returns typed distributions instead of generated prose.

Why not just use an LLM judge?

Not claiming Sooth is universally more accurate. Claiming it gives you architectural guarantees a prompt cannot:

Sooth Generic LLM judge
Claim-level verification ✅ Sometimes
Source span behind each verdict ✅ Sometimes
PASS / FAIL / REVIEW ✅ fixed vocabulary Generated labels
Probability distribution ✅ Usually none
Verdict rules in readable code ✅ Prompt-dependent
CI exit codes ✅ ❌
Audit log (--log JSONL) ✅ DIY

Who it's for

Developers building systems that generate text from trusted material:

  • RAG pipelines — retrieved the right document, still wrote the wrong number
  • AI agents — before an agent's reply reaches a human
  • Support / ops copilots — policy-backed answers, checked against the policy
  • Report & summary generation — figures that must match the source
  • Compliance workflows — evidence trail for every claim, not vibes

Known limits (alpha)

  • Safeguards catch most drift and smuggling: claim numbers absent from the source demote PASS to REVIEW, and a detail-match gate flags altered hedges ("about 74%" → "over 74%"). Not perfect — read the Why column before trusting a verdict.
  • Derived numbers (totals, values computed outside the source) look "missing" and land in REVIEW.
  • Source + questions must fit ~64k tokens — split long documents yourself.

Development

pip install -e ".[dev]"
python3 tests/test_core.py     # pure checks, no network
pytest                         # same suite
bash tests/smoke.sh            # live smoke (needs TYPESAFE_API_KEY)
PYTHONPATH=src python3 tests/calibrate.py   # live calibration, 30 labeled claims

Docs: PRD · Design · Testing

Roadmap

  • v0.2.3 shipped: GitHub Action — CI quality gate in one uses: line
  • v0.2.2 shipped: sooth demo (offline, no API key)
  • v0.2.1 shipped: source-span evidence, published on PyPI
  • later: hosted web app — paste UI, history, team review queues

License

MIT © Naufal Hilmiaji. Powered by TypeSafe / Jev.

Release files for sooth 0.2.3

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

Source distribution (sdist)

Source distribution for sooth 0.2.3
File Size Uploaded
sooth-0.2.3.tar.gz 32.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sooth 0.2.3
File Interpreter ABI Platform
sooth-0.2.3-py3-none-any.whl Python 3 none any Details

Total release size: 48.1 kB

Release files / sooth-0.2.3.tar.gz

Download URL sooth-0.2.3.tar.gz
Size 32.8 kB
Tags Source
SHA-256 checksum
How to use checksums
a223c65c5ae74828d0900a20e4f4644fd63a5e93dcb2cf479df93a83a49aaf5b
BLAKE2b-256 checksum
How to use checksums
4d55fd924114b4dcaf74f2bdcccf9d2fe33a2871d4c119ed5540a2c74ea45b8f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / sooth-0.2.3-py3-none-any.whl

Download URL sooth-0.2.3-py3-none-any.whl
Size 15.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
90da2310d93223510633cdf885a15271d357995bd6b8ab210563fecb2d9335cb
BLAKE2b-256 checksum
How to use checksums
4167f7a08a9a4e9936693c925ac19528822ad13f346fc76e8af1d621a2df5856
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

0.2.3 This release

2 release files

0.2.2

2 release files

0.2.1

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