Six Agents, One Board, and How I Find Out Whether They Are Telling the Truth

!Six agent workstations gather around a physical evidence board.

Six Agents, One Board, and How I Find Out Whether They Are Telling the Truth

*Published: August 26, 2026*

*This is Part 8, and the last of this run. Part 6 covers what transfers between runtimes. Part 7 covers the phone half.*

---

Six agents work for me. They have names, roles, their own memories, their own models, and a shared board. They pick up cards, do the work, hand it to a reviewer, and post a line to a channel when something changes.

Today, while I was writing the previous two articles, they opened two pull requests, wrote ten reports, created a missing build script nobody had noticed was missing, and finished six pieces of work I could verify. I did not watch any of it.

**Making that happen was the easy part.** The hard part, the part that took months and every scar in this series, is this:

When a machine tells you it finished something, that is a claim. Not a fact. Everything below is about the difference.

---

The six

Each is a separate profile with its own model, its own provider, its own memory and its own permission floor.

| Role | Does | Is not allowed to | |---|---|---| | **A chief** | Routes work, writes acceptance criteria, escalates | Implement anything | | A builder | Code, tests, scripts, anything with a passing command | Merge, force push, or review its own work | | **A reviewer** | Re-runs the acceptance command, tries to refute the claim | Implement the fix it found | | An outreach one | Research and first drafts to named humans | Send anything | | **A marketer** | Copy, campaign material, video scripts | Post live, or invent a statistic | | An accountant | Reads the finances, reports numbers with their derivation | File, pay, sign, or submit |

Those right-hand columns are not style guidance. They are enforced at the tool boundary by a hook that fails closed, and there is a script that plants a deliberate violation on every profile and requires each one to be blocked. **A rule in a prompt is a suggestion. A rule in a hook is a rule.**

I put them all in one room once and asked them to say hello. They describe their own jobs better than my table does.

!Six agents introduce themselves in a group chat, each naming the work it owns.

---

!A reviewer compares a raw command result with a physical artifact.

The reviewer runs on a different vendor, and it earned that within the hour

For months my builder and my reviewer ran on two models from the same family. Same vendor, same training, same blind spots. I called that a dual-model review and it was decoration: asking a model's sibling to check its homework.

Today I moved the reviewer to a genuinely different vendor. **Thirteen minutes later it rejected my own work, correctly.**

I had written an acceptance criterion for a short biography, and my criterion checked word count. The reviewer pointed out that the field it has to fit is measured in **characters**, that the draft was 321 characters against a 280 limit, and that word count was therefore the wrong property entirely.

It was right. I wrote the criterion, I was confident, and I had measured the wrong thing.

That is what a second vendor buys. Not a second opinion. A different set of blind spots.

---

!Only a real artifact passes the verification gate.

Why "done" is not a number I trust

Here is the thing that reframed how I supervise all of this.

**The runtime's own completion judge marks a goal that is blocked, or judged unachievable, as DONE.** So if I count done cards, that count is inflated by construction. Not by bugs. By design.

Here is the board on an ordinary evening. Seven waiting, three running, seventy-one done, eleven blocked. The tempting number is the seventy-one. The useful column is the eleven.

!A kanban board with seven cards to do, three running, eleven blocked and seventy-one done.

Worse, it never sees the work. It reads a few thousand characters of the worker's own prose about the work. Not the files, not the test output, not the diff.

So my daily review refuses to report a plain done count. It reports:

- **Done with a verified file on disk.** The card declared an artefact, and that path exists. This is the only honest count. - **Claimed done, artefact missing.** Treated as unfinished. - Blocked, with the full reason, deduplicated by card. One card blocking nine times is one problem, not nine. - **Running with a dead worker.** Reads as running until a four-hour timeout. Nothing else surfaces it. - Self-review violations, where a card's review ran as the profile that built it. Any non-zero fails the week. - **The canary.**

!A deliberately impossible card tests whether the gate still works.

The canary

There is a card on the board with a deliberately impossible acceptance criterion. It exists to fail.

If it ever reaches "done," the gate is broken and every other done card on that board is suspect.

That is a five-minute thing to set up and it is the single highest-value check I have. A gate nobody tests is indistinguishable from a gate that has quietly stopped gating.

!Six agents feed work into one shared board.

---

The acceptance criterion is the whole mechanism

Every card carries a command. Not a description of success. **A command, whose raw output must appear in the worker's response.**

Not: "the report is complete and well structured." But: `cargo test --lib data_export`, and paste what it printed.

I have written this rule down three times and broken it twice, so here is the honest version:

If I cannot name the command that proves an item finished, I do not understand it well enough to hand over.

That single test has killed more badly-specified work than any amount of careful prose. When I cannot write the command, the card is not ready.

<details> <summary>Three ways an acceptance command can be a fake gate</summary>

All three of these are mine, all from this month.

**One: it cannot fail.** I wrote a check with a regular expression where an escaped pipe meant a literal pipe rather than "or." It could never match a correct report. It was red by construction and would have failed a perfect submission.

Two: it passes on any match. A counting command exits successfully if it finds *one* of the seven things it is counting. Pasting "1" satisfies it. Enforcing "exactly seven" needs a real comparison, which meant writing a small script.

**Three: another line of the same brief guarantees it passes.** I once wrote a check that compared against committed changes, three lines above an instruction not to commit anything. It could only ever return zero. I now read every acceptance criterion against every constraint in the same brief.

