Metadata-Version: 2.4
Name: prism-verify
Version: 1.1.0
Summary: Runtime adjudication service for agent workflows. Family-different, reasoning-stripped, multi-lens verification with replayable receipts.
Project-URL: Homepage, https://github.com/mcp-tool-shop-org/prism-verify
Project-URL: Repository, https://github.com/mcp-tool-shop-org/prism-verify
Project-URL: Issues, https://github.com/mcp-tool-shop-org/prism-verify/issues
Author-email: mcp-tool-shop <64996768+mcp-tool-shop@users.noreply.github.com>
License-Expression: MIT
License-File: LICENSE
Keywords: adjudication,agent,llm,mcp,verification
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.11
Requires-Dist: click>=8.0
Requires-Dist: cryptography>=42.0
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.0
Requires-Dist: ulid-py>=1.1
Provides-Extra: all
Requires-Dist: anthropic>=0.40; extra == 'all'
Requires-Dist: fastapi>=0.115; extra == 'all'
Requires-Dist: google-genai>=1.0; extra == 'all'
Requires-Dist: mcp>=1.0; extra == 'all'
Requires-Dist: openai>=1.50; extra == 'all'
Requires-Dist: sentencepiece>=0.2; extra == 'all'
Requires-Dist: torch>=2.0; extra == 'all'
Requires-Dist: transformers>=4.40; extra == 'all'
Requires-Dist: uvicorn>=0.30; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40; extra == 'anthropic'
Provides-Extra: dev
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: google
Requires-Dist: google-genai>=1.0; extra == 'google'
Provides-Extra: http
Requires-Dist: fastapi>=0.115; extra == 'http'
Requires-Dist: uvicorn>=0.30; extra == 'http'
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == 'mcp'
Provides-Extra: nli
Requires-Dist: sentencepiece>=0.2; extra == 'nli'
Requires-Dist: torch>=2.0; extra == 'nli'
Requires-Dist: transformers>=4.40; extra == 'nli'
Provides-Extra: openai
Requires-Dist: openai>=1.50; extra == 'openai'
Description-Content-Type: text/markdown

<p align="center">
  <a href="README.ja.md">日本語</a> | <a href="README.zh.md">中文</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.pt-BR.md">Português (BR)</a>
</p>

<p align="center">
  <img src="https://raw.githubusercontent.com/mcp-tool-shop-org/prism-verify/main/assets/prism-verify-logo.png" alt="prism-verify logo" width="500">
</p>

<p align="center">
  <a href="https://pypi.org/project/prism-verify/"><img src="https://img.shields.io/pypi/v/prism-verify" alt="PyPI"></a>
  <a href="https://www.npmjs.com/package/@mcptoolshop/prism-verify"><img src="https://img.shields.io/npm/v/@mcptoolshop/prism-verify" alt="npm"></a>
  <a href="https://mcp-tool-shop-org.github.io/prism-verify/"><img src="https://img.shields.io/badge/Landing_Page-live-22d3ee" alt="Landing Page"></a>
  <a href="https://mcp-tool-shop-org.github.io/prism-verify/handbook/"><img src="https://img.shields.io/badge/Handbook-docs-22d3ee" alt="Handbook"></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="License"></a>
</p>

# 

