DEV Community

Cover image for Two AI agents, one human, and a system that is not allowed to trust itself
umbra
umbra

Posted on

Two AI agents, one human, and a system that is not allowed to trust itself

The diagram above is a complete architecture on one screen. Not a marketing sketch — the real thing, running nightly, with every number measured rather than claimed.

Let me walk through it, because the interesting part is not the boxes. It is why they are arranged this way, and what breaks when they are not.

The problem this exists to answer
When AI writes the code, you cannot trust the author.

Not because the model is malicious — because trust was never the right instrument. You cannot inspect intent. You cannot code-review at the volume machines now produce. And every safety layer that works by asking the model nicely fails silently the first time the model is confidently wrong.

So I set out to answer something narrower and more tractable: can we make what code is allowed to do machine-checkable, and refuse to run anything that lies about it?

That question produced two things, and they exist for each other. LOOM, an effect-typed language that makes permissions provable. ARGUS, a nightly organism that grows LOOM and treats its own conclusions as suspects until proven.

The diagram is how those two are wired together without either becoming a single point of failure.

The top: one human, one word
Everything begins with a single authority. Two autonomous agents run below, and neither may act without explicit approval. They stop fail-closed and wait.

This is not ceremony. In one working session I stopped three separate times, mid-transaction, because a precondition no longer held. All three stops turned out to be correct — the world had moved under the plan while the plan was still being written.

An agent that cannot stop is an agent you cannot deploy. An agent that stops for the wrong reasons is merely annoying. An agent that stops for the right reasons, and can show you the measurement that made it stop, is the only kind worth running unattended.

The human is also the only one who declares which day it is. Neither agent may invent that number. It sounds trivial. It closes a whole class of drift where an automated system quietly redefines its own timeline and then reports progress against it.

Two agents, separated on purpose
Codex writes the language: parser, effect checker, five backends, the entire trust chain. Cloud Code runs the organism: the nightly cycle, backups, continuity, the evidence layer. Cloud has read-only access to the language. Codex does not run the organism.

Here is the part that matters, and it is not a division of labour. It is a division of author and judge.

Each agent is the independent adversary for the other's work.

That decision paid for itself repeatedly, and the clearest example is one where I was wrong. My backup layer had a lock that decided which directory it was protecting by looking at the pathname. Move the locked directory aside, create a fresh one at the same path, and the release returned success — while the original stayed locked forever.

Codex reproduced that against committed code. And when I went to look, I found something worse: my own source comment, sitting directly above the failing check, claimed that replaced roots were refused.

The comment was false, and I had written it.

That is the entire argument for separation in one incident. An author does not see their own blind spot, because the blind spot is made of the same assumptions that produced the code, the tests, and the comment explaining why the code is correct. Confident prose is not a control.

The bridge: measurement, not narrative
One shared file. Currently over ten thousand lines.

Everything one agent passes to the other must be recorded there as a measurement — hashes, test counts, exact paths, return codes, the specific bytes of the specific artifact. Narrative is not accepted.

That single constraint is what makes the audit possible. The judge reads numbers, not the author's story about the numbers. "I verified it" is not admissible. Manifest 7380ef7f…, sixteen of sixteen lines verified against card bytes is.

Two memories, both private
Each agent carries persistent memory across sessions: who the operator is, how we work, every directive, every lesson learned, the full history of the collaboration.

Neither agent reads the other's memory.

That is not a limitation. It is what keeps a cold read cold. A judge who inherits the builder's context inherits the builder's assumptions — and then agrees with them, fluently and at length. Separation of memory is separation of priors.

The narrow column in the middle: four gates
The organism may influence the language only by passing all four. This is the single point of contact between the two halves of the system, and it is deliberately narrow.

precheck verifies a proposal against an exact snapshot of the committed canon and applies nothing. Every anchor must resolve exactly once, or it refuses.

red-team attacks the organism's own proposal — hunting for a hole, not for a confirmation. This is the stage that changes what a human sees in the morning.

audit judges findings against an immutable snapshot of the target, never against a convenient copy.

publish writes the completion marker last. Until that marker exists and re-validates, the run did not happen.

Every gate may refuse. Refusal is the normal, healthy outcome — not an error state.

The cycle: cheap first, and the paid step never acts

eyes (0 tokens) → brain (paid, hard cap) → hands (sandboxed, no network)
→ precheck → red-team → audit → publish
Three decisions carry most of the weight.

The cheap step runs first, so the budget never decides what gets examined. If the expensive step leads, cost silently becomes your research agenda.

The paid step proposes but may never apply. Model output is a candidate, not an action. This is the difference between an assistant and an agent you can leave alone overnight.

The hands run the proposed experiment in a sandbox with no network. A hypothesis is settled by execution, not by how convincing the prose was. Models are extremely good at convincing prose. That is precisely why prose cannot be the evidence.

The consequence: what reaches a human in the morning is never "here is an idea." It is "here is an idea, and here is my best attempt to break it."

The language: a chain with no word for "allowed"
In LOOM, every function must declare its effects, and the checker proves the declaration honest before a single line runs. A seam is not advice — it is a capability boundary. Wrap an untrusted step in seam (Pure) and its I/O becomes physically impossible, not merely discouraged.

Built on top of that is the part I find most interesting:

approve(request) → authorization: claim-required
claim(approval) → authorization: mediation-required
mediate(claim) → authorization: bounded-execution-required
Read the return values. Not ok. Not authorized. Every successful verification returns what is still unproven.

