Building Software in the Age of AI Agents
Generating an implementation is only one part of building software. Someone still has to decide what the product should do, understand the constraints, and establish whether the result is correct.
Working with AI makes those responsibilities especially visible. A convincing implementation can arrive before the problem has been properly defined. If the requirements are vague, it becomes easy to build the wrong thing with impressive efficiency.
My view is that the most useful way to approach this era is to treat delegation as an engineering skill. Give an agent a clear outcome, a suitable environment, and a way to check its work. Then review the result with the same care you would apply to any other change.
Start with an Observable Outcome
“Improve the article page” leaves almost every important decision open. Does improvement mean faster loading, better typography, clearer navigation, or more accessible content?
A stronger task describes behavior that someone can observe:
Add a back link to the article page. If the reader arrived from the article list, return them there. If they opened the article directly, use the article list as the fallback. Keep the link accessible by keyboard and preserve the existing page transitions.
This gives the work a boundary. It describes the expected behavior, includes an edge case, and identifies an existing feature that must keep working.
Before delegating, answer three questions: What should change? What constraints matter? What evidence would demonstrate that the task is complete?
The answers do not need to become a long specification. A short paragraph with concrete acceptance criteria often gives the implementation enough direction.
Make the Repository Explain Itself
An agent needs access to the decisions that shape the codebase. A folder structure can show where files belong, but it rarely explains why a service must stay on the server or why a particular dependency is intentional.
Keep durable project knowledge close to the code. Repository instructions should explain how to run the application, which checks matter, where feature logic belongs, and which architectural boundaries must be preserved. Where framework behavior depends on the installed version, point to the matching documentation.
Be selective. Repeating generic advice across several instruction files creates maintenance work and makes contradictions harder to spot. Record the facts that a capable developer could reasonably miss when joining the project.
The repository itself should reinforce those instructions. Clear names, explicit interfaces, and focused modules make it easier to locate a change and understand its consequences. That benefits everyone who works on the software.
Delegate in Reviewable Steps
Large requests hide uncertainty. A task such as “rebuild authentication” combines product decisions, data modeling, security boundaries, and user interface changes. Reviewing the resulting patch can be harder than directing the work in smaller pieces.
Start by asking for an explanation of the existing flow and its failure points. Use that understanding to choose a bounded change. Implement it, verify it, and move to the next step with better information.
Parallel work is useful when tasks have clear ownership and few dependencies. Two agents changing the same interface can create conflicting assumptions even if Git merges their edits successfully. Define the shared contract first, then divide the work around it.
Keep each patch small enough to explain. If you cannot describe its behavior and tradeoffs clearly, reduce its scope before accepting more implementation.
Build a Feedback Loop You Can Trust
An agent reporting success is a claim to verify. Reading a diff, running a type checker, and opening the application provide different kinds of evidence.
A type checker can catch an incompatible value while missing an incorrect permission rule. A passing test can confirm the behavior it covers while overlooking a requirement nobody encoded. A page can render successfully and still fail during keyboard navigation.
Choose checks based on the change. For a bug fix, reproduce the failure and confirm that the same scenario succeeds afterward. For an interaction, exercise it in the running application. For a data boundary, check invalid input and unauthorized access as well as the expected path.
Tests also need review. A test that simply repeats the implementation's assumptions can preserve the mistake. Derive expected behavior from the requirement, and inspect what would actually cause the test to fail.
Ask for a completion report that connects the change to its evidence: what was implemented, what was checked, and what remains uncertain.
Keep Authority Explicit
Reading source files, editing a local branch, publishing a release, and modifying production data have different consequences. Give an agent the access its task requires, and make the boundaries clear before it begins.
Prefer reversible work while exploring a solution. A local patch or preview gives you something concrete to inspect before a consequential action. Keep credentials out of prompts and use the environment's supported mechanisms for access.
Human ownership continues after delegation. The developer accepting the change needs to understand its important decisions, its failure modes, and how to recover if it behaves unexpectedly.
Keep Learning Through the Work
Delegation can become a learning tool when you stay engaged with the reasoning. Ask why a particular approach fits the codebase. Compare it with an alternative. Trace a request through the changed code and check whether the explanation matches what actually happens.
When something fails, take time to understand the cause before requesting another patch. Otherwise, a series of plausible fixes can leave behind a system that nobody can confidently explain.
The habit worth building is deliberate ownership: define the outcome, provide context, inspect the implementation, and verify the behavior. AI can participate throughout that process. Your judgment gives the work its direction and determines when it is ready to ship.