My AI Coding Setup Has Trust Issues
In this article
Codex writes the code. Claude and Kimi try to break it. Then Codex has to prove who is right.
Let's Kill the Multi-Agent Fantasy First
It's stupidly easy to romanticize AI coding agents.
Open three terminal windows. Give each one a dramatic name. Add a dashboard with blinking status indicators. Maybe put some cyberpunk wallpaper behind it. Congratulations, you are now apparently running an artificial intelligence software company from your bedroom.
Except you're not.
Most "multi-agent systems" I see are just several models talking to each other until one of them produces something confident enough to look finished. One model writes the code. Another says it looks good. A third suggests renaming a variable. Everyone congratulates everyone else, and somewhere inside the application a race condition quietly prepares to ruin your Friday night.
That's not a review system.
That's a group chat where nobody wants to be rude.
I started building my setup because I had a simpler problem: I liked coding with AI, but I didn't trust a model to review its own work.
And honestly, why should I?
If a developer implemented a large feature, wrote the tests, reviewed the pull request, resolved all the comments, and approved the merge alone, we wouldn't call that "efficient engineering."
We'd call it Tuesday at a badly managed startup.
Yet with AI, we accept exactly this flow. The model writes hundreds of lines, runs a few tests, reads its own diff, and announces:
Everything looks good. The implementation is production-ready.
Of course it thinks that. It just spent an hour building the damn thing.
The Problem With One Model Reviewing Itself
The issue isn't that the model is stupid. Modern coding agents are disturbingly capable.
The issue is context.
The agent that implemented the feature already has a story in its head. It knows what it intended to build. It remembers the decisions it made. It understands why that suspicious-looking condition exists.
When it reviews the result, it doesn't see only the code. It sees the code plus its intentions.
But users don't execute intentions. Computers execute code.
This is the same reason humans are bad at proofreading their own writing. You don't read what is on the page. You read what you remember writing. Missing words become invisible because your brain helpfully inserts them.
Coding agents do something similar. The implementation path anchors the review. Once the model has decided that a particular design is correct, asking it to "review carefully" does not magically delete that belief.
You can start a new conversation with the same model, and that helps. But I wanted stronger separation: different model families, clean context, independent reports, and no ability for reviewers to quietly "fix" the code while reviewing it.
I wanted reviewers, not co-authors.
My Setup Has Three Roles
The system I use now has three main participants.
Codex is the implementer. It reads the repository instructions, investigates the existing code, makes the changes, and runs the initial tests.
Claude Code is the first independent reviewer.
Kimi Code is the second independent reviewer and can be switched on or off depending on the size and risk of the task.
Then Codex returns as the final verifier.
That last part matters.
Claude and Kimi do not get to decide whether their own findings are correct. They report possible problems. Codex must trace each one through the actual code, compare it with the intended behavior, reproduce it when possible, and either accept or reject it with evidence.
The flow looks like this:
- I describe the task
- Codex investigates, implements, and tests
- A private snapshot of the change is created
- Claude and Kimi review it independently
- Codex verifies every finding
- Accepted findings are fixed
- The old review becomes stale
- Fresh reviewers inspect the new version
- Codex performs the final review and verification
There is no majority vote.
Claude and Kimi can agree and still be wrong. Codex can disagree and still be wrong. Three models can hold a unanimous election and still choose the bug.
Agreement raises priority. Evidence decides.
Reviewers Are Read-Only for a Reason
My external reviewers cannot edit the working tree.
They receive a private, immutable snapshot and are limited to reading and searching. Claude Code supports a planning mode intended for this kind of read-only analysis, and its permission system can restrict the available tools. Anthropic documents the permission model here.
Kimi is treated the same way.
This restriction sounds overly cautious until you imagine the alternative.
A reviewer spots something suspicious, edits it, adjusts a test, and then reports that everything looks fine. Now the review and implementation are mixed together. You no longer know what was originally reviewed, what changed, or whether the "fix" created another problem.
The reviewer's job is to accuse.
The implementer's job is to investigate.
I don't let the prosecutor quietly visit the crime scene at night and rearrange the furniture.
The Snapshot Matters More Than It Sounds
The reviewers do not inspect whatever happens to be sitting in my working directory when they wake up.
They inspect a fixed snapshot.
This solved a surprisingly subtle problem. An AI implementation can continue changing files while another process is reviewing them. Without a snapshot, Claude might read one file before a fix and another file after it. The resulting review describes a version of the code that never actually existed.
That's not a code review. That's time travel with bad synchronization.
The snapshot also has a fingerprint. If task-related code changes after the review, the previous result becomes stale and cannot be used as the final pass.
This seems obvious when written down:
A review is valid only for the exact code that was reviewed.
Yet it is very easy to violate in practice.
A reviewer returns "clean." You make one tiny fix. Tests pass. The diff looks harmless. You keep the old approval because rerunning the reviewers feels expensive.
But the old reviewer never saw the fix.
The change may be tiny. The logical impact may not be. So the system refuses to pretend.
New code, new review.
What the Reviewers Actually Return
I don't ask Claude and Kimi whether the code "looks good."
That question produces confidence-shaped fog.
They receive the task's intent, acceptance criteria, scoped code changes, relevant risk profile, and strict output instructions. Their reports separate concrete findings from test gaps.
A useful finding needs more than "this could be improved." It should identify:
- The location.
- The failure mode.
- The conditions required to trigger it.
- The likely impact.
- A way to verify it.
- A severity that means something.
Test gaps are tracked separately because "there should be a test for this" is not always a bug.
Sometimes the behavior is already covered elsewhere. Sometimes the suggested test would only duplicate an existing one. Sometimes the gap is real but low priority. And sometimes the missing test is the only thing standing between us and a future archaeological expedition through production logs.
Every item gets a decision:
- Accepted.
- Rejected.
- Uncertain.
- Already covered.
- Deferred.
And every decision needs evidence.
"Claude said so" is not evidence.
"Kimi agreed" is also not evidence.
"The code at this path performs this operation, this test reproduces the failure, and this change fixes it" is evidence.
What the First Real Runs Taught Me
The first version of this flow was simpler.
Codex implemented. Claude reviewed. Codex fixed the findings. Everyone went home.
Then I used it on something large enough to matter.
The reviewers found real problems. Good.
They also found things that sounded terrifying but were completely wrong. Also good, in a strange way. False positives are annoying, but they proved why Codex had to verify findings instead of blindly applying them.
A reviewer can produce an excellent five-paragraph explanation of a bug that does not exist. The explanation may include file paths, line numbers, a plausible runtime sequence, and enough confidence to make you reconsider your career.
Then you inspect the actual call path and discover that a guard three layers earlier makes the entire scenario impossible.
Without verification, the "fix" for that imaginary bug could create a real one.
The more important lesson came from testing.
A test can prove that a method was called without proving that the operation was correct. The arguments may have the wrong nesting. A field may be placed in the wrong object. The mocked call succeeds because the mock accepts anything, while the real database or external API would interpret it differently.
Green tests can be very persuasive liars.
So the workflow now treats sensitive side effects differently. For database writes, migrations, external APIs, authentication, and similar paths, Codex must verify the exact operation shape and the resulting postcondition.
Not just:
Was the method called?
But:
Was it called with the exact structure the real system expects, and did the intended state actually result?
That one change made the review process slower.
It also made it real.
Then the Review System Needed a Review
At some point, I realized something embarrassing: I had built a sophisticated system for finding bugs in code, but the system itself was code.
And yes, it had bugs.
In one version, two review decisions recorded at the same time could overwrite each other. The reviewers worked perfectly. The triage logic worked perfectly. The audit record quietly lost information because concurrent writes were not protected.
Beautiful.
The system designed to prevent race conditions had a race condition.
So decisions are now recorded through a locked transaction, with an atomic batch mode when several findings are resolved together.
Another issue appeared around commits.
A working tree could pass review, then be committed without changing its content. Technically the repository state changed, so a naive freshness check marked the review as stale. But the reviewed code and committed code were identical.
The solution was not to disable freshness checking. It was to add commit attestation: prove that the committed task scope is content-equivalent to the reviewed snapshot.
Same code, same review.
Actually changed code, stale review.
This is the kind of boring machinery that makes the system useful. The clever part is asking three models to inspect code. The reliable part is knowing exactly what they inspected.
One Command, Because I'm Still Lazy
Originally, I imagined typing a long instruction after every implementation:
Use the multi-model review workflow.
Run Claude and Kimi independently.
Verify every finding.
Fix accepted issues.
Rerun the reviewers.
Perform the final review.
That lasted about five minutes.
If I need to remember and correctly restate the process every time, I don't have a workflow. I have a ritual.
So I turned the whole thing into Codex Multi-Model Review, an open-source Codex plugin with a slash command:
/multi-model-review:multi-review uncommitted with-kimi
The command determines the relevant paths, creates the workflow, runs the reviewers, records their findings, guides the verification loop, and refuses to produce a final pass if something is pending or stale.
Kimi can be enabled globally, disabled globally, or included only for a particular run.
For larger or riskier changes, I use both Claude and Kimi on the first and final rounds. Intermediate repair rounds can be lighter. There is little value in summoning the entire AI United Nations every time Codex adds a missing null check.
The process is bounded to three review rounds. If the models are still arguing after that, the system stops and reports the disagreement.
Otherwise two agents can debate an edge case until the heat death of the universe while consuming enough tokens to fund a small municipal library.
When I Don't Use It
I don't run this flow for every change.
A typo does not need three model families, immutable snapshots, persisted triage, and a constitutional convention.
The full process makes sense when a change is:
- Large enough that one person cannot easily hold the whole diff in their head.
- Connected to authentication, money, data writes, external APIs, or other meaningful side effects.
- Difficult to reproduce manually.
- Going somewhere expensive to debug after release.
- Written mostly by an agent in one long session.
For small changes, Codex implements, tests, and reviews its own diff. That is usually enough.
The purpose of process is to reduce risk, not to cosplay as a regulated bank while changing button padding.
What This System Does Not Solve
Three models are not proof of correctness.
They can share blind spots. They can misunderstand the same requirement. They can all focus on the complicated part while missing the stupid part. They can produce a beautiful report about concurrency while nobody notices the function returns the wrong status code.
The system also costs time.
Independent reviews consume tokens. Verification consumes more. Fixes invalidate earlier reviews, so another round costs more again. A proper review can take longer than the implementation.
That is not always worth it.
There is also a risk of automation theater. A workflow ID, three JSON files, a green status, and an impressive terminal summary can create the appearance of safety without the substance.
A green badge is only useful if it means something.
Mine means:
- The reviewers inspected the same immutable source.
- They could not modify it.
- Every finding and test gap was triaged.
- Accepted issues were fixed.
- Relevant verification was performed.
- The final code still matches the reviewed fingerprint.
- Codex performed the last review.
- No unresolved high-severity issue remains.
It still does not mean "bug-free."
Nothing honest means that.
This Article Is Already Aging
The funniest part of writing about AI tooling in 2026 is that every sentence comes with an invisible expiration date.
The model names will change.
The commands will change.
Claude will add something. Codex will move something. Kimi will rename something. A feature described as experimental today will become the recommended default next week and disappear into a settings menu by Friday.
This setup works today.
We'll see what it worked like yesterday.
That is why I care less about the specific models than the structure around them.
Codex is my main agent today because I like how it works as an implementer and final verifier. Claude and Kimi give me independent perspectives. Tomorrow, one of those roles may be filled by another model entirely.
The names are replaceable.
The principles are not:
- The implementer does not approve its own work.
- Reviewers start with fresh context.
- Reviewers cannot edit the code.
- Findings are allegations until verified.
- Code changes invalidate old reviews.
- Tests must prove behavior, not ceremony.
- Irreversible actions remain behind a human gate.
- The workflow itself must be tested and reviewed.
Reliability does not come from finding one magical model. It comes from building a system around the model.
My addition is simple:
Sometimes that system should include another model whose job is to say, "Wait, this looks wrong."
And another one whose job is to check whether the first reviewer is full of shit.
No Grand Conclusion, Just a Gate
I still vibe code.
I still describe an idea in plain language and watch a machine turn it into working software at a speed that would have looked absurd a few years ago. I still enjoy the moment when a feature appears almost faster than I can properly explain it.
I just stopped confusing speed with correctness.
Codex builds.
Claude and Kimi attack.
Codex verifies what is real.
Tests settle the arguments.
The fingerprint makes sure everyone is still talking about the same code.
And I remain responsible for what eventually ships, because no matter how many agents I open in separate terminals, they all have one important thing in common:
None of them will be awake at 3 a.m. when production catches fire.
I will.