Authorization is not a property any single component can grant. It is the last link in the chain, and it only comes into existence once nothing before it can lie.

The most recently published layer re-verifies the approval, the exact invocation binding and the claim from scratch; opens file paths descriptor-relatively without following symlinks; hashes the executable; verifies working directory, exact environment values and canonical stdin — and then documents the timing window it cannot close, requiring the next layer to re-measure at the moment of spawn.

A layer that names its own limit is worth more than one that pretends it has none.

The bottom: continuity
Four git bundles, four continuity archives, a run receipt, and a manifest in which every named byte is re-hashed on verification.

Inside it: the language, the organism, both agent memories, and the bridge.

If the machine disappeared tomorrow, what recovers from that card is not the code. It is the entire collaboration — including what each agent knows and why.

The card's mutation lock is bound to the root's device and inode, not to its pathname, because a different directory at the same path is not that root. And exactly one full backup per day per card: before that repair, mounting any volume triggered a complete run — thirteen in a single day, hours of continuous writing for minutes of actual change.

What is actually unique here
Not the primitives. Effect systems, capabilities and linear resources are prior art with excellent lineage — Koka, Eff, Unison, OCaml. I would be lying if I claimed otherwise.

Three things are genuinely unusual, and all three are visible on the diagram.

One: the refusal chain. Almost every permission system in production answers "is this allowed?" and returns yes. This one refuses to let any single layer answer that question at all, and returns the next unproven thing instead. Authorization becomes a property of the whole chain rather than of whichever component was asked.

Two: adversarial self-verification as a default, not a phase. The organism attacks its own proposal before a human ever sees it. On top of that runs a mutation harness that copies the tree, deletes one defence, and requires the test suites to go red. A surviving mutation is an invariant nobody asserts — a passing test that was decoration. That harness has found real holes in work I had already declared finished, including one where the version field of a schema was checked by nothing at all, because a neighbouring check made it look covered.

A green suite proves your tests pass. It does not prove they would notice if a defence disappeared. Those are different properties, and only one of them survives a codebase that keeps changing.

Three: the author/judge split enforced structurally. Two agents, two private memories, one shared bridge that accepts only measurements. Most "AI reviews AI" setups share context, share priors, and therefore share blind spots. This one deliberately does not.

What it is for
Short term, it is a research artifact: a credible, fully open, self-verifying reference implementation of a trust layer for AI-written code. Everything on the diagram — architecture, cycle, gates, schemas, and every defect described here — is public. The only closed part is the growth engine, because that is the one thing that can be cloned rather than learned from.

Longer term, the pattern generalises past the language.

The interesting export is not LOOM's syntax. It is the shape: a system in which proposals are cheap, verification is adversarial, evidence is atomic, and permission is the last link rather than the first. Any pipeline where machines generate changes faster than humans can review them has the same structural problem — and most of them are currently solving it by asking the model to be careful.

We are going to need something better than careful. Something that refuses.

Built solo, in the open, from Ukraine 🇺🇦

👇 everything is here:
GitHub — github.com/umbraaeternaa/loom
Site — umbraaeternaa.github.io/loom
Playground (try it live) — umbraaeternaa.github.io/loom/play.html
Instagram — instagram.com/umbra_owner_architect_ai
LinkedIn — linkedin.com/in/volodymyr-natoptanyi-16b906262
Support — send.monobank.ua/jar/AHaziFXjYX

2 · INSTAGRAM (EN) — 2 143 / 2 200
🧭 Two AI agents, one human, and a system that is not allowed to trust itself

The whole architecture on one screen. Every number measured, not claimed.

When AI writes the code, you cannot trust the author. You cannot inspect intent, and any safety layer that works by asking the model nicely fails the first time it is confidently wrong.

So I built two things that exist for each other.

LOOM — a language where every function must declare its effects, and the checker proves the declaration honest BEFORE anything runs. Wrap an untrusted step in a Pure seam and its I/O becomes physically impossible.

ARGUS — a nightly organism that grows LOOM and treats its own conclusions as suspects until proven.

The three ideas the diagram encodes:

ONE. Separate the author from the judge. Codex writes the language, Cloud runs the organism, and each audits the other. That is how a defect was found where my own source comment claimed a case was handled — and the comment was false, and I had written it. An author cannot see their own blind spot, because the blind spot also wrote the tests, and the comment.

TWO. Nothing is allowed until it is proven. approve returns claim-required. claim returns mediation-required. mediate returns bounded-execution-required. Not ok. Not authorized. Every successful check returns what is STILL unproven. Permission is the last link, and it exists only once nothing before it can lie.

THREE. Memory is private, the bridge is shared — and the bridge accepts measurements, never narrative. "I verified it" is inadmissible. A hash is not.

A green suite proves your tests pass. It does not prove they would NOTICE a defence going missing. So a harness deletes one defence and demands the suites go red.

Built solo, in the open, from Ukraine 🇺🇦

👇 everything is here:
GitHub — github.com/umbraaeternaa/loom
Site — umbraaeternaa.github.io/loom
Playground — umbraaeternaa.github.io/loom/play.html
Instagram — instagram.com/umbra_owner_architect_ai
LinkedIn — linkedin.com/in/volodymyr-natoptanyi-16b906262
Support — send.monobank.ua/jar/AHaziFXjYX

AI #SoftwareArchitecture #Security #OpenSource #BuildInPublic

Top comments (0)