Ask a coding agent to implement a feature, and it will do it.
Ask another agent to review the code, and it will do that too.
Is that all you need to create production-quality software?
Hell no.
The problem is not that coding agents cannot write code. They can write an astonishing amount of it, astonishingly quickly.
The problem is that they are usually optimizing for the task directly in front of them:
Implement this feature.
So they implement the feature.
They are not automatically optimizing for the health of the system, consistency with the architecture, operational safety, future maintenance, or the sanity of the poor human who will be debugging it at 2:00 a.m.
An agent dropped into an established codebase is a little like a very fast new hire who skipped onboarding, missed every architecture meeting and has no idea why half the strange-looking decisions in the code exist.
It sees a problem. It writes a solution.
Often from scratch.
That may be fine for a genuinely new system. In a production codebase, it can create duplicated functionality, inconsistent patterns, code bloat, maintenance problems and a fresh mountain of technical debt.
And then there is the happy path.
The code works when the input is valid, the database is available, the network behaves, the user does exactly what was expected and Mercury is not in retrograde.
That is not production code.
Getting the feature to work is often less than 10% of the real job. The rest is making sure it fits into the system, fails safely, behaves predictably and does not break everything around it.
The Prompt Is Not the Specification
“Add support for this feature” is not a specification.
Before an agent starts writing code, it needs a clear, detailed and human-validated description of what the feature is supposed to do.
That specification should include:
- The expected behavior.
- Success and failure paths.
- Validation rules and error handling.
- Performance and operational expectations.
- Security and permission requirements.
- Metrics, logging and observability.
- Compatibility requirements.
- Explicitly excluded behavior.
- Clear acceptance criteria.
There should not be a collection of unanswered questions hiding inside the document. If the humans have not decided how the feature should behave, the agent will decide for them.
It will do so confidently.
Possibly with excellent formatting.
The agent should also be told to challenge the specification before implementation. It should identify contradictions, missing failure cases and ambiguous requirements. Those questions should be resolved by humans, not silently converted into code.
Tell It Where the Feature Lives
The agent also needs to understand the architecture around the change.
That means providing or identifying:
- The coding standards.
- The relevant architectural patterns.
- Existing modules and shared libraries.
- Similar features already in the codebase.
- Ownership boundaries between components.
- Expected data flows.
- Testing conventions.
- Deployment and compatibility constraints.
Without this context, the agent will often build the feature in isolation.
It may create a new validation framework when one already exists. A new HTTP client. A new retry mechanism. A fourth configuration loader. Another exciting interpretation of what a “repository” class should be.
The code may work perfectly and still be completely wrong for the codebase.
The instructions should explicitly require the agent to search for existing functionality before creating anything new. It should reuse shared code where appropriate and refactor existing code when that produces a cleaner result.
“Do not duplicate functionality” should not be an implied preference. It should be an explicit requirement.
Tests Are Part of the Feature
The agent should create tests for every success and failure path in the specification.
It should run those tests during every implementation cycle, not after it has finished writing several thousand lines and declared victory.
It should also run the broader test suite to detect side effects.
A feature is not complete because its new tests pass. It is complete when:
- The new behavior works.
- Invalid inputs fail correctly.
- External failures are handled.
- Existing behavior remains intact.
- Performance remains acceptable.
- Logging and metrics provide useful evidence.
- The implementation matches the specification.
The goal is not merely to demonstrate that the code can work.
The goal is to build evidence that it will continue to work inside the real system.
The Review Agent Needs Independence
A second agent can be useful for review, but only if it does more than admire the first agent’s homework.
The review agent should read the specification independently and build its own understanding of the required behavior.
It should first assess the quality of the specification itself. Is it complete? Are the acceptance criteria measurable? Are important failure paths missing?
It should then compare the implementation against that independent understanding rather than relying on the developer agent’s summary of what it built.
The reviewer should:
- Verify that every required capability was implemented.
- Run the feature using realistic and independently selected data.
- Run the complete test suite.
- Review test coverage and identify meaningful gaps.
- Search the codebase for duplicated functionality.
- Check adherence to established architecture and coding standards.
- Review error handling, security and operational behavior.
- Look for unintended changes to existing code paths.
For larger changes, it should perform two separate reviews.
The first is a normal code review: readability, maintainability, correctness and consistency.
The second is adversarial: how can this fail, how can it be abused, what assumptions are unsafe and what happens when every dependency has a bad day at once?
That second review is usually where production reality lives.
Agents Can Write the Code. Humans Must Define “Good.”
Coding agents are powerful because they make implementation dramatically faster.
But faster implementation does not reduce the need for specifications, architecture, testing and review. It makes those things more important.
When code becomes cheap to produce, bad code also becomes cheap to produce.
Lots of it.
The answer is not to avoid coding agents. The answer is to give them the information and constraints required to operate as part of an engineering system rather than as isolated code generators.
Give the implementation agent a complete specification, architectural context, reuse requirements, testing expectations and a clear definition of done.
Give the review agent independence, realistic data and permission to be deeply suspicious.
Then present the implementation, evidence, risks and review findings to the human in the loop.
The agent can write the feature.
It can help prove the feature.
But a human still needs to decide whether that proof is good enough to put into production.