// code.noirebox.eu — the technical reference. The marketing page is gone on purpose.
NoireBox v0.21.0
A tamper-evident journal for AI agents: every event hash-chained (SHA-256), signed (Ed25519), append-only on SQLite, anchored to external RFC 3161 witnesses — plus a pluggable guardrail and a standalone verifier a third party can run offline, without trusting you.
pip install noirebox
source · SPECS.md · threat model · changelog · 27 ADRs
§Overview
NoireBox is a single FastAPI service + Python package that gives an AI-agent
system two guarantees: provable traceability (every event
sealed in a journal a third party can verify offline) and
input filtering (transcripts scanned before they reach the
agent, verdicts sealed as events). The journal is domain- and
language-agnostic — an event is a type and a payload — which is why it fits
any stack. The verification never contacts the server: the export plus
openssl is the whole trust surface.
transcript ──▶ guardrail (regex | ml | tiered llm) ──▶ agent (any)
│ incident │ llm_call / llm_output
▼ ▼
┌───────────────── TAMPER-EVIDENT JOURNAL ─────────────────┐
│ SQLite append-only · SHA-256 chain · Ed25519 │
└───────────────────────────┬─────────────────────────────┘
GET /api/v1/export │ GET /api/v1/attestation
▼
export.json ──▶ verifier.py (third party, offline) → exit 0|1|2
Properties
- Append-only — no UPDATE, no DELETE exist; sealing costs 0.17 ms/event
- Located tamper detection — rewrite, insert or delete fails verification at the exact
seq - Non-repudiation — Ed25519 over each
event_hash; the key never has to leave your infrastructure - External time — RFC 3161 anchoring: only a 32-byte head hash ever leaves
- Offline verification — the verifier speaks JSON +
openssl ts, no API to trust - Undecidable ≠ clean — unverifiable states are named first-class, never folded into OK
Not
- Not a blockchain — one issuer, one verifier, no consensus tax (ADR 001)
- Not an observability tool — Langfuse-style logs are for debugging and stay rewritable; this is for proof
- Not a certification — a building block that states its perimeter instead of overselling it (threat model)
- Not multi-tenant SaaS — self-hosted, zero telemetry, one SQLite file per journal
§Install
Python ≥ 3.11, MIT, zero telemetry. The ML guardrail engine ships inside the wheel (FR + EN detectors, ~250 KB each) — no model download at runtime.
pip install noirebox # core: journal + API + guardrail + verifier deps pip install noirebox[pdf] # + PDF attestation export (reportlab) pip install noirebox[hsm] # + PKCS#11 key custody (python-pkcs11)
Or Docker (image includes the ML engine):
docker run -p 8768:8768 ghcr.io/noirebox/noirebox:latest # API + OpenAPI docs on http://127.0.0.1:8768/docs — data persists in ./data
Or from source (venv + deps + tests + API):
git clone https://github.com/noirebox/noirebox && cd noirebox ./start.sh
Environment variables
| Variable | Effect |
|---|---|
| NOIREBOX_DB | Journal path (default: data/noirebox.db, or nearest .noirebox/ directory) |
| NOIREBOX_CLIENTS | id:secret,… — enables JWT bearer auth + per-client rate limit. Unset = open API. A SET-but-unparseable value is fail-closed since 0.21.0 (NB-01) |
| NOIREBOX_METADATA_AUTH | 1 moves the metadata routes behind the bearer token (verification routes can never be locked) |
| NOIREBOX_TSA_PROFILES | Multi-TSA anchoring: several independent witnesses behind one anchor (ADR 008/009) |
| NOIREBOX_TSA_URL | Legacy single-TSA endpoint (still works) |
| NOIREBOX_JUDGE_MODEL | Local LLM judge for the tiered engine (default qwen2.5-coder:3b via Ollama) |
| NOIREBOX_HSM_PIN | PKCS#11 token user PIN — prefer over argv (an argv PIN sits in the process table) |
§Quickstart
# 1 — run the API noirebox serve # http://127.0.0.1:8768 — interactive OpenAPI at /docs # 2 — seal an event (auth off by default; enable with NOIREBOX_CLIENTS) curl -X POST http://127.0.0.1:8768/api/v1/events \ -H 'Content-Type: application/json' \ -d '{"type":"llm_call","payload":{"model":"gpt-x","prompt_sha256":"…"}}' # 3 — anchor the chain head with an external TSA witness (RFC 3161) curl -X POST http://127.0.0.1:8768/api/v1/anchors # 4 — export the full dossier curl -s http://127.0.0.1:8768/api/v1/export > export.json # 5 — verify as a third party, offline (pip install noirebox is enough) python verifier/verifier.py export.json # exit 0 = intact & witnesses verified · 1 = broken · 2 = anchoring unproven
One-command demos: make demo (full scene: scan → journal → auditor → caught tampering) · make demo-mcp · make demo-fleet · make demo-tamper-style standalone scripts in demo/.
§Data model
An Event is the only write shape. Types are free-form strings (1–64 chars) — llm_call, llm_output, incident, eval, anchor are conventions, not a closed enum.
| Field | Type | Constraint |
|---|---|---|
| seq | int | ≥ 1, no gaps, UNIQUE |
| ts | str | ISO 8601 UTC, milliseconds |
| type | str | 1–64 chars, free-form |
| payload | object | arbitrary JSON (GDPR minimization = caller's responsibility) |
| prev_hash | 64 hex | SHA-256 of event seq-1 ("0"×64 genesis) |
| event_hash | 64 hex | SHA-256 of the canonical serialization of {seq, ts, type, payload, prev_hash}, UNIQUE |
| signature | 128 hex | Ed25519 over bytes.fromhex(event_hash), instance key |
Canonical serialization — any third-party reimplementation must produce the same bytes:
json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
The key is Ed25519, PEM PKCS8, chmod 600, created at database init (<db>.key). The public key alone is enough to verify. Where that key lives is pluggable — see custody.
§HTTP API
FastAPI, 12 routes, interactive OpenAPI at /docs and /redoc; machine-readable spec: docs/openapi.json. Base http://127.0.0.1:8768. 🔒 = behind the bearer token when auth is enabled; verification routes are open by design.
| Route | Auth | Body / query | Response |
|---|---|---|---|
| GET /health | — | — | liveness |
| POST /api/v1/token | — | {client_id, client_secret} | JWT HS256, 1 h expiry |
| POST /api/v1/events | 🔒 | {type, payload} → 201 | the sealed event |
| GET /api/v1/events | 🔒 | ?limit&offset&since_seq | paginated list; since_seq = live-tail cursor (indexed, no replay) |
| GET /api/v1/activity | — | — | day → sealed-event count (aggregate only) |
| GET /api/v1/verify | — | — | {valid, nb_events, first_error} |
| POST /api/v1/transcripts/scan | 🔒 | {meeting_id, text, engine, lang} → 201 | incidents + journal entry |
| GET /api/v1/attestation | — | — | signed summary (head hash + signature) |
| GET /api/v1/attestation.pdf | — | — | A4 PDF for the DPO |
| POST /api/v1/attestation/verify | — | attestation | {valid} |
| POST /api/v1/anchors | 🔒 | — → 201 | {anchor_event_seq, anchored_head_seq, anchored_head_hash, tsr_bytes} |
| GET /api/v1/export | 🔒 | — | {format_version, service, public_key, events, attestation} |
Auth (ADR 004) — enabled only if NOIREBOX_CLIENTS is set: 1-hour JWT HS256, 60 req/min per client (sliding window, 429 + Retry-After), constant-time secret comparison. Errors: 401 (missing/invalid token) · 422 (Pydantic) · 429 (quota) · 503 (engine unavailable, actionable message) · verification failures always carry the exact seq.
§Receipts & sealed payload schemas
Beyond free-form events, subsystems seal versioned payload schemas into the same journal. Each schema version is a contract; the reconciliation layer assembles verdicts from them.
| Schema | Sealed by | Carries |
|---|---|---|
| receipt/0.2.2 | any writer | judged_by (an llm judge requires spec_hash — it read its sealed spec, or the seal refuses), reason, optional requirement_ref |
| writer/0.1 | the registrar | known-writers registry: public_hex → domain, declared_by — resolved against the PINNED registrar key (out-of-band); non-registrar entries can't vote; a key under two domains = registry_duplicate_undecidable, never first-wins |
| registry-disclosure/0.2 | the report | registrant + evidence grade — disclosure, never violation; never touches clean_pass |
| retention/0.1 | noirebox seal-retention | prune / migrate / policy-change / restore — retention changes are custody events journaled like any other, not ops-layer edits |
Named states, never silence: unverified_label · independence_undecidable · label_llm_call_mismatch · registry_duplicate_undecidable · scope_check_not_run — an undecidable outcome is never reported as clean, and a skipped check is reported as skipped.
The doctrine behind these schemas — who may judge what, and which verdict outranks which — is written up as the authority ladder (ADR 019–022).
§Verification contract
verifier/verifier.py — strict order, first failure wins, never contacts the server (openssl only):
seqof event n equals n — no gaps, no duplicatesprev_hashequalsevent_hashof event n−1event_hashequals the recomputed canonical SHA-256signaturevalid for the export public key- Attestation:
head_seq= event count,head_hash= lastevent_hash, signature valid on the canonical summary - Each
anchorevent: referenced head consistent with the chain, RFC 3161 token verified (openssl ts -verify) against that hash and the embedded TSA certificate
| Exit | Meaning |
|---|---|
| 0 | INTACT — chain valid and every witness token verified |
| 1 | BROKEN — first chain/signature break + exact location |
| 2 | ANCHORING UNPROVEN — a witness token could not be verified (missing openssl/ots, timeout). Report field: unverifiable_witnesses. Accept explicitly with --allow-unverified-witnesses (0.21.0, NB-02: undecidable is never clean — including inside the tool that enforces the doctrine) |
TSA roots for public witnesses are pinned in the repository (verifier/tsa_roots/) — the auditor never trusts a certificate the operator ships. The auditing machine needs pip install noirebox, nothing else.
§Key custody & signing
Every signer answers the same interface — .sign() + .public_hex() — so custody can move without touching callers:
| Signer | Key lives | Notes |
|---|---|---|
| KeyPair | PEM file, chmod 600 | default; fine when process and disk are one trust domain |
| SocketSigner | keyholder daemon, over a unix socket | signs bytes, never reveals the key, no export operation; --allow-uid peer check fails CLOSED where the peer uid isn't checkable (0.15.0) |
| P11Signer | PKCS#11 token, non-extractable | --ensure-key imports the existing journal key — continuity, not rotation; public hex doesn't move (0.16.0, noirebox[hsm]) |
Custody disclosure — the journal states its own proof grade:
noirebox custody-gradeprintswitness = min(authoring, retention): a journal is only as provable as the weaker of "was the writer's key in custody at seal time" and "was the retention path itself journaled"noirebox seal-retention --action prune|migrate|policy-change|restore— retention operations become first-class sealed events- Custody vs anchoring are different trust boundaries and are disclosed separately (ADR 022)
- Post-quantum evidence is staged as hybrid signing behind the signer interface — classical Ed25519 stays the trust anchor while a PQ sibling rides along (ADR 027)
- The pinned hardware root remains the deployer's call — stated in the threat model, not hidden
§Anchoring & fleet
A journal that dates itself proves nothing — that's the suspect writing its own report. Anchoring lets an external Timestamp Authority sign "I received hash X at time T". Only the 32-byte head hash ever leaves. A regenerated journal shows a head the old token doesn't cover, and a backdated token is arithmetically impossible — this is the control that catches an operator with the private key.
Witness layers you choose
| Layer | Trust | Setup |
|---|---|---|
| Qualified eIDAS TSA (Universign, Certigna…) | legal presumption of date + integrity (eIDAS art. 41) | point a profile at the endpoint |
| Public TSAs (DigiCert, FreeTSA…) | independent organizations; roots pinned in this repo | NOIREBOX_TSA_PROFILES |
| OpenTimestamps / Bitcoin | forging means redoing the network's proof of work; verifying ≈ 30 µs | ots client in PATH |
| Self-hosted OpenSSL TSA | own root + leaf chain, 0 €, works offline | make tsa |
The anchor event payload carries head_seq, head_hash, the primary RFC 3161 token (tsr, base64 DER), the TSA cert bundle (tsa_cert_pem) and the full witness list (tokens — one token per profile + OTS receipts).
Fleet hub
One seal for the whole fleet: the heads of N journals form a Merkle tree, a single TSA seal covers them all, and each member proves its place with ~11 hashes — verified offline. noirebox fleet-anchor seals it, fleet-verify checks one member, fleet-status checks every member (exit 0 all covered / 1 alarm, --json for alerting), fleet-watch runs that on a cadence with optional re-anchoring (--reanchor shrinks the falsifiable window to the interval) and webhook alarms. The hub sees 32-byte hashes, never your events.
§Guardrails
Prevention is pluggable; proof is universal. Already running Lakera, Llama Guard, your own LLM-judge? Keep them — a guardrail is just another event source, and its verdicts become tamper-evident instead of living in rewritable logs.
| Engine | How | Latency (7 lines) |
|---|---|---|
| regex | bilingual FR/EN patterns compiled at load; score = fixed severity | 0.21 ms |
| ml | TF-IDF (1–2 word + 3–5 char grams) + logistic regression; FR + EN detectors ~250 KB each in the wheel; threshold 0.5, granularity = line | 10.3 ms |
| tiered | regex + ML first; a local LLM judge (default qwen2.5-coder:3b, JSON-pinned, temperature 0) only pays for doubt (ADR 015/016) | ml cost + judge on disagreement |
Incident contract — same shape from every engine:
{
"category": "instruction_override|data_exfiltration|pii_request|tool_abuse",
"score": 0.94,
"excerpt": "…≤ 120 chars…",
"start": 214, "end": 305
}
Honest failure modes: unparsable judge output → 503, never a manufactured incident; verdicts outside the taxonomy are dropped; measured false negatives are non-zero and tracked. The bundled detector is a working example of the plugin contract — swappable by design (ADR 003: Meta's Prompt Guard evaluated and declined, integration path documented).
§Integrations
MCP server — agent tools over stdio JSON-RPC
python -m noirebox.mcp_server
# client config: {"mcpServers": {"noirebox": {"command": "python", "args": ["-m", "noirebox.mcp_server"]}}}
| Tool | Does |
|---|---|
| noirebox_scan | scan a transcript, seal the incidents |
| noirebox_log_event | seal one free-form event |
| noirebox_verify | verify the journal in place |
| noirebox_attestation | fetch the signed summary |
Agent hooks & editor
noirebox hook tool-use/session-end— seal one tool action (PostToolUse) or the full session transcript (SessionEnd) from hook JSON on stdin; best-effort by design (ADR 013)noirebox seal-trajectory --rollout <dir>— seal a coding agent's model trajectory (model-io JSONL): per-line digests only, never the payload (ADR 012)- VS Code / Cursor extension (also on Open VSX) — journal + verify from the editor; versioned separately from the package
- ZCode / Claude Code plugin —
plugins/claude+plugins/noireboxin-repo
Operations
noirebox export-siem --format cef|otlp --since N— CEF (ArcSight) or OpenTelemetry JSON, tail-only with--sincenoirebox audit-pack <outdir>— one folder for the auditor: export + verifier report + the Annexe IV §2(f) logging description (ADR 010)noirebox replay <meeting_id>— rebuild the decision timeline from sealed evidence; refuses if the chain doesn't verify first ("replay refuses theater")noirebox reconcile --config invariants.json --journal-report --fail-on-findings— invariants over the journal, CI-friendly exit 2noirebox crosschain --journal a=path …— consumption edges across journals, partial order, fan-in (ADR 024)noirebox toolset-pin --server S --tools tools.json --reviewed-by NAME --check --fail-on-drift— MCP tool descriptions are instructions: pin the baseline, diff on session start (ADR 025)- Built-in dashboard (heatmap, traffic radar) on the service; Grafana JSON in
docs/grafana-dashboard.json
§CLI reference
noirebox --version → 0.21.0. Twenty subcommands; every journal path resolves the same way (--db → NOIREBOX_DB → nearest .noirebox/ → data/noirebox.db).
| Command | What it does |
|---|---|
| serve | run the HTTP API (uvicorn) — --host, --port (default 127.0.0.1:8768) |
| seal | seal one free-form event: seal <type> '<json>' — digests and short facts, never raw content |
| verify | verify the journal chain in place, print the verdict |
| locate | print the resolved journal path |
| reconcile | invariants over the journal from a JSON config; --journal-report seals the report; --fail-on-findings exits 2 (CI) |
| crosschain | reconciliation across journals (consumption edges, ADR 024); repeatable --journal NAME=PATH |
| toolset-pin | MCP toolset baseline: pin, then --check (session-start gate), --fail-on-drift for cron/CI |
| audit-pack | auditor pack: export + verifier report + Annexe IV §2(f) description |
| seal-trajectory | seal a coding agent's model trajectory (model-io JSONL, digests only); --rollout scans a dir, --interval rescans |
| hook tool-use | seal one agent tool action (PostToolUse) from hook JSON on stdin |
| hook session-end | seal the session transcript (SessionEnd) |
| fleet-anchor | one Merkle seal over N journal heads, witnessed by the configured TSAs, proofs printed per member; --allow-local = no external date |
| fleet-verify | is this journal covered by the hub's latest fleet seal? (exit 0/1) |
| fleet-status | check every member against the hub seal — cron/CI friendly, --json |
| fleet-watch | service form: check on a cadence, alarm on drift (webhook), optional --reanchor |
| replay | rebuild the decision timeline for one meeting/run from sealed evidence; refuses an unverified chain |
| export-siem | CEF or OTLP/JSON export, --since tail-only |
| keyholder | serve the key over a unix socket — signs bytes, never reveals; --allow-uid, --pkcs11-*, --ensure-key |
| keyholder-status | describe a running keyholder: public key (the out-of-band pin value) + peer check |
| seal-retention | seal a retention change INTO the journal (prune | migrate | policy-change | restore) |
| custody-grade | print the custody disclosure: witness = min(authoring, retention) |
§Performance & measurements
Every number is reproducible from the repo. A metric we can't reproduce means unknown, not a rounder number.
| Metric | Value | Reproduce with |
|---|---|---|
| Sealed append — SHA-256 + Ed25519 + SQLite commit | 0.17 ms | make bench |
| Regex guardrail scan (7 lines) | 0.21 ms | make bench |
| ML guardrail scan (7 lines, sklearn loaded) | 10.3 ms | make bench |
| Full chain verification, 100 events (incl. JSON load) | 44 ms | verifier/verifier.py |
| Bundled detectors, FR + EN | 293 + 243 KB | make train · make train-en |
| Held-out attack sentences, FR + EN | 12/12 | tests/test_ml_guardrail.py |
| Test suite | 392 · 0 failing | make test |
MacBook M-series, local venv — sealing/verification rows 2026-10-04. Absolute values vary with hardware; make bench on your machine is the reference.
SCAR-BENCH-114 — open-weights measurement
A published, seeded measurement protocol (docs/SCAR-BENCH.md): 120 planned trials against three local models, canary-witness scoring, raw results in-repo. Headline:
| Model | Condition A (prose) — canary trip rate | Condition B (primitive) | Strict canonical JSON |
|---|---|---|---|
| qwen2.5-coder:3b | 100% (18/18) | 75% (15/20) | 0 |
| qwen2.5:0.5b | 100% (19/19) | 78.9% (15/19) | 0 |
| llama-guard3:1b | 100% (20/20) | see results file | 0 |
Disclosure: single machine, local Ollama, temperature 0.7, per-trial fixed seeds. Measurement, not a verdict. 4 timeouts excluded, disclosed in the results file.
§Project layout
noirebox/ the package chain.py store.py schemas.py hash chain, SQLite append-only store, Pydantic models receipt.py reconcile.py independence.py sealed receipts, invariants, flow independence anchors.py witness.py merkle.py fleet.py RFC 3161 anchoring, fleet hub keyholder.py hsm.py custody: unix-socket signer, PKCS#11 guardrail.py ml_guardrail.py llm_judge.py tiering.py three scan engines + tiered judge mcp_server.py hookcli.py trajseal.py toolset.py agent-facing surfaces crosschain.py digests.py siem.py replay.py pdf_export.py c2pa.py aiact.py cli.py main.py dashboard.py auth.py verifier/verifier.py standalone third-party verifier (+ tsa_roots/ pinned certificates) bench/ SCAR-BENCH harness + published results (scar114) tsa/ self-hosted OpenSSL witness (root + leaf chain) plugins/ VS Code extension · Claude Code hooks · ZCode plugin tests/ 392 tests — the invariant suite, incl. SCAR replay docs/ SPECS · THREAT-MODEL · ADRs · compliance & bench docs (this site) demo/ runnable end-to-end scenes
§Releases & distribution
| Channel | Artifact |
|---|---|
| PyPI | pip install noirebox |
| GHCR | ghcr.io/noirebox/noirebox:latest |
| VS Code Marketplace · Open VSX | editor extension — versioned separately (0.10.1) |
| GitHub Releases | VSIX + tagged sources, notes per release |
History
21 releases since 2026-09-19, every one in the changelog. Recent arc:
- 0.21.0 — 2026-10-15 — external audit round: 10 findings, 0 breaking the cryptography; 8 fixed outright, NB-05/NB-08 closed in their compatible halves, each with a named test. Fail-closed defaults everywhere (
unverifiable witness → exit 2, unparseableNOIREBOX_CLIENTSrefuses to boot) - 0.20.0 — 2026-10-14 — retention sealing + custody grade:
witness = min(authoring, retention) - 0.19.0 / 0.18.0 — 2026-10-14 — uid-gate as a tri-state disclosure (off / enforced / unavailable), custody protocol 0.2, PIN moved out of argv
- 0.16.0 / 0.15.0 — 2026-10-13 — the key leaves the disk: keyholder daemon, then PKCS#11 token
- 0.11.0 — 2026-10-11 — receipt/0.2.2 (judged_by + spec_hash), SCAR-BENCH-114 published
- 0.1.0 → 0.10.0 — 2026-09-19 → 10-04 — chain, guardrails, RFC 3161, fleet hub, distribution
§Security & honest limits
The adversary model, trust boundaries and residual risks live in the threat model; the security baseline and scan methodology in SECURITY-BASELINE.md. Report vulnerabilities per SECURITY.md — please don't open public issues for them.
Known limits, assumed and tracked:
- Payloads are not encrypted — GDPR minimization is the caller's responsibility
- Pinned hardware root of custody is still open; the published attestation is the countermeasure until then
- Probabilistic guardrail — measured false negatives are non-zero
- Single-process append lock — sharding/scaling not targeted
- 0.21.0 residual: re-hash detection stays a versioned-format decision (NB-05 compatible half)
§Compliance mapping
Full write-ups: COMPLIANCE-EU.md · ART12-MAPPING.md. A building block, not a certification — the perimeter is stated, not oversold.
| Obligation | Answered by |
|---|---|
| GDPR art. 5(2) — accountability: demonstrate compliance | tamper-evident journal of what the AI produced, when, on which input |
| GDPR art. 15/20 — access & portability | signed export, verifiable by the subject's own auditor |
| EU AI Act art. 12 + 19 — automatic event logs, retained ≥ 6 months | sealing at runtime; cryptographic log integrity; ART12 mapping doc |
| EU AI Act art. 55(1)(c) — GPAI incident tracking (live since Aug 2025) | incidents as first-class sealed events; audit-pack for reporting |
| AI Act Annexe IV §2(f) — document the logging characteristics | noirebox audit-pack generates the description with the export |
| eIDAS art. 41 — qualified timestamp presumption | anchor profiles for qualified TSAs + pinned-root public TSAs + OpenTimestamps |
| Sovereignty | self-hosted, zero telemetry, keys on your infrastructure, EU-only clouds fine |
§Documentation index
Everything below lives in docs/ in the repository — markdown, versioned with the code.
| Document | Contents |
|---|---|
| SPECS.md | the source of truth: data contracts, crypto, API contract, measured performance — divergence between code and spec is a bug |
| ADRs.md | 27 architecture decision records with their context and rejected options |
| THREAT-MODEL.md | adversary model, trust boundaries, open residuals |
| AUTHORITY-LADDER.md | who may judge what — the verdict-precedence doctrine behind receipt schemas |
| SCAR-BENCH.md | the published measurement protocol: taxonomy, claims format, differential harness |
| COMPLIANCE-EU.md | GDPR / AI Act / eIDAS mapping with article-level references |
| ART12-MAPPING.md | AI Act art. 12 logging requirements → journal properties |
| SECURITY-BASELINE.md | security scan methodology and results, with reproduction commands |
| VULGARISATION.md | the whole project explained from zero, no prior knowledge assumed |
| ROADMAP-PLUGINS.md | plugin ecosystem direction |
§ADR index
All 27 in docs/ADRs.md — each with context, decision and what was rejected:
| 001 | Guardrail: regex → ML micro-model → LLM judge last |
| 002 | Reject Meta's Llama Prompt Guard 2 as the engine |
| 003 | Third-party detectors: documented path, not embedded |
| 004 | OAuth2 (JWT bearer) + rate limiting, optional by config |
| 005 | PDF attestation: proof for humans, JSON for machines |
| 006 | RFC 3161 anchoring: close the "insider with the key" gap |
| 007 | Self-hosted TSA: root + leaf chain, not a single certificate |
| 008 | Multi-TSA anchoring with pinned roots |
| 009 | OpenTimestamps witness: the compute-grade layer |
| 010 | AI-Act-shaped events + audit-pack |
| 011 | Content-provenance events (model-collapse research, in journal form) |
| 012 | Model-trajectory sealing: the flight recorder's flight recorder |
| 013 | Transcript-agnostic sealing + per-project journals |
| 014 | JWT secret derived from private material, never public data |
| 015 | The tier-2 judge: local LLM, house taxonomy, JSON-pinned, honest when silent |
| 016 | The tiered scan: the judge pays only for doubt |
| 017 | Fleet hub v0: one seal covers N journals |
| 018 | Key via secret-manager injection, loud on mismatch |
| 019 | Receipt schema v0.2: verdict binds its check, evaluator, reach |
| 020 | The denominator: attempt-first sealing |
| 021 | Flow independence is a testable invariant |
| 022 | Custody vs anchoring: map the trust boundary, disclose the grade |
| 023 | Seal the belief, not only the action |
| 024 | Cross-chain reconciliation: consumption edges, partial order |
| 025 | Toolset baseline: tool descriptions are instructions, pin them |
| 026 | Admission receipts: seal the basis, not only the act |
| 027 | Post-quantum evidence: hybrid signing behind the signer interface |
§Contributing
- Branches + pull requests;
mainis protected (PR + required checks). No direct pushes. make test— 392 tests, must stay green ·rufffor lint (B/SIM/C4 enforced) · CI runs the suite + Bandit + a stub-LLM coverage pass.- The spec is the contract: a code change that diverges from
docs/SPECS.mdupdates the spec in the same PR — or it's a bug. - Numbers cited in docs must be reproducible (
make bench,make test) — measured, never rounded up. - MIT. Issues and PRs welcome; security issues go to SECURITY.md, not public issues.
NoireBox is engineered in the Vosges, France 🇫🇷. NoireBox is a building block, not a certification — it proves the integrity of the record; data minimization and key-root decisions remain the deployer's.