In “Why Verification Should Be Defined Before Implementation”, I wrote that the definition of done is better established before a solution exists.

Working with coding agents added another boundary to this idea. It is not enough to define what a correct result looks like in advance. Implementation also needs to be separated from the decision about whether the evidence is sufficient.

At first, I tried to make agent work more reliable mainly through better prompts: more detail about the task, constraints, expected result, and required checks. That helps. But a longer prompt does not solve the fundamental problem.

The same agent can still implement the change, choose a convenient way to verify it, and then decide that the task is complete.

Over time, I started moving the definition of done out of the prompt and into an external, verifiable contract.

A Detailed Prompt Is Not Verification

A coding agent can follow a detailed task accurately and still verify the result too narrowly.

Suppose it is asked to fix a bug and add a regression test. The agent changes the code, writes a test for its solution, runs it, and gets a green result.

Every step looks reasonable. But the test may cover only the main scenario. Adjacent behavior may have changed. A public contract may have been broken. The diff may contain changes unrelated to the task.

One executor is effectively making several decisions:

how to implement the change
→ how to verify it
→ whether that verification is sufficient
→ whether the task can be considered complete

The problem is not necessarily the model. Combining these roles creates blind spots in ordinary software development as well.

With an agent, this becomes especially visible because done can appear a few minutes after a large series of changes and sound convincing even when the evidence is weaker than the report.

I Ended Up With Three Layers Before Implementation

I now try to separate requirements for agent work into three levels.

The first is permanent repository rules. These contain constraints that should not be repeated in every prompt: project structure, required checks, engineering boundaries, security requirements, and rules for making changes.

The second is the scope of the current task. This is where task-specific requirements remain:

what must change

what must remain unchanged

which parts of the project are in scope

which properties of the result must be demonstrated

The third is executable verification. If a requirement can be expressed as a test, linter, or reproducible command, I prefer that to a textual instruction such as “make sure everything works.”

For example, ashikov-garden has a canonical make check command for full project verification. The same command can be run by an agent, by a developer locally, and by CI.

The agent does not have to reinterpret this instruction every time:

check that the site is not broken

There is a more concrete contract:

make check

The check itself also needs verification. When I added file-ending validation, I tested not only valid cases but also inputs that the check had to reject.

A green gate is useful only when you know which violations are capable of making it red.

The Boundaries of the Change Need Verification Too

Passing tests are not enough.

An agent can fix the requested bug and at the same time change adjacent configuration, perform an unnecessary refactoring, or leave temporary files behind. Automated tests may still remain green.

That is why after implementation I look not only at behavior, but also at the change itself:

which files changed

what is actually in the diff

whether unrelated changes appeared

whether the stated constraints were preserved

For many tasks, ordinary git diff, git diff --check, and git status together with project tests are enough.

These checks answer different questions.

A test shows whether a particular property of the system still holds. The diff shows how the result was achieved. The working tree helps confirm that the agent stayed within the boundaries of the task.

For me, keeping the change limited to the task has therefore become part of verification rather than just another request in the prompt.

Done Is a Conclusion, Not Evidence

I care less and less about the agent simply saying that a task is complete.

What matters is the basis for that conclusion:

changed
→ what exactly

verified
→ with which commands

observed
→ what result

task boundaries
→ how they were confirmed

not verified
→ what remains unconfirmed

Some workflows in my repository already encode this directly. The agent must report the checks it actually performed and must not claim that a check succeeded if it was never run.

That changes the nature of the final report.

The agent does not need to convince me that the solution is good. It needs to provide observable facts from which that conclusion can be made.

But one problem still remains.

All of that evidence was collected by the same executor that wrote the code.

A Second Agent Reviews the Result With a Clean Context

For tasks where the cost of an error justifies it, I add another verification step: I give the result to another agent in a fresh context.

That does not mean the reviewer should know nothing about the task.

It needs:

the original task

repository rules

scope and constraints

acceptance criteria

the final diff

results of the checks that were run

What it does not need is the entire history of how the first agent arrived at the solution.

The implementation agent has seen its intermediate hypotheses, failed attempts, and explanations for the chosen approach. That context is useful while solving the problem, but it can become a liability during review.

If the second agent receives the same long conversation, it becomes easier to continue the first agent’s reasoning:

this solution was chosen because...
this check is considered sufficient because...
this compromise was already discussed because...

With a fresh context, the task is different:

here is the required result
here are the constraints
here is the resulting diff
here is the claimed evidence

find a reason why this should not be accepted

The reviewer starts from the task contract rather than from the explanation of the implementation.

This can expose things the executor missed precisely because it knows its own solution too well: an uncovered scenario, an unnecessary change, an incorrect assumption, or a check that does not actually prove the claimed property.

The review does not necessarily require a different model. Separating the roles and the context matters more: one run solves the task, another independently evaluates the result.

I also prefer the reviewing agent not to immediately fix everything it finds. First, it should provide a separate conclusion about whether the result satisfies the original contract. Otherwise review quietly turns back into implementation.

My Prompts Became Shorter, Not Longer

At first, adding more instructions to each prompt seemed like the natural way to make agent work more reliable.

Over time, stable requirements moved elsewhere.

General rules went into repository instructions. Repeatable processes went into skills. Reproducible verification went into project commands and CI. Independent review became a separate run that receives the original contract and the final result.

The task prompt is left with the information the agent cannot reliably derive from the repository: the goal, important context, and task-specific constraints.

My workflow increasingly looks like this:

task
→ scope
→ acceptance criteria
→ implementation
→ executable checks
→ diff inspection
→ evidence
→ independent review

This does not eliminate agent errors. Checks can be incomplete, acceptance criteria can be wrong, and a second agent can still miss a defect.

But the responsibilities become clearer.

The implementation agent chooses how to solve the problem.

The checks confirm predefined properties of the result.

The diff shows the actual scope of the change.

The second agent independently evaluates whether the evidence is sufficient for the original task.

For me, the quality of coding-agent work therefore depends less and less on how detailed a prompt I can write.

The prompt defines the work. The verification contract defines done. Independent review prevents the executor from being the only judge of its own result.