How to Build a Claude Code Agent Team That Runs in Loops
Don't want to figure this out alone? I walk members through every step inside the community. Join the Skool → skool.com/raycfu

Most AI coding setups run once and hand you whatever comes out. You get the code, you read through it, you find the bugs, you paste the errors back in, you wait for a fix, you test again, and you repeat until it works. You are the bottleneck at every step because you are the one relaying failures back and forth.
A looping team fixes this. Two agents run in a cycle. The Builder writes the code. The Checker tests it. If the Checker finds failures it sends them back to the Builder automatically. The Builder fixes the issues. The Checker tests again. This keeps going until everything passes or until the loop hits a hard stop rule. You type one command and the team handles the entire build-test-fix cycle without you touching the keyboard.
This guide gives you the exact files to create, the stop rules that prevent wasted tokens, and the orchestrator that runs the whole thing.
WHY TWO AGENTS INSTEAD OF ONE
When one agent writes code and then checks its own work, it grades itself with the same blind spots that created the bug in the first place. It wrote the code a certain way because it thought that was correct. When it reviews that same code it is biased toward agreeing with its own reasoning. That is why bugs slip through self-review.
Two separate agents fix this structurally. The Builder writes code and fixes code. That is all it does. The Checker runs tests, type checks, and linting. It never edits code. It just reports what failed. The Checker has no idea what reasoning the Builder used. It only sees the output and whether it passes or fails.
This separation is what makes the loop actually work. The Builder cannot fool itself into thinking broken code is fine because the Checker is an independent judge with no stake in what the Builder wrote.
THE FOLDER STRUCTURE
You need two folders in your project:
.claude/agents/ is where the two agent definition files live. Each one is a markdown file that tells Claude Code who the agent is, what tools it can use, and what model to run on.
.claude/commands/ is where the loop orchestrator lives. This is the command that chains the Builder and Checker together and keeps them cycling until the work is done.
You also need to add stop rules to your CLAUDE.md file in the project root.
FILE 1: THE BUILDER
The Builder writes code and fixes code. Nothing else. It does not test. It does not review. It does not decide if the code is good enough. It just builds what you asked for and fixes whatever the Checker reports as broken.
Create a file at .claude/agents/builder.md and paste this:
"--- name: builder description: Writes and fixes code. Invoke to implement a task or to fix failures the checker found. tools: Read, Write, Edit, Glob, Grep, Bash model: sonnet
You build and you fix. Nothing else.
On a new task: implement it, matching existing style. On a fix request: read the failure, find the cause, fix that cause only. Never weaken a test to make it pass. Fix the code. Report what you changed in one line."
Why the Builder runs on Sonnet: Implementation and bug fixing against clear instructions is exactly the kind of work Sonnet handles best. It is fast, accurate, and costs a fraction of Opus. Since the Builder runs multiple times per loop (once for the initial build and then once for every fix cycle), keeping it on Sonnet saves significant tokens over the course of a session.
Why the Builder never weakens tests: This is the most important rule. If the Builder is allowed to delete or modify a failing test to make it pass, it will eventually do that instead of fixing the actual code. The rule "never weaken a test to make it pass, fix the code" prevents the loop from faking a green result.
FILE 2: THE CHECKER
The Checker runs all your tests, type checks, and linting. It reports exactly what failed. It never edits code. It never tries to fix anything. Its only job is to tell the truth about what is broken.
Create a file at .claude/agents/checker.md and paste this:
"--- name: checker description: Runs all checks and reports what failed. Invoke after the builder. Never edits code. tools: Read, Grep, Glob, Bash model: sonnet
You check, you never fix.
Run all three, in order:
- Tests: npm test (or pytest -q, or cargo test --quiet)
- Types: npx tsc --noEmit (or pyright, or cargo check)
- Lint: npm run lint (or ruff check, or cargo clippy)
Then report in this exact format: All pass: 'ALL GREEN' Any fail: 'FAILED' then each cause as file:line - what broke - which check caught it
Never paraphrase a failure. Copy the real error. The builder fixes from your report, so a vague report wastes a whole cycle."
Adapt the test commands to match your project. If you are using Python, swap npm test for pytest -q and npx tsc --noEmit for pyright. If you are using Rust, swap for cargo test --quiet and cargo check. The structure stays the same regardless of language.
Why the Checker's report format matters: The Checker outputs failures in a specific format: file, line number, what broke, and which check caught it. This format matters because the Builder reads this report and uses it to locate and fix the problem. A vague report like "some tests failed" wastes an entire cycle because the Builder has to spend time figuring out what actually broke instead of just fixing it. A precise report like "src/auth.ts:42 - expected 429 got 200 - tests" tells the Builder exactly where to look and what to fix.
Why the Checker never edits code: If the Checker could edit code it would be tempted to patch around failures instead of reporting them accurately. Keeping the Checker read-only ensures it is an honest judge. The only thing it can do is tell the truth about what passed and what failed.
FILE 3: THE LOOP ORCHESTRATOR
This is the command that drives the cycle. It dispatches the Builder, then the Checker, then loops back to the Builder if anything failed.
Create a file at .claude/commands/loop.md and paste this:
"--- description: Run the builder and checker in a loop until all checks pass argument-hint: <task> allowed-tools: Read, Grep, Glob, Bash, Task model: opus
Run this task as a loop: $ARGUMENTS
- Write a one-line brief: goal, files in scope, definition of done.
- Dispatch the builder to implement the task.
- Dispatch the checker to run all checks.
- If checker says ALL GREEN: stop, show me the result.
- If checker says FAILED: send the failures to the builder to fix, then go back to step 3.
- Repeat up to 5 cycles. Track the cycle count out loud.
Stop conditions are in CLAUDE.md. Follow them exactly."
Why the orchestrator runs on Opus: The orchestrator is the decision maker. It reads the Checker's report and decides whether to loop again, stop for success, or stop because a rule was hit. This is a judgment call that benefits from stronger reasoning. And because the orchestrator only runs the lightweight coordination logic (not the actual coding or testing), the Opus cost is small relative to the Sonnet cost of the Builder and Checker doing the heavy work.
Why the orchestrator tracks cycle count out loud: Printing "Cycle 2 of 5" at each iteration lets you see where the loop is and how many attempts remain. Without this you have no visibility into whether the team is making progress or spinning.
FILE 4: THE STOP RULES
A loop without brakes either runs forever burning tokens or fakes a pass to exit. These rules prevent both. Add them to your CLAUDE.md file in your project root:
"## Loop stop rules
The team loops until one of these is true:
All green: every check passes. Stop and report success with proof. 5 cycles used: stop. Report what still fails and what was tried. Same failure twice in a row: stop. The builder is guessing, not fixing. Escalate to me. A fix makes a previously passing check fail: stop. Something is being broken to fix something else.
Never report success without checker output from the final cycle. Never weaken or delete a check to reach all green."
Why each rule exists:
The 5 cycle cap prevents infinite loops. Without it a stuck team burns tokens until your session runs out. 5 cycles is enough for most features. If 5 rounds of build-test-fix cannot solve the problem, a human needs to look.
The "same failure twice" rule catches guessing. If the Builder produces the exact same failure on cycle 3 that it produced on cycle 2, it does not understand the problem. It is trying random fixes hoping one sticks. That is the moment to stop and escalate because another cycle will not help.
The "breaking a passing check" rule catches destructive fixes. Sometimes fixing one test breaks another. If a previously passing check starts failing after a fix, something is being damaged to fix something else. That needs a human to decide the right approach.
The "never report success without proof" rule prevents fake passes. The final Checker output must be included in the success report. If the orchestrator says "all green" but cannot show the Checker's output proving it, something went wrong.
HOW TO USE IT
Open Claude Code in your project directory and type:
/loop add rate limiting to the login route, 5 attempts per IP per minute
Or:
/loop fix the flaky checkout test that fails 1 in 50 runs
Or:
/loop refactor the auth middleware to support both JWT and API key authentication
The orchestrator kicks off. It dispatches the Builder to implement your request. The Builder writes the code. The Checker runs all tests, types, and lint. If everything passes the loop stops and shows you the result. If something fails the Checker sends the exact failures to the Builder, the Builder fixes them, and the Checker runs again.
You watch the cycles tick by without touching anything:
Cycle 1: Builder wrote the feature. Checker found 2 failures. Cycle 2: Builder fixed both issues. Checker found 1 more edge case. Cycle 3: Builder handled the edge case. Checker says ALL GREEN. 14 tests passing. Types clean. Lint clean.
Three cycles. Zero manual intervention. You never copied a single error message. The loop handled everything.
WHAT A REAL RUN LOOKS LIKE
Here is an actual example of the loop running on a rate limiting feature:
You type: /loop add rate limiting to the login route, 5 attempts per IP per minute
Cycle 1: Builder writes rateLimiter.ts and edits login.ts. Checker runs tests. FAILED. login.test.ts:42 expected 429 got 200 (the rate limiter is not returning the right status code). rateLimiter.ts:18 'window' possibly undefined (type error).
Cycle 2: Builder fixes the 429 response and adds a null guard on the window variable. Checker runs tests. FAILED. login.test.ts:51 counter not reset after window expires (edge case the tests caught).
Cycle 3: Builder adds counter reset on window expiry. Checker runs tests. ALL GREEN. 14 of 14 tests passing. Types clean. Lint clean.
Done in 3 cycles. You never relayed a single failure. The Checker found them, the Builder fixed them, and the loop ran to green on its own.
COMMON MISTAKES TO AVOID
No cycle cap. Without "5 cycles max" a stuck team loops until your tokens run out or your session dies. Always set a hard cap. 5 is the sweet spot for most features. You can increase it to 7 or 10 for complex tasks but never leave it unlimited.
Letting the Builder check itself. If you combine building and checking into one agent you lose the structural advantage. The whole point is that the Checker has no knowledge of the Builder's reasoning. Keep them separate.
No "same failure twice" rule. Without this the loop will keep trying random fixes for a problem it does not understand. Two identical failures in a row means the Builder is stuck and more cycles will not help.
Vague Checker reports. If the Checker says "tests failed" without specifying which file, which line, and what the actual error was, the Builder wastes an entire cycle trying to figure out what broke. The report format with file, line, error, and check type is critical.
Letting the loop weaken tests. If either agent can delete or modify a failing test to make the suite pass, the loop will eventually discover that shortcut. The rules explicitly forbid weakening or deleting checks. The code gets fixed. The tests never get compromised.
Running the loop on tasks that are too large. The loop works best on bounded features. Add rate limiting. Fix a flaky test. Refactor a module. If you give it something massive like "rewrite the entire authentication system" the loop will hit the 5 cycle cap without finishing because the task is too big for one pass. Break large tasks into smaller pieces and run the loop on each one.
TIPS FOR GETTING THE MOST OUT OF IT
Start with a well-tested codebase. The loop is only as good as your test suite. If you have zero tests the Checker has nothing to run and the loop becomes a single pass with no verification. Write tests first, then use the loop to build features against them.
Run the loop overnight for larger features. Type /loop before bed with a bounded task. Wake up to either a green result or a clear report of what is still broken and what was tried. Either way you are further ahead than you would be doing it manually.
Review the cycle log even on success. When the loop finishes with ALL GREEN, read through what happened at each cycle. You will learn what kinds of bugs the Builder tends to create and what the Checker catches. Over time this helps you write better initial prompts that produce cleaner code on cycle 1.
Use the loop for bug fixes, not just new features. When you get a bug report, type /loop fix the bug where users see a 500 error when submitting the checkout form. The Builder investigates, writes the fix, and the Checker verifies it passes. Often faster than debugging manually.
Don't want to figure this out alone? I walk members through every step inside the community. Join the Skool → skool.com/raycfu
