<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sam LABBE</title>
    <description>The latest articles on DEV Community by Sam LABBE (@slabb).</description>
    <link>https://dev.to/slabb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2901084%2F16244fc1-095c-41d9-ad2a-203fb3e617f9.png</url>
      <title>DEV Community: Sam LABBE</title>
      <link>https://dev.to/slabb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/slabb"/>
    <language>en</language>
    <item>
      <title>I built the flight data recorder for AI agents.</title>
      <dc:creator>Sam LABBE</dc:creator>
      <pubDate>Tue, 22 Sep 2026 18:50:05 +0000</pubDate>
      <link>https://dev.to/slabb/i-built-the-flight-data-recorder-for-ai-agents-38f6</link>
      <guid>https://dev.to/slabb/i-built-the-flight-data-recorder-for-ai-agents-38f6</guid>
      <description>&lt;p&gt;&lt;em&gt;Or why I spent my evenings making AI-agent journals impossible to rewrite.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkivc1bsio3209t7hf9qq.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkivc1bsio3209t7hf9qq.jpeg" alt="Fleet of AI Agents sealing informations" width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One Tuesday, at 2:37 PM
&lt;/h2&gt;

&lt;p&gt;A disgruntled employee opens the database behind an AI product and&lt;br&gt;
edits one row. The minutes an agent produced yesterday — the ones a client&lt;br&gt;
is about to receive — now say something else. No alert. No trace. The&lt;br&gt;
dashboard shows a pristine history, because the history &lt;strong&gt;has been&lt;br&gt;
rewritten&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This isn't a thriller plot. It is the default state of every AI-agent&lt;br&gt;
product shipping today: their logs live in mutable databases, and &lt;strong&gt;nothing&lt;br&gt;
exists to prove, after the fact, what the agent actually decided&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I looked for the tool that closes this gap. It didn't exist. So I built it.&lt;br&gt;
It's called &lt;strong&gt;NoireBox&lt;/strong&gt;, it's open source (MIT), and this post is about&lt;br&gt;
what it does, how it does it, and why I believe it's a missing piece.&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;&lt;a href="https://slabbdev.github.io/noirebox/" rel="noopener noreferrer"&gt;https://slabbdev.github.io/noirebox/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The founding question
&lt;/h2&gt;

&lt;p&gt;After fifteen years of backend engineering — insurance, renewable energy,&lt;br&gt;
real estate — in systems where every decision must be defensible years&lt;br&gt;
later, I asked the question that started everything:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If someone contests a decision made by an AI agent tomorrow, who can&lt;br&gt;
&lt;em&gt;prove&lt;/em&gt; it?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not "who can tell the story". Not "where is it logged". Who can &lt;strong&gt;prove&lt;/strong&gt; it&lt;br&gt;
— to a client, a lawyer, an auditor, a regulator — without trusting the&lt;br&gt;
vendor, the host, or the administrator?&lt;/p&gt;

&lt;p&gt;The answer, everywhere, was: nobody. Observability tooling (Langfuse,&lt;br&gt;
LangSmith, Helicone…) is great for &lt;strong&gt;debugging&lt;/strong&gt; what happened — but its&lt;br&gt;
logs stay mutable, and nothing is exportable as evidence. Debugging and&lt;br&gt;
proving are different jobs.&lt;/p&gt;
&lt;h2&gt;
  
  
  The principle: a proof, not a promise
&lt;/h2&gt;

&lt;p&gt;NoireBox is a &lt;strong&gt;tamper-evident journal for AI agents&lt;/strong&gt; — a flight data&lt;br&gt;
recorder, like the ones in aircraft. Every event (model call, output,&lt;br&gt;
decision, incident) goes through four mechanisms:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Hash chaining.&lt;/strong&gt; Each event's SHA-256 fingerprint includes the previous&lt;br&gt;
event's. Modify, insert, or delete anything and the chain breaks — and the&lt;br&gt;
verifier tells you &lt;strong&gt;which&lt;/strong&gt; event was tampered with. A numbered notebook:&lt;br&gt;
you can't tear out a page without anyone noticing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Signatures.&lt;/strong&gt; Every fingerprint is signed with &lt;strong&gt;Ed25519&lt;/strong&gt;, using a key&lt;br&gt;
that never leaves the server (chmod 600). Regenerating the whole chain&lt;br&gt;
without the key? The forgery is visible on sight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The outside witness.&lt;/strong&gt; The detail that kills tampering &lt;em&gt;at the source&lt;/em&gt;:&lt;br&gt;
NoireBox has an external &lt;strong&gt;timestamp authority&lt;/strong&gt; (RFC 3161 — the same&lt;br&gt;
protocol notaries and audit firms use) sign the chain head's fingerprint at&lt;br&gt;
time T. Rewriting history &lt;em&gt;afterwards&lt;/em&gt; becomes arithmetically impossible:&lt;br&gt;
the old token no longer covers the new head. A journal that timestamps&lt;br&gt;
itself proves nothing — that's the suspect writing its own police report.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The third-party-verifiable export.&lt;/strong&gt; One file, plus a standalone&lt;br&gt;
verifier that &lt;strong&gt;anyone&lt;/strong&gt; runs on their own machine, offline, with no&lt;br&gt;
credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python verifier/verifier.py export.json
&lt;span class="go"&gt;[✓] INTACT — 3 events verified · attestation valid · anchors checked
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on that Tuesday at 2:37 PM, the same verifier returns a different&lt;br&gt;
verdict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[3] An attacker rewrites event 2: the minutes now read "REFUSE".
[✗] DETECTED — event 2: invalid hash (content was modified)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Real output from the repo's tamper demo — not an illustration.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NoireBox never asks you to trust it. It hands you the dossier, and anyone&lt;br&gt;
recomputes the truth themselves.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What about a whole fleet? One seal, a thousand boxes
&lt;/h2&gt;

&lt;p&gt;Each box seals its own chain head individually. But what if you run 1,200&lt;br&gt;
agents? Aggregated anchoring: the chain heads of N boxes form a &lt;strong&gt;Merkle&lt;br&gt;
tree&lt;/strong&gt; whose root receives &lt;strong&gt;a single&lt;/strong&gt; TSA seal. One seal for the whole&lt;br&gt;
fleet — and each box proves it took part with ~log₂(N) hashes (11 for&lt;br&gt;
1,200), verified offline.&lt;/p&gt;

&lt;p&gt;That's the &lt;strong&gt;Certificate Transparency&lt;/strong&gt; model — the system that made HTTPS&lt;br&gt;
certificates auditable worldwide — applied to AI-agent decisions. To my&lt;br&gt;
knowledge, nobody does this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make demo-fleet
&lt;span class="go"&gt;[2] Merkle tree: 3 leaves, root ef43f07bbe6b0691…
    cr-reunion         proof: 2 hashes → ✓ covered
    support-juridique  proof: 2 hashes → ✓ covered
    scoring-credit     proof: 2 hashes → ✓ covered
[5] support-juridique regenerates its journal: content rewritten, re-chained cleanly.
[✗] DETECTED — the new head is not covered by the fleet seal.
&lt;/span&gt;&lt;span class="gp"&gt;    old head covered: yes;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;new one: NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important part: the hub doing the aggregation cannot cheat. It can&lt;br&gt;
&lt;em&gt;omit&lt;/em&gt; a box (a detectable silence), but it can neither rewrite a sealed&lt;br&gt;
batch nor include a fake head — and it journals the full tree into &lt;strong&gt;its&lt;br&gt;
own&lt;/strong&gt; NoireBox journal. Every member verifies &lt;strong&gt;locally&lt;/strong&gt;, without&lt;br&gt;
contacting anyone. The arithmetic decides.&lt;/p&gt;

&lt;h2&gt;
  
  
  The guardrail is a plugin (keep yours)
&lt;/h2&gt;

&lt;p&gt;Already running Lakera, Llama Guard, your own LLM-judge, or your own&lt;br&gt;
regexes? &lt;strong&gt;Keep them.&lt;/strong&gt; Prevention is a fungible layer — everyone has their&lt;br&gt;
own, and it will keep changing. Proof is the universal layer.&lt;/p&gt;

