# TruthLens π
[](https://crates.io/crates/truthlens)
[](https://docs.rs/truthlens)
**AI Hallucination Detector β Formally Verified Trust Scoring for LLM Outputs**
Analyze AI-generated text for hallucination risk. No API keys needed. No LLM calls required. Fast, local, formally verified, and color-coded terminal output.
**Published package:** <https://crates.io/crates/truthlens>
**API docs:** <https://docs.rs/truthlens>
## Quick Start
### Install as CLI
```bash
cargo install truthlens
```
### Usage
```bash
# Analyze text directly
truthlens "Einstein invented the telephone in 1876."
# Trust: 49% [ββββββββββββββββββββββββββββββ] HIGH
# π΄ Claim 1: 49% β specific verifiable claim β verify independently
# JSON output (for scripts/API integration)
truthlens --json "Python 4.0 has quantum computing support."
# Pipe from file or other commands
cat ai_response.txt | truthlens
# Pipe from clipboard (macOS)
# Analyze ChatGPT/Claude output saved to file
# Compare multiple AI responses for contradictions
truthlens --consistency "response 1" "response 2" "response 3"
# Run built-in demo examples
truthlens --demo
```
### Use as a Rust library
```rust
use truthlens::analyze;
let report = analyze("Einstein was born in 1879 in Ulm, Germany.");
println!("Trust: {:.0}% β {}", report.score * 100.0, report.risk_level);
// Trust: 52% β HIGH
// Access per-claim breakdown
for claim in &report.claims {
println!(" {} β {}", claim.text, claim.trust.risk_level);
}
// Access trajectory analysis
println!("Pattern: {}", report.trajectory.pattern);
println!("Damping: ΞΆβ{:.2}", report.trajectory.damping_estimate);
// JSON serialization
let json = serde_json::to_string_pretty(&report).unwrap();
```
### Multi-response consistency check (v0.3)
Paste N responses to the same prompt β TruthLens detects contradictions between them.
```rust
use truthlens::check_consistency;
let report = check_consistency(&[
"Einstein was born in 1879 in Ulm, Germany.",
"Einstein was born in 1879 in Munich, Germany.", // β contradiction
"Einstein was born in 1879 in Ulm, Germany.",
]);
println!("Consistency: {:.0}%", report.consistency_score * 100.0);
// Consistency: 75%
// Contradictions detected
for c in &report.contradictions {
println!("β οΈ {} vs {} β {}", c.claim_a, c.claim_b, c.conflict);
}
// β οΈ "Ulm, Germany" vs "Munich, Germany"
// Claims unique to one response (potential hallucination)
for u in &report.unique_claims {
println!("π Unique to response {}: {}", u.response_idx, u.text);
}
```
```bash
# CLI: compare multiple responses as separate arguments
truthlens --consistency \
"Einstein was born in 1879 in Ulm, Germany." \
"Einstein was born in 1879 in Munich, Germany." \
"Einstein was born in 1879 in Ulm, Germany."
# Consistency: 70% [ββββββββββββββββββββββββββββββ]
# β Contradictions:
# Response 1 vs 2: "Ulm, Germany" vs "Munich, Germany"
# β
Consistent claims:
# 3/3 agree: einstein was born in: 1879
# JSON output
truthlens --consistency --json "resp1" "resp2" "resp3"
# Pipe JSON array from stdin
echo '["Python was created in 1991.", "Python was created in 1989."]' \
| truthlens --consistency
```
### Use as a Python library (v0.5)
```bash
pip install truthlens
```
```python
from truthlens import analyze, check_consistency, extract_claims, extract_entities
# Analyze text for hallucination risk
report = analyze("Einstein was born in 1879 in Ulm, Germany.")
print(f"Trust: {report['score']:.0%} β {report['risk_level']}")
# Per-claim breakdown
for claim in report["claims"]:
print(f" {claim['text']} β {claim['trust']['risk_level']}")
# Multi-response consistency check
result = check_consistency([
"Einstein was born in 1879 in Ulm.",
"Einstein was born in 1879 in Munich.",
])
print(f"Consistency: {result['consistency_score']:.0%}")
# Extract atomic claims
claims = extract_claims("Python was created in 1991. It is widely used.")
# Extract named entities
entities = extract_entities("Marie Curie won the Nobel Prize in 1903.")
print(entities) # ['1903', 'Marie Curie']
```
### Install via Snap (v0.5)
```bash
# Install from Snap Store (Ubuntu/Linux)
sudo snap install truthlens
# Analyze text
truthlens "Einstein invented the telephone in 1876."
# JSON output
truthlens --json "Python was created in 1991."
# Compare multiple AI responses
truthlens --consistency \
"Einstein was born in Ulm." \
"Einstein was born in Munich."
# Entity verification (requires network)
truthlens --verify "Marie Curie won the Nobel Prize in 1903."
# Run demo examples
truthlens --demo
# Show help
truthlens --help
```
### Entity verification (v0.4)
Cross-reference named entities (people, places, dates) against Wikidata to boost or reduce trust scores.
```bash
# Install with verification support
cargo install truthlens --features verify
# Verify entities in a claim
truthlens --verify "Albert Einstein was born in 1879 in Ulm, Germany."
# Trust: 67% [ββββββββββββββββββββββββββββββ] MEDIUM
# π Verified: Albert Einstein (Q937) β birth year: 1879, birthplace: Ulm β
# Combine with JSON output
truthlens --verify --json "Marie Curie won the Nobel Prize in 1903."
```
> **Note:** The `--verify` flag requires the `verify` feature (adds the `ureq` HTTP dependency).
> Without `--features verify`, TruthLens works fully offline with no network dependencies.
```toml
# Cargo.toml
[dependencies]
truthlens = "0.5"
# With entity verification
# truthlens = { version = "0.5", features = ["verify"] }
```
## What It Does
TruthLens decomposes AI text into atomic claims and scores each for hallucination risk using linguistic signals β **no LLM calls, no API keys, no external dependencies**.
```
Input: "Python 4.0 was released in December 2025 with native quantum computing support."
Output: π΄ Trust: 49% [HIGH]
β specific verifiable claim β verify independently
β overconfident language without hedging
```
## How It Works
### 1. Claim Extraction
Text β atomic sentences β each is an independent claim to evaluate.
### 2. Signal Analysis (per claim)
| **Confidence** | Overconfident language without hedging (hallucination red flag) | 35% |
| **Hedging** | Uncertainty markers ("might", "possibly") β correlates with lower hallucination | 25% |
| **Specificity** | How concrete/verifiable the claim is (numbers, names, dates) | 20% |
| **Verifiability** | Whether the claim contains fact-checkable entities | 15% |
| **Consistency** | Multi-sample agreement (optional, requires LLM) | 5% |
### 3. Trust Score
Signals are aggregated into a single trust score in **[0.0, 1.0]**:
| 0.75β1.0 | β
LOW | Likely factual or appropriately hedged |
| 0.55β0.74 | β οΈ MEDIUM | Some uncertain claims, verify key facts |
| 0.35β0.54 | π΄ HIGH | Multiple suspicious claims, verify everything |
| 0.0β0.34 | π CRITICAL | Likely contains hallucinations |
### 4. Passage Scoring
Passage score = 70% average + 30% worst claim. One bad claim drags down the whole passage.
## Key Design Decisions
- **No LLM required** β linguistic analysis only. Fast (microseconds), private (local), free.
- **Hedging = good** β unlike most "confidence detectors", we score hedged claims HIGHER. A model that says "might" is better calibrated than one that states falsehoods with certainty.
- **Specificity is double-edged** β specific claims are more useful but also more damaging if wrong. We flag them for independent verification.
- **Formally verified** β Lean 4 proofs guarantee score bounds, monotonicity, and composition properties.
## What's Proven (Lean 4)
### Score Bounds
- `signal_nonneg` β all signals β₯ 0
- `weighted_contrib_bounded` β wΒ·s β€ wΒ·max when s β€ max
- `clamped_score_in_range` β final score β [0, 100] after clamp
- `truthlens_weights_sum` β weights sum to 100%
### Monotonicity
- `signal_increase_improves_score` β improving a signal improves the score
- `total_score_improves` β better signal + same rest = better total
- `good_claim_improves_passage` β adding a good claim raises the average
### Composition
- `passage_score_bounded` β 70%Β·avg + 30%Β·min β€ 100%Β·max
- `passage_at_least_worst` β passage score β₯ 30% of worst claim
- `score_order_independent` β claim order doesn't affect passage score
- `score_deterministic` β same inputs β same output (functional purity)
### Trajectory (v0.2)
- `adjusted_score_bounded` β score + modifier stays bounded after clamp
- `transitions_bounded` β direction changes β€ n_claims β 2
- `damping_positive` β damping estimate is always positive (stable system)
- `penalty_still_nonneg` β score after penalty β₯ 0 after clamp
### Consistency (v0.3)
- `consistency_bounded` β consistency score β [0, 100] after clamp
- `contradictions_bounded` β contradiction count β€ comparison pairs
- `agreement_ratio_valid` β agreement β€ total responses
- `agreeing_response_improves` β adding agreement increases count
- `contradiction_symmetric` β if A contradicts B, B contradicts A
- `unique_bounded` β unique claims β€ total claims
### Verification (v0.4)
- `verification_modifier_bounded` β modifier β [0, 15] (scaled) after clamp
- `combined_modifier_bounded` β combined modifier β [-15, +15]
- `adjusted_score_with_verification` β score + verification modifier stays in [0, 100]
- `adjusted_score_with_both` β score + trajectory + verification modifier stays in [0, 100]
- `entity_partition` β verified + contradicted + unknown = total
- `verified_contradicted_disjoint` β verified + contradicted β€ total
- `empty_verification_neutral` β no entities β zero modifier
- `all_verified_max` β all verified β maximum positive modifier
- `all_contradicted_max` β all contradicted β maximum negative modifier
- `more_verified_improves` β adding verified entity increases modifier (monotonic)
- `more_contradicted_worsens` β adding contradicted entity decreases modifier (monotonic)
## Examples
### Factual text
```
"Albert Einstein was born on March 14, 1879, in Ulm, Germany."
β π΄ 52% HIGH β specific verifiable claim, verify independently
```
### Well-hedged passage (β
LOW risk)
```
"Climate change might be linked to increased hurricane frequency.
Some researchers believe ocean temperatures could affect storm intensity.
It is possible that sea levels will rise over the next century."
β β
60% LOW β Trajectory: FLAT LOW (consistently cautious), trust bonus +10%
```
### Single hedged claim
```
"Climate change might be linked to increased hurricane frequency."
β β οΈ 65% MEDIUM β appropriately hedged
```
### Overconfident hallucination
```
"The Great Wall is exactly 21,196.18 kilometers long."
β π΄ 52% HIGH β overconfident without hedging; highly specific
```
### Vague filler
```
"Various factors contribute to the situation."
β π΄ 40% HIGH β vague claim with low specificity
```
## JSON Output
```json
{
"score": 0.49,
"risk_level": "High",
"summary": "1 claims analyzed. 1 high-risk claims detected.",
"claims": [
{
"text": "Einstein invented the telephone in 1876.",
"trust": {
"score": 0.49,
"signals": {
"confidence": 0.5,
"specificity": 0.3,
"hedging": 0.5,
"verifiability": 0.7,
"consistency": null
},
"risk_level": "High"
}
}
]
}
```
## Repository Structure
```
truthlens/
βββ rust/ # Core library + CLI
β βββ src/
β β βββ lib.rs # Public API: analyze(), check_consistency()
β β βββ claim.rs # Claim extraction + linguistic analysis
β β βββ scorer.rs # Trust scoring + signal aggregation
β β βββ trajectory.rs # Confidence trajectory analysis (v0.2)
β β βββ consistency.rs # Multi-response consistency checker (v0.3)
β β βββ entity.rs # Entity cross-reference with Wikidata (v0.4)
β β βββ main.rs # CLI: analyze, --consistency, --verify, --demo
β βββ tests/
β β βββ integration.rs # End-to-end integration tests
β βββ Cargo.toml
βββ python/ # Python bindings (v0.5)
β βββ src/lib.rs # PyO3 wrapper
β βββ truthlens/ # Python package
β β βββ __init__.py # Re-exports + docstrings
β β βββ __init__.pyi # Type stubs (PEP 561)
β β βββ py.typed # PEP 561 marker
β βββ tests/
β β βββ test_truthlens.py # Python test suite
β βββ Cargo.toml # cdylib crate
β βββ pyproject.toml # maturin build config
βββ lean/ # Formal proofs
β βββ TruthLens/
β β βββ ScoreBounds.lean # Score β [0, 1], weight sum, clamp
β β βββ Monotonicity.lean # Better signals β better score
β β βββ Composition.lean # Passage aggregation properties
β β βββ Trajectory.lean # Trajectory modifier bounds + correctness
β β βββ Consistency.lean # Contradiction bounds, agreement, symmetry
β β βββ Verification.lean # Entity verification modifier bounds (v0.4)
β βββ lakefile.lean
βββ snap/ # Snap package config (v0.5)
β βββ snapcraft.yaml
βββ bridge/ # Lean β Rust mapping (coming)
βββ README.md
```
## Build
```bash
# Rust (default β no network dependencies)
cd rust
cargo test # unit + doc tests
cargo test --features verify # includes entity verification tests
# Python bindings
cd python
pip install maturin pytest
maturin develop # build + install locally
pytest tests/ -v # run Python tests
# Lean
cd lean
lake build # 6 proof modules, zero sorry
```
## Roadmap
- [x] **v0.1** β Linguistic analysis: claim extraction, hedging detection, specificity scoring
- [x] **v0.2** β Confidence trajectory: detects oscillating, flat, or convergent confidence patterns using second-order dynamical system modeling
- [x] **v0.3** β Multi-response consistency, CLI (`cargo install truthlens`), colored output
- [x] **v0.4** β Entity cross-reference: verify extracted entities against Wikidata SPARQL (optional `verify` feature flag)
- [x] **v0.5** β Python bindings (PyO3) β `pip install truthlens`, Snap package
- [ ] **v0.6** β Claude Code / MCP integration: local stdio MCP server, `analyze_text` + `analyze_file` tools, auto-checks AI text claims in-context
- [ ] **v0.7** β VS Code extension: analyze selection/file, inline diagnostics for docs/comments/markdown, status bar trust score
- [ ] **v0.8** β CI/CD integration: GitHub Action, fail builds on low trust score, policy thresholds (`--min-score`)
- [ ] **v0.9** β Browser extension: highlight claims in ChatGPT/Claude UI with inline trust indicators
- [ ] **v1.0** β TruthLens Platform: unified trust layer across CLI, VS Code, MCP, and CI pipelines with policy enforcement and fully local execution
- [ ] **v2.0** β Enterprise Trust System: policy engine, dashboard, audit & compliance reporting, enterprise API, team governance
### Design Principles (all versions)
- **Zero API calls by default** β every version works offline, locally, for free
- **Formally verified** β Lean 4 proofs for all scoring properties
- **Hedging = trustworthy** β a model that says "might" is more honest than one stating falsehoods with certainty
- **Fast** β microsecond analysis, no model inference required
## Why TruthLens?
Every existing hallucination detector either requires multiple LLM API calls (expensive, slow) or access to model logprobs (grey-box only). TruthLens works on **any AI output** with **zero API calls** β you paste text, you get a trust score. And the scoring properties are **formally proven** in Lean 4, which nobody else does.
## License
Apache-2.0