🏗️ The Runtime That Keeps Receipts: Why I Deleted My Own AI Platform and Rebuilt It Around an Approval Gate
Stratum began as a confession: hundreds of files of simulated intelligence, beautiful dashboards, and not one real file changed. This is the story of tearing that down and building an agentic execution runtime governed by one rule — nothing is observable until something actually happened.
Every few weeks last year, I gave a demo that worked perfectly.
A session would open. A proposal would appear. A decision-intelligence panel would score it, a governance timeline would light up, projections would refresh across six tabs. Observers nodded. I nodded. Everything on those screens was real data, persisted in real databases, served by a real FastAPI backend with more than three hundred modules.
There was just one problem. None of it had ever touched a file. No repository had been transformed. No command had run. The proposals were born from mocks, the approvals approved nothing pending, the decision intelligence reasoned over events that no execution had produced. I had built a gorgeous mirror of a product — a theater of agency — and the pytest suite passed beautifully, which made it worse.
"A dashboard can show anything. That is exactly what makes dashboards dangerous. The question that broke my illusion was embarrassingly simple: show me the diff."
If you build or buy agentic AI software today, you have probably met its ghost. Chat windows that claim work happened. Agent loops whose only evidence is their own narration. Demos where the mock is the feature. Governance pages counting approvals of proposals that were never executable. The industry has become extraordinarily good at representing AI work and remarkably forgiving about whether any occurred.
This is the story of how I stopped doing that, deleted my own architecture, and rebuilt it around a single non-negotiable idea: an execution runtime must keep receipts.
The Reckoning: An Audit of My Own Code
The rebuild started not with new code but with verdicts against the old code. Every module in the legacy platform had to answer one question: are you causally connected to something that actually happened?
- KEEP — almost nothing wholesale. A handful of principles survived: local-first operation, events as the source of record, providers behind an adapter seam.
- REWRITE — the provider transport, the planner, proposals and approvals, tool execution, event handling, reconstruction. The concepts were right; the causal wiring was missing.
- QUARANTINE — everything else. Hundreds of models, services, projection builders, diagnostics, and intelligence layers with no real producer feeding them. Quarantined rather than deleted only so valuable pieces could be resurrected later against seams that now actually work.
The hardest part was not writing the verdicts. It was accepting that tests passing was never evidence the product worked. My old suite verified that simulated objects behaved as their simulations defined them. Circularity is not validation; it is choreography.
What Today’s Agent Runtime World Gets Wrong
Stratum exists because five failure modes keep repeating across the agentic tooling landscape:
| Failure Mode | What We See Today | What a Runtime Owes You |
|---|---|---|
| Narration as evidence | Agents report success in prose; the transcript is the only artifact. | Durable events per transition: typed, sequenced, causally linked facts — not stories. |
| Approval as UI decoration | Confirm buttons wired to nothing pending; approvals recorded for plans that cannot execute. | A structural gate: execution is unreachable in code until a human decision exists for that exact plan. |
| Mock-driven acceptance | Demos pass because canned responses define both the stimulus and the assertion. | Live-provider acceptance: the primary proof path hits a real endpoint and shows its receipts. |
| Fragile sessions | State lives in memory or an opaque model session; a crash erases the work and the context. | Recoverable executions: pending work survives restarts and resumes without re-invoking the model. |
| Provider lock-in | Business logic fused to one vendor SDK’s object model. | An adapter seam: swap OpenAI, Azure, Groq, Ollama without touching the engine. |
None of these are exotic research problems. They are plumbing failures — and plumbing is precisely what a runtime is for.
Why Now?
Three curves crossed to make this the right moment:
First, agentic coding went mainstream. CLI copilots and autonomous engineers are committing to real repositories daily. When the tool changes your files, “trust the demo” stops being an engineering stance and becomes an audit finding waiting to happen.
Second, durable event infrastructure became commodity. Kafka-compatible brokers like Redpanda run comfortably on a laptop. The excuse “event sourcing is for enterprises” expired the moment a single-container broker could hold your entire execution history.
Third, my own research told me where the gap was. In a prior prototype, AI Event Fabric, I explored whether independent AI and human participants could coordinate through durable events alone. The retained evidence supported the event-boundary hypothesis — but the lifecycle experiments exposed the deeper truth: a broker gives you transport and history, not a worker runtime. Readiness, recovery, approval authority, and execution control live above the event layer. Stratum is the answer to that discovery: the runtime layer the fabric experiments proved was missing.
The Vision: One Spine, No Shortcuts
Stratum’s entire contract fits in one picture. Seven stages. One of them belongs to a human, unconditionally.
+ bounded context
validated schema
recorded as fact
· verify commands
diffs · artifacts
+ SQLite index
no side effects
The wording matters. The gate is not a policy setting or a checkbox in a settings panel. It is a guard clause in the engine: decide_and_execute refuses any transition that does not originate from APPROVAL_REQUIRED with a matching pending plan id. During UAT, I watched a duplicate approve request get rejected with “cannot resolve approval from status COMPLETED.” That error message is my favorite feature.
The Architecture at a Glance
Zoom out from the spine and the system reads like a distributed-systems diagram, not an AI demo. One Kafka-grade event backbone sits at the center. Everything else — humans, CLIs, consoles, planners, verifiers — is just another participant, attached as a producer, a consumer, or both. Around the backbone sit three dashed seams: swap anything behind a dashed border without touching the engine, the contracts, or each other.
producer + consumer
Kafka-grade
seams
OpenAI · Azure · Groq · OpenRouter · Ollama · vLLM. Vendor- and provider-agnostic by contract (AIAdapter) — the engine never learns a vendor’s name.read_file · write_file · run_command) inside workspace boundaries. Harness-agnostic: CLI, console, HTTP — identical guarantees, one gate.Under the Hood: Six Decisions That Define Stratum
read_file, write_file, run_command. Small vocabularies are auditable vocabularies. The model proposes within the schema; anything else is rejected before a human ever sees it — invalid output fails the task before approval exists.stratum.runtime.events.v1, keyed by execution id for total ordering.requires_approval. And because the boundary lives in the engine, every transport (CLI prompt, browser button, HTTP call) inherits identical guarantees for free.AIAdapter) separates “how do I talk to this model?” from “what does the runtime do with the result?” OpenAI, Azure OpenAI, Groq, OpenRouter, Ollama, vLLM all speak the same dialect. New providers are new adapters; the engine never learns their names.The Crash Experiment
Every claim above survives contact with a terminal. My favorite afternoon of the whole rebuild was spent trying to break the approval boundary with a kill signal.
The setup: submit a task through the browser console. Watch the live provider return a structured plan. Status: APPROVAL_REQUIRED. Then, before approving — kill the server process outright.
Restart. The engine reads its two-table SQLite projection and prints:
$ stratum serve --port 8899 --brokers 127.0.0.1:9092
Resumed 1 pending execution(s) awaiting approval:
exe_mt4t9iev-3h7trr15 Change the greeting returned by hello.py...
The plan was approvable again — same steps, same identity, sequence numbering continuing exactly where the dead process left off, correlation preserved. Approving it through the restarted console executed the transformation normally. The resumed path never called the provider once (a test asserts this by replacing the adapter with one that fails loudly if touched). And when I tried approving a second time out of curiosity, the engine answered like a strict accountant:
InvalidTransitionError: cannot resolve approval from status COMPLETED
Meanwhile the event stream told the whole truth to two independent observers: Redpanda’s watermark advanced by exactly the number of emitted events, and the SQLite index held the same twenty-six rows. Two stores, one reality, zero reconciliation drift.
Show Me the Diff: A Real Run
This is the loop Stratum optimizes for — a genuine end-to-end transformation, operator in the middle:
$ stratum run --repo ./example-repo \
--task 'Change the greeting returned by hello.py from
"Hello" to "Hello Stratum" and update the test accordingly.' \
--file hello.py --file test_hello.py \
--brokers 127.0.0.1:9092
Repository validated.
Planning...
PLAN
1. [read_file] Read current hello.py (hello.py)
* 2. [write_file] Write updated hello.py ... (* mutates repo)
3. [run_command] Run tests ...
Approve plan for exe_mt4oq87s-kkrlpg49? [y/N] y
Executing...
[+] read hello.py (86 bytes)
[+] updated hello.py (94 chars)
[+] `python -m pytest -q` exited 0
Task COMPLETED.
Execution ID: exe_mt4oq87s-kkrlpg49
And when you ask for the history back, replay folds the recorded events into a narrative — without calling the model, without touching the filesystem:
$ stratum replay exe_mt4oq87s-kkrlpg49 --brokers 127.0.0.1:9092
Execution exe_mt4oq87s-kkrlpg49
Task: Change the greeting ...
Approval: granted by cli-operator
[+] 18:01:38 read_file - read hello.py (86 bytes)
[+] 18:01:38 write_file - updated hello.py (94 chars)
[+] 18:01:38 run_command - `pytest -q` exited 0
artifact: hello.py (94 bytes)
Status: COMPLETED
(26 events replayed; no AI calls, no side effects)
Trust, but Verify: The Negative Control
The question I respect most from skeptics is blunt: “how do I know a real model did the work and not a mock?” So the runtime ships with its own interrogation kit.
Every AI interaction emits ai.requested and ai.responded events carrying the endpoint host, the model id, the provider’s own request identifier, token usage, and latency. Query the store after any run and you will find records like chatcmpl-32ead6b1-… issued by Groq’s servers — cross-checkable against provider billing consoles.
And the decisive experiment takes ten seconds. Run any task with a bad key:
$ STRATUM_PROVIDER_API_KEY=bogus-key stratum run --repo ./demo-repo --task t
Task failed before approval: provider failed: provider returned 401:
{"error":{"message":"Invalid API Key",
"type":"invalid_request_error","code":"invalid_api_key"}}
A mock cannot make a remote service reject you. The deterministic test adapter exists strictly under tests/; production paths import only the httpx adapter. The acceptance suite additionally runs a vertical test against a live provider and a round-trip test against a live broker — the primary evidence path is real infrastructure, by design and by conviction.
The Stack, Briefly
- Core: Python 3.11, asyncio, plain dataclasses. The engine imports no web framework, no ORM, no agent framework.
- Providers: httpx against the OpenAI-compatible dialect — one seam, many vendors, zero SDK object-model leakage.
- Events: Redpanda via a thin Kafka producer/consumer wrapper; the rest of the codebase knows only a publisher interface.
- Persistence: stdlib SQLite, WAL mode, schema-versioned, two tables.
- Transports: argparse CLI and a FastAPI-hosted vanilla-JS console — both stateless clients of the same engine.
- Tests: 61 of them, including live-provider and live-broker acceptance gates that skip honestly when infrastructure is absent.
Who Gets What
- Representations seduce; consequences teach. Every hour spent polishing a projection of work was an hour not spent making work possible.
- Approval must cost the system something. A gate the engine can route around is decoration. Put the guard in the code path and let the error messages do the preaching.
- Mocks belong in unit tests, never in acceptance. The most valuable tests in the suite are the ones that would fail if a vendor changed their API tomorrow — because they actually call the vendor.
- Failures are findings. A verification command that exits non-zero and gets recorded honestly is worth more than a green checkmark that was never at risk.
The Call to Action
The next wave of agentic software will be judged not by how fluently it narrates its intentions but by how verifiably it acts. The tools we adopt will need to answer, durably and without hand-waving: what did you do, who allowed it, and can you prove both?
Stratum is my answer — small enough to read in an afternoon, opinionated enough to refuse lying to you, extensible enough to grow real capabilities on top. It runs locally, speaks to the provider you already have, keeps its promises in a broker you control, and treats your approval as the most important event in the stream.
Clone it. Point it at a disposable repository. Give it a tiny task. Approve the plan. Then try to find something in the event store that did not happen — that search will come up empty, and that emptiness is the product.
⚡ Try Stratum
The full benchmark — planning against a live provider, your approval, real file edits, verification, Redpanda streaming, and replay — is one clone away:
git clone https://github.com/mailtotanvir/stratum.git
cd stratum
# configure any OpenAI-compatible provider
export GROQ_API_KEY="your-key"
# install + start broker + run the live acceptance suite
cd stratum && uv venv .venv --python 3.11
uv pip install -e '.[dev,api]' && source .venv/bin/activate
docker compose -f ../docker-compose.redpanda.yml up -d
STRATUM_KAFKA_BROKERS=127.0.0.1:9092 pytest
# transform a real repository, with you holding the gate
printf 'y\n' | stratum run --repo ./example-repo \
--task 'Change the greeting returned by hello.py from "Hello" to "Hello Stratum".' \
--file hello.py --file test_hello.py --brokers 127.0.0.1:9092
Star the repo, break the approval gate (please — I want to know how), and watch the receipts accumulate in Redpanda. The event stream never blinks.