&lt;p&gt;Journal your solution's verdicts with a single &lt;code&gt;POST /api/v1/events&lt;/code&gt;&lt;br&gt;
(&lt;code&gt;type: "incident"&lt;/code&gt;) and its catches become tamper-evident and&lt;br&gt;
third-party-verifiable, instead of ending up in rewritable app logs. The&lt;br&gt;
bundled detector (regex + micro-model, French and English, ~250 KB per&lt;br&gt;
language) is a &lt;strong&gt;working example of the plugin contract&lt;/strong&gt;, not an&lt;br&gt;
obligation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers — all reproducible with one command
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Reproduce with&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sealing one event (hash + signature + commit)&lt;/td&gt;
&lt;td&gt;0.21 ms&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docs/SPECS.md&lt;/code&gt; §6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full verification of 100 events&lt;/td&gt;
&lt;td&gt;22 ms&lt;/td&gt;
&lt;td&gt;&lt;code&gt;verifier/verifier.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bundled detectors, FR + EN&lt;/td&gt;
&lt;td&gt;293 + 243 KB&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;make train&lt;/code&gt; · &lt;code&gt;make train-en&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Held-out attack sentences (never seen in training)&lt;/td&gt;
&lt;td&gt;12/12&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tests/test_ml_guardrail.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test suite, re-run on every push&lt;/td&gt;
&lt;td&gt;91 green&lt;/td&gt;
&lt;td&gt;GitHub Actions CI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I imposed one rule on myself: &lt;strong&gt;no number that can't be reproduced with one&lt;br&gt;
command.&lt;/strong&gt; A metric we can't reproduce is &lt;em&gt;unknown&lt;/em&gt; — not a rounder number.&lt;br&gt;
That's also why this post contains no "78M+ events", no customer logos, no&lt;br&gt;
testimonials.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is not
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not a blockchain.&lt;/strong&gt; One issuer, one verifier. Blockchains solve a
problem we don't have — consensus among strangers — at a complexity price
we refuse to pay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a certification.&lt;/strong&gt; A building block that feeds your audits; the
exact perimeter is written down in the
&lt;a href="https://github.com/slabbdev/noirebox/blob/main/docs/THREAT-MODEL.md" rel="noopener noreferrer"&gt;threat model&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not an LLM.&lt;/strong&gt; A 250 KB specialist detector that sorts sentences into 5
classes, deterministic and testable — not a black box predicting the next
token.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why now
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://eur-lex.europa.eu/eli/reg/2024/1689/oj" rel="noopener noreferrer"&gt;EU AI&lt;br&gt;
Act&lt;/a&gt; (article 12) requires&lt;br&gt;
&lt;strong&gt;automatic event logging&lt;/strong&gt; for high-risk systems. GDPR (art. 5(2), 15/20)&lt;br&gt;
puts the burden of proof on whoever processes the data. ISO 42001 asks for&lt;br&gt;
traceability of AI decisions.&lt;/p&gt;

&lt;p&gt;European vendors will have to &lt;strong&gt;prove&lt;/strong&gt; — not promise — what their agents&lt;br&gt;
did. Today, almost none of them can. NoireBox is a sovereign building block:&lt;br&gt;
self-hosted, zero telemetry, keys stay yours. Built in the Vosges mountains&lt;br&gt;
🇫🇷 — yes, proof infrastructure can be built from the mountains.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in three commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git clone https://github.com/slabbdev/noirebox &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;noirebox
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./start.sh          &lt;span class="c"&gt;# 91 green tests + API on :8768 — /docs is live&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make demo           &lt;span class="c"&gt;# the model → the journal → the auditor → the attacker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FastAPI, 10 documented routes, a Python SDK, an MCP server (4 tools to plug&lt;br&gt;
your agents in), a DPO-ready PDF export, and a self-hosted TSA (&lt;code&gt;make tsa&lt;/code&gt;,&lt;br&gt;
OpenSSL, $0, offline) — because a witness you don't control is a witness&lt;br&gt;
less.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;On the roadmap: a supervision view readable by non-developers, a per-writer&lt;br&gt;
identity field, multi-TSA rotation. The core is &lt;strong&gt;MIT, forever —&lt;br&gt;
verification included.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If this resonates, here's what would help the most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ &lt;a href="https://github.com/slabbdev/noirebox" rel="noopener noreferrer"&gt;A star on the repo&lt;/a&gt; — it sounds
silly, but it's what makes a project exist&lt;/li&gt;
&lt;li&gt;🕵️ &lt;strong&gt;Try to break the proof.&lt;/strong&gt; This is a project whose product is
resistance to tampering: the best compliment is an issue describing an
attack&lt;/li&gt;
&lt;li&gt;🔀 Fork it, PR it, question it — the code is deliberately small (one
journal, one plugin, one verifier) so it can be read end to end&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you know a DPO, a CISO, or an AI vendor preparing for article 12,&lt;br&gt;
send them this post — that's exactly who this black box is for.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;NoireBox — every AI decision, sealed forever.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built solo, in the Vosges mountains, between two missions. Code, threat&lt;br&gt;
model and specs:&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/slabbdev/noirebox" rel="noopener noreferrer"&gt;github.com/slabbdev/noirebox&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>ai</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
