# Maker vs Checker

Course: [Loop Engineering](https://www.devtutorials.ai/learn/loop-engineering) · Section: First Loop
Source: https://www.devtutorials.ai/learn/loop-engineering/first-loop/maker-and-checker

> The writer never grades itself. Watch a self-graded loop approve four broken fixes, then add a checker subagent with its own rubric that runs the tests.

## The Writer Never Grades Itself

The **maker** writes each fix. The **checker** decides if the fix is good. In this lesson, you will learn why they must be two separate parts. You will also give the checker a rubric that can say no.

In From Prompting to Loops, a loop with no checker called a broken fix "done".

Here is why that happens. The maker believes its fix works. That is why it wrote it.

So when the maker grades its own work, the answer is almost always yes.

**Simple lesson:** the part that writes the fix must not be the part that grades it.

### A Real-World Example

A student writes the answers to a test.

The student does not mark the test. The teacher does, with an answer key.

The student is not dishonest. But they already believe their answers are right. Marking their own work, they would see what they meant, not what they wrote.

A loop works the same way:

- **Student** = the maker.
- **Teacher** = the checker.
- **Answer key** = the rubric.
- **The most important line in the key** = "run the tests".

Click the button and watch the six tickets in the Loop Lab.

- **Every row:** says **self-graded**.
- **Four rows:** end in a red **false "done"**.
- **The scorecard:** 2 really fixed, 4 false "done".

## What You Will Learn

In this lesson, you will learn:

1. Why a wrong "done" hurts every later run.
2. What a checker rubric is.
3. The difference between a strict and a lenient rubric.
4. Why a checker must not copy the maker's prompt.
5. What happens to a rejected fix.
6. Where each tool keeps a checker subagent.

**About the lab tickets**

- Four tickets (#2, #7, #11 and #16) have a hidden flaw.
- The maker's **first** fix for each one breaks a test. Its second try is correct.
- A good checker catches the first try and sends it back.

## Why Self-Grading Fails

### Same Idea, Same Mistake

When the maker checks its own work, it uses the same idea that made the bug.

If it misread the ticket while writing, it misreads it again while checking.

Research on agent harnesses found the same thing. A separate checker, told to look for problems, catches far more than the maker grading itself.

### A Wrong "Done" Hides the Ticket

In a loop, a wrong "done" does more harm than one bad fix.

The loop only picks tickets that are not done yet. So a ticket marked done is never looked at again. Not in the next turn, and not in the next run.

Watch the self-graded run, then the real tests the next morning:

Step through all three frames.

- **Frame 1:** the run log. Every fix is graded by the maker.
- **Frame 2:** the real tests. Four of the six "done" tickets fail.
- **Frame 3:** the same tickets with a checker. Every broken fix gets a second try.

**Simple lesson:** a false "done" is not just one bug. It hides the ticket from every run after it.

## The Checker and Its Rubric

### What a Rubric Is

**Rubric** = the checker's answer key. It is a short list of checks the checker runs on every fix.

In the loop file, the rubric is a list under `checker:`:

```yaml
checker:
  rubric:
    - run pnpm test
    - read the diff for the ticket
```

### Strict vs Lenient

**Strict rubric** = it has at least one check that a program decides, such as running the tests.

**Lenient rubric** = it only looks at the code and judges how it seems.

| Rubric line | Strict or lenient? | Why |
|---|---|---|
| `run pnpm test` | Strict | A program decides pass or fail |
| `run dotnet build -warnaserror` | Strict | A program decides pass or fail |
| `read the diff` | Lenient on its own | A broken line can look fine |
| `check the code looks clean` | Lenient | "Looks clean" is a feeling |

Reading the diff is still useful. It catches a change to the wrong file.

But it belongs **beside** a test step, never instead of it.

### See a Lenient Checker in the Lab

Click the button and compare it with the self-graded run.

- **Every row:** now says **pass**, not self-graded. It looks better.
- **The scorecard:** still 4 false "done".

### A Checker That Copies the Maker

There is a second way to get a checker that cannot say no. You copy the maker's prompt into it.

Then the checker thinks like the maker. It agrees with every fix.

Here are both weak checkers, run on the same six tickets:

- **Frame 1:** two rubrics. Only one has a check a program decides.
- **Frame 2:** the lenient checker passes all four broken fixes. The strict one rejects them.
- **Frame 3:** a checker with the maker's prompt. It passes them too.

**Important:** a weak checker is worse than no checker in one way.

- It makes the loop **look** safe.
- Your report shows a checker passing every fix, so you trust it.
- Always give the checker its own rubric, with one step a program decides.

**Simple lesson:** a checker is useful only if it can say no. That needs its own rubric and a real test step.

## What Happens to a Rejected Fix

### Evidence, Not Claims

The maker does not tell the checker "it works". It hands over **evidence**:

- the diff, so the checker sees what changed
- the real test output, so the checker sees what failed

The checker runs its rubric on that evidence. Then it says **pass** or **reject**.

### Back Into the Loop

A reject does not stop the loop. The ticket is simply not done, so it stays in the queue. The loop tries it again.

Step through all four frames.

- **Frames 1 and 2:** the maker hands over evidence for #2. The tests fail, so the checker rejects it.
- **Frame 3:** the next turn tries #2 again. This time it passes.
- **Frame 4:** the cost is a few extra turns. The gain is zero false "done".

Nobody stepped in. The loop sent the ticket back by itself.

**Simple lesson:** a reject is the checker doing its job. A few extra turns are cheaper than a bug a user finds.

## Checkers in Each Tool

### Subagents

**Subagent** = a second agent with its own file of instructions. It does not see the maker's chat, so it cannot be talked into agreeing.

In real tools, the checker is usually a subagent.

| Tool | Where a checker subagent lives |
|---|---|
| Claude Code | A markdown file in `.claude/agents/`, for example `.claude/agents/checker.md` |
| Codex | A TOML file in `.codex/agents/`, with `name`, `description` and `developer_instructions` |
| Cursor | A markdown file in `.cursor/agents/` |

These layouts changed often in 2026. Check your tool's own docs before you rely on a path.

### What a Checker File Says

A checker file says three things:

1. **Who it is:** "You review fixes. You did not write them."
2. **Its rubric:** "Run the tests. Read the diff. Reject if either fails."
3. **What it returns:** "pass, or reject with one line saying why."

**Give the checker a different prompt.**

- Even with the same model, a checker told to look for problems finds more of them.
- A copy of the maker's prompt gives you a second maker, not a checker.

**Simple lesson:** keep the checker in its own subagent file, with its own job and its own rubric.

## Your Turn

### Lab Exercise: Give the Checker Its Own Rubric

This loop's checker copies the maker's prompt. Its rubric only says "looks done". It passes everything.

Click the button to open the loop file in the lab.

1. Under `checker:`, delete the line that copies the maker's prompt.
2. Replace the rubric with a step that runs the tests and a step that reads the diff.
3. Press **Check my loop**.

The check needs **0 false "done"** on all 3 versions. Every good fix must still pass.

**Simple lesson:** one deleted line and one test step turn a yes-machine into a real checker.

## TL;DR

1. **Maker** = writes the fix. **Checker** = decides if it is good. Never the same part.
2. **Self-grading** = the maker grades itself. Broken fixes are marked done.
3. **False "done"** = a broken ticket marked done. No later run looks at it again.
4. **Rubric** = the checker's answer key: a short list of checks.
5. **Strict rubric** = has a check a program decides, such as `pnpm test`.
6. **Lenient rubric** = only looks at the code. It lets broken fixes through.
7. **Shared prompt** = the checker copies the maker. It agrees with every fix.
8. **Evidence** = the diff and the real test output, not the maker's word.
9. **Reject** = the ticket goes back into the queue for another try.
10. **Subagent** = a second agent with its own instructions file.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Self-grading | "The agent ran the tests, so it checked itself." | A separate checker gives the verdict. | Broken fixes are marked done. |
| A shared prompt | "Same instructions keep them in sync." | The checker needs its own prompt and rubric. | The checker agrees with every fix. |
| A lenient rubric | "Read the diff" is enough. | Add a step a program decides: run the tests. | Fixes that look right but fail ship anyway. |
| Treating rejects as errors | "The loop failed, it rejected a fix." | A reject is the checker doing its job. | You loosen the rubric and let bugs through. |
| Trusting the checker's word | "The checker said pass, so it passed." | Look at what the rubric really ran. | A weak checker hides broken fixes behind green rows. |

## Check Your Understanding

## Exercises

Press **Check** when you are ready. Use **Show Hint** if you get stuck.

## What to Remember

- The maker writes. The checker grades. Never the same part.
- A false "done" hides a broken ticket from every later run.
- The checker needs its own prompt and its own rubric.
- A strict rubric has a step a program decides, such as running the tests.
- A weak checker makes a loop look safe while it lets bugs through.
- A reject sends the ticket back. The extra turn is cheap.
- Real tools keep checkers as subagents: `.claude/agents/`, `.codex/agents/`, `.cursor/agents/`.

## Further Reading

- [Harness design for long-running apps, by Anthropic](https://www.anthropic.com/engineering/harness-design-long-running-apps): separating the generator from a skeptical evaluator.
- [Loop Engineering and Autonomous Agent Systems, by Rick Hightower](https://rickhigh.substack.com/p/loop-engineering-and-autonomous-agent): "no verify step means not autonomous".
- [Loop Engineering, by Addy Osmani](https://addyosmani.com/blog/loop-engineering): subagents as one of the five building blocks.

Next: **Stop Rules**. A loop retries a flaky test all night, and you write the rules that make every loop end.