Two independent reviewers found the first two, in the same criterion, on the same day, and each found a different one.

</details>

---

What actually happened today

Real numbers from the machine, not an illustration.

**Nine cards created. Six done with a verified file on disk. One claimed done with no artefact, which counts as unfinished. One blocked. Zero self-review violations.**

What landed: two pull requests, one on a desktop app and one on a website. Ten written reports. A build script that every one of my project plans referenced and which did not exist in the repository, now written and tested.

I did not count work I could not verify.

---

!A monitoring beam catches the machine that left no heartbeat.

The failure shape that bit me three times in one day

This is the most useful thing in the article, so I want to be precise.

**Three systems reported success while doing nothing. All three looked healthy.**

One. Two automation workflows firing every five minutes, reporting one hundred percent success, with zero-second durations and empty results. One of them had **never executed once in its entire existence**. Behind them sat 223 rendered marketing videos that have never been published, because the pipeline that was supposed to publish them was green and idle.

Two. My own review script reported a clean, quiet day across a day with fifteen real events. The timestamps in the database are integers; I compared them to a formatted date string. In that database, every integer sorts before every string, so the filter matched nothing, always. **And my own test passed, because I had written the test fixture using the same wrong assumption as the code.**

Three. A sync between my task manager and my notes had been dead for **eight days**. Killed, and I am not exaggerating, by an apostrophe in the word "card's" inside a comment explaining how the sync worked. The shell that ships with macOS is old enough to mis-parse that particular construct.

It survived eight days for two reasons that generalise:

It exited with a success code. I measured it afterwards: that failure mode returns zero. Anything asking "did the job succeed?" saw a clean run.

**My health check was not watching it.** It watched four jobs, by name, typed by hand. The broken one was not on the list. A hand-maintained watchlist only grows when someone remembers, so the thing you forget to add is exactly the thing nobody is watching.

What I changed, and it is small

**The watchlist discovers itself.** It enumerates every scheduled job rather than reading a list I typed. A new job is watched the moment it exists. Anything deliberately excluded has to justify itself in code.

Every scheduled job writes a heartbeat as its final act, and the check reads the heartbeat, not the exit code.

That second one is the whole lesson: **for a scheduled job, assert that the work happened, not that the process ended.**

I tested it in both directions, which I had failed to do the first time. I backdated the heartbeat by three days while leaving the exit code at zero. The check went red. I restored it. The check went green. My first attempt at that test deleted the script entirely, which produces a completely different failure code and proved nothing about the real one.

---

Two other models reviewed all of this before you read it

Before writing these three articles I gave both a written list of my fifteen findings and one instruction: **assume every one is wrong.**

They refuted five.

The one that matters most: I was about to tell you that my shared memory service was offline and my private network was down. Both models independently proved otherwise, and one of them found a write to that service dated the same day, from a third client. My claim was not partly wrong. It was wrong, and it fit a pattern I had already seen three times that day, which is exactly why I believed it.

They also caught me claiming a whole tooling lane was dead. **It was not. I had broken it myself**, by putting a stale copy of a program first on my search path, hitting an error, and reporting the error as a discovery.

And one of them found a real bug in a fix I had already declared verified.

It is the same trick as one model reviewing another's code. This time I pointed it at my own beliefs. It is uncomfortable every time and I have not once regretted it.

---

What this actually is

People keep asking whether this is an assistant. I do not think it is. The distinction matters.

An assistant waits for you. **This is a small operation that keeps working while I am not looking**, on a board that outlives any conversation, with a supervision cycle instead of my attention. I check once a day, read what was done, and correct what drifted.

The whole thing runs on a laptop, a phone, a tablet and a pair of earphones.

---

An idea I want to think out loud about

Several people have now asked how to build this. I have been wondering whether the useful thing to share is a guide, or something more.

Not a framework. Most of what makes mine valuable is the accumulated corrections: hundreds of specific ways I have been wrong, each one now a rule, each rule now a check. A starter kit ships an empty brain. The interesting part took months of being wrong in particular ways.

**But the loop is portable.** A correction becomes a rule, a rule becomes a check, a check becomes a mechanism that fails loudly next time. That shape is small, and it is the part that compounds.

So possibly: these articles as the guide, plus the smallest scaffold that makes the loop start turning. A couple of hundred lines and the reasoning behind each piece. Then your system grows because it accumulates your corrections, not because I shipped you mine.

I am genuinely undecided. Would this be useful to anyone else? I do not know yet.

---

Five rules I learned the expensive way

1. **A claim of completion is a claim.** Verify the artefact, never the status. 2. Name the command that proves it. If you cannot, the task is not specified. 3. **Assert the work, not the exit code.** A process ending tells you nothing. 4. Test your checks in both directions. Known-bad must fail. Known-good must be silent. A check that has never failed has never been tested. 5. **Have something with different blind spots try to refute you** before you act on your own conclusion.

Every one of those is written down because I broke it first.

---

*This is Part 8 of the EMMI-AI Infrastructure series.* *Part 1 · Part 2 · Part 3 · Part 4 · Part 5 · Part 6 · Part 7*

*Built by Emanuel Covasa in County Leitrim, and reviewed by two models that were told to prove me wrong.*

#AI #Agents #ClaudeCode #DeveloperTools #Verification #PersonalAI #Neurodivergent #ADHD #BuildInPublic