Runtime adjudication service for agent workflows. Family-different, reasoning-stripped, multi-lens verification with replayable receipts. **[Landing page &amp; handbook →](https://mcp-tool-shop-org.github.io/prism-verify/)**

## Install

Install the `prism` CLI (and the HTTP service) on your PATH:

```bash
uv tool install prism-verify        # or: pipx install prism-verify
```

Zero Python? Use the npm launcher (downloads + SHA256-verifies a prebuilt binary):

```bash
npx @mcptoolshop/prism-verify verify --artifact @file.py --intent "..." --caller-family openai
```

Or add it as a library — extras: `[anthropic]` `[openai]` `[google]` `[mcp]` `[http]` `[all]`:

```bash
uv add prism-verify
# or
pip install "prism-verify[all]"
```

## Quick start

Prism always verifies with a model family **different** from the caller's (Lock 1), so
configure at least one alternate-family provider. Generate an Ed25519 signing key (the default —
receipts are verifiable by anyone with the public key) so receipts can be written, or use
`PRISM_DEV=1` for local play:

```bash
prism keygen --out ~/.prism/signing_key.pem      # Ed25519 keypair (default signing)
export PRISM_SIGNING_KEY=~/.prism/signing_key.pem # or: export PRISM_DEV=1 (local play)
export ANTHROPIC_API_KEY="sk-ant-..."             # alt-family verifier for an OpenAI-family caller

prism verify \
  --artifact @myfile.py \
  --intent "Sort a list in O(n log n)" \
  --caller-family openai \
  --provider anthropic
```

> Legacy alternative: `export PRISM_SIGNING_SECRET="$(openssl rand -hex 32)"` signs receipts with
> HMAC instead (verifiable only by holders of that shared secret — see [Receipts](#receipts--signing-ed25519-verifiable-by-anyone)).

## Architecture

Prism enforces four architectural locks at the API contract:

1. **Family-different** — caller's model family is always excluded from verification
2. **Reasoning-stripped** — producer CoT is stripped before crossing the family boundary
3. **Multi-lens** — at least 3 independent lenses run in parallel
4. **Submodularity-aware** — refuses if lenses agree too much (collapsed signal)

For **citation** artifacts, a layered floor runs before the LLM groundedness lens — each
deterministic stage refuses what it can *prove*, else abstains:

- **Existence floor** — live arXiv/Crossref retrieval; a fabricated identifier is dropped, not reasoned about.
- **Numeric/unit floor** — a percentage swap, a unit-scale slip (42 milli- vs micro-arcsec), or a
  comparison-direction falsehood (5.0 < 5.8 ≠ "exceeded") is caught arithmetically.
- **Groundedness lens** — the family-different, reasoning-stripped LLM check against the retrieved abstract.
- **Orthogonal NLI floor** *(opt-in, `PRISM_NLI_FLOOR`)* — an encoder NLI cross-encoder vetoes a
  "supported" the LLM gave but a mechanistically-different model does not corroborate.

## Calibration & benchmark (`prism eval`)

prism is built to be **measured**, not just asserted. `prism eval` runs the lenses over a labeled
corpus and reports — on prism's own data — per-lens precision/recall/MCC, the inter-lens diversity
matrix (Krippendorff α + pairwise Cohen κ), submodular coverage-gain, verdict accuracy, and
confidence calibration (ECE/Brier), each with an honest confidence interval.

```bash
prism eval --split public --runs 3     # measure against the bundled corpus (needs a verifier)
prism eval --offline                    # deterministic mock (CI smoke; NOT a real measurement)
```

The v0.5 run (local `mistral-small:24b`) surfaced a real gap in a core lock: the runtime
submodularity metric (finding-set Jaccard ρ) reads **0.0 for every lens pair** while decision-level
Cohen κ is **0.73–0.81** — the `ρ ≤ 0.25` gate is *blind to the lens correlation κ reveals*. Finding
that is the whole point of the slice; full results + method in
[`eval/RESULTS.md`](eval/RESULTS.md) and [`design/07`](design/07-slice1-calibration.md).

## HTTP service

Run prism as an HTTP service (needs the `[http]` extra):

```bash
prism serve --host 127.0.0.1 --port 8000      # OpenAPI docs at /docs
```

| Endpoint | What it does |
|---|---|
| `POST /verify` | Verify an artifact (same contract as the CLI). Blocks within the budget; `Prefer: respond-async` + a `webhook` URL → `202`, verdict delivered to the (signed) webhook. |
| `GET /replay/{receipt_id}` | The signed receipt + `signature_valid`. |
| `POST /verify-receipt` | Verify a standalone receipt (cross-tool). |
| `GET /healthz` | Liveness + configured verifier families (no auth). |

Set API keys (hashed at rest) — prism is **fail-closed**, so `/verify` is refused until keys
are configured or you opt into local no-auth:

```bash
export PRISM_API_KEYS="<sha256(key1)>,<sha256(key2)>"   # callers send: Authorization: Bearer <key>
export PRISM_WEBHOOK_SECRET="<random>"                  # to sign async/escalate webhook deliveries
# local dev only:
export PRISM_HTTP_ALLOW_NO_AUTH=1
```

Errors are RFC 9457 `application/problem+json`; `POST /verify` honours an `Idempotency-Key`
header and a per-key rate limit (`429` + `Retry-After`). Async/escalate webhooks are
Standard-Webhooks-signed, SSRF-guarded (no internal/metadata targets), retried, and carry a
named cancel-event compensator.

## Receipts & signing (Ed25519, verifiable by anyone)

Every verification produces a signed, replayable receipt in `~/.prism/receipts.db`. v0.4 signs
new receipts with **Ed25519 (RFC 8032)** by default, so **a different tool can verify a prism
receipt with prism's public key — no shared secret**:

```bash
prism keygen --out ~/.prism/signing_key.pem    # generate an Ed25519 keypair
export PRISM_SIGNING_KEY=~/.prism/signing_key.pem
prism pubkey                                    # publish this public key + kid to consumers

# a consumer (e.g. role-os) verifies a receipt with ONLY the public key:
prism verify-receipt receipt.json --public-key prism-pub.pem
```

The signature covers the verdict, the pre/post-strip artifact hashes, the verifier model, the
submodularity matrix, the per-lens prompt hashes (byte-for-byte replayable), the citation
retrieval pins, and the signing `alg`/`kid`. Legacy **HMAC** receipts still verify (set
`PRISM_SIGNING_SECRET`); `PRISM_DEV=1` mints a dev key for local play. Prism **refuses to start**
the verify / replay / serve / MCP paths if no key is configured, rather than silently signing
with a publicly known key.

Manage stored receipts with the compensator commands:

```bash
prism receipt delete <receipt_id>
prism receipt prune --older-than 90d --yes
```

## Security & privacy

- **Threat model.** Prism reads the artifact + intent you pass and the verifier models'
  responses, and writes signed receipts to a local SQLite DB. It does **not** read your
  source tree, environment, or credentials beyond the provider API keys you supply via
  environment variables. Receipt signatures give **third-party verifiability** (Ed25519: a
  consumer verifies with the public key, no shared secret) but are not tamper-*proof* against a
  local-root attacker who can read the on-disk private key — that's the same ceiling as the HMAC
  secret. For genuine tamper-resistance, hold the key in an HSM and anchor receipts in a
  transparency log (the named hardening path).
- **HTTP surface.** `prism serve` binds loopback by default, is **fail-closed** (no `/verify`
  without API keys), hashes keys at rest, and **SSRF-guards** caller-supplied webhook URLs
  (no internal/link-local/metadata targets). It runs caller-supplied artifacts through a model;
  an artifact may *attempt* prompt injection but cannot change the verdict schema or exfiltrate
  prism's provider keys.
- **No telemetry.** Prism sends requests only to the model providers you configure
  (Anthropic / OpenAI / Google / local Ollama). Nothing else.
- Full policy: [SECURITY.md](SECURITY.md).

## License

MIT
