DEV Community

nsb
nsb

Posted on

Your AI agent wrote its own log. That's the problem.

A value showed up in a staging table that shouldn't have been there. Benign on its face — recoverable, nothing critical. But it didn't quite make sense to me, and I needed to know how it got there.

I checked the agent's log. Nothing. No write, no read, no mention of that table at all.

I checked the database logs. The change was there, and the timing lined up. But the connection was the shared service account, the one the whole deploy pipeline uses, and there's no per-session identity attached to it. So the database knew a write happened. It couldn't tell me which process made it, or which run.

Two records. Neither one could tell me what I needed to know.

Which meant I had a strong feeling I knew what happened and no way to prove it. Not to a teammate, not to a reviewer, not even to myself. I spent the morning in that gap.

The log is written by the thing you're checking

Every agent framework has logging. Claude Code has telemetry. Cursor shows you what's happening. MCP servers log their calls. There's no shortage of visibility.

But all of it is produced inside the agent's process. The agent writes directly to its own history. There's no separate observer in the loop — the record you read afterward was authored by the thing you're trying to check.

That's the part I couldn't get past. I can't trust the integrity of a record whose only author is a hallucinating agent on a strong dose of overconfidence. Not because it's lying. Because it isn't. It reports what it believes it did, and it believes it did the right thing. A confident record that's wrong reads exactly like a confident record that's right.

When the agent is right, that's fine. When it's confused, when the model is wrong, when something goes somewhere you didn't expect — the record is coming from the exact thing you're trying to verify. If it's compromised, the log is compromised. If it's wrong, the log is confidently wrong. And if it simply didn't notice what it did, the log is silent.

This isn't a new problem. It's the problem every evidence-producing domain solved decades ago. You don't accept a company's own security report as a SOC 2. You don't accept a company's own financial statement without an audit. The reason is the same everywhere: a record produced by the entity being observed is a claim, not evidence.

Agent tooling hasn't caught up to that.

And you can't just re-run it

My first instinct was the obvious one: if I don't know what happened, run it again and watch.

That doesn't work. Agents aren't deterministic. Same input, different path. Same task, different files touched. The run you're trying to understand is gone, and re-running gives you a different run.

So you're left with two bad options. Trust the agent's own record, or have no record at all.

The part I couldn't unsee

It wasn't the wrong value.

Once I was in that gap, the thought went further. If I can't account for this — one staging table, low stakes, recoverable — what about the environments where I don't get a second chance? Payment endpoints. Customer records. Anything with real consequences and an audit trail someone else would eventually read.

But that's the smaller realization. Here's the one that changed how I work.

I'd been writing prompts with full confidence. Detailed instructions, clear boundaries, "don't touch X" and "only do Y." Reading the agent's summaries and signing off. Confident the whole time.

Underneath that, I had no idea what was actually happening.

The confidence in my instructions didn't match what I actually knew. I was writing authoritative prompts into a void and calling the output a result. And the reason I couldn't tell the difference was that every piece of evidence I had about the agent's behavior came from the agent.

That's the thing I couldn't unsee.

What an independent record actually requires

The fix isn't better logging. It's where the record lives.

The record has to be produced outside the agent's process. Separate process, separate identity, separate storage, separate code path. The agent can't write to it, because there's nothing persistent running for it to write to. It starts when the agent starts and it's gone when the agent ends.

That's the same trust topology audit converged on everywhere else. The observer has to be independent of the observed.

The second requirement is that anyone can check it. Not "trust the vendor's dashboard" — actually verify it. Locally, offline, without an account, without a network call. A hash-chained ledger and a verifier that imports nothing from the tool that wrote it. Two independent implementations agreeing is a stronger claim than one program checking its own work.

What I built

Centrol is a free, local flight recorder for AI agents. It's a single Go binary, no daemon, no cloud, no account, no telemetry. It covers the paths agents act through — the filesystem, MCP tool calls, shell, and outbound network — and logs what it sees to an append-only, hash-chained ledger.

Two commands do most of the work:

centrol guard wraps an agent run. It takes a snapshot first, records every action out-of-band while the run is happening, and leaves you with a state you can return to. No slowdown, no change to how the agent works — one word in front of the command you were already running.

centrol proxy sits in front of your MCP servers. Every tool call passes through it before anything executes, which is where allowlists and blocks happen. A call that violates policy doesn't run, and it's recorded as having been refused.

Setup for the proxy path is one command. centrol proxy install <client> rewrites the MCP config so every server launches through the proxy. You run it once. It backs up your original config first, and it's safe to re-run — anything already wrapped is left alone.

What it doesn't do

I'd rather tell you the limits up front than have you find them the hard way.

It's not a sandbox. It records and reverses governed actions. It doesn't prevent a determined agent from acting outside the governed interfaces.

Guard and proxy enforce differently, on purpose. centrol guard never blocks a filesystem write — not even one to ~/.ssh or ~/.aws. A filesystem watcher sees writes after they've landed, so there's nothing left to block. It logs those as violations and lets them through. centrol proxy is different: the call hasn't reached the server yet, so a tool call that resolves to a protected path is genuinely never forwarded. If you need a hard guarantee that a credential path is never touched, that guarantee exists on the proxy path, not the guard path.

Rollback has honest scope. centrol undo restores tracked git state and untracked files that existed at snapshot time. It doesn't restore ignored files, databases, or other external state. And it doesn't guess — when it finds files it can't account for, it lists them and lets you decide what happens to them instead of deleting on your behalf.

Quickstart

# Install (macOS/Linux)
curl -fsSL https://raw.githubusercontent.com/baitelmal/centrol/main/install-centrol.sh | sh
Enter fullscreen mode Exit fullscreen mode
# Install (Windows, PowerShell)
irm https://raw.githubusercontent.com/baitelmal/centrol/main/install-centrol.ps1 | iex
Enter fullscreen mode Exit fullscreen mode
# Wrap an interactive agent session
centrol guard -- claude

# Or front a stdio MCP server
centrol proxy --target "npx @modelcontextprotocol/server-filesystem /path/to/allow"

# See what happened
centrol audit

# Confirm the record hasn't been tampered with
centrol audit --verify

# Roll back the most recent run
centrol undo
Enter fullscreen mode Exit fullscreen mode

The ledger is written locally and never transmitted. centrol-verify is a standalone binary that checks a ledger's hash chain without importing anything from centrol — so you can verify a record without trusting, or even building, the tool that produced it.

Why I'm posting this

I built it for myself, because I wanted something to boost trust in my agents and mitigate the obscurity of their black box designs. The record needs to be independent, it has to work offline as well, and it has to be verifiable without taking my word for it. Those three constraints ruled out everything I looked at.

If you've given an agent real access to something that matters and you've had a similar experience — give it a spin. I hope it's useful to someone.

Repo: https://github.com/baitelmal/centrol

If you try it, I'd like to hear how it goes — your experience with it, and any edge cases you run into.

Top comments (0)