What to Do While Your AI Coding Agent Writes Code

    When an AI coding agent takes over the keyboard, developers face a new question: what should I do during the few minutes it spends writing code? Scrolling your phone means missing the chance to correct course early, while watching every line burns your attention on low-value work. This article reframes the problem by weighing the costs of two extremes—full hands-off delegation and line-by-line scrutiny—and argues that the real job during the downtime is not to police the code but to define what "correct" means. You establish design intent before the agent generates output, review with focus afterward, and add system-level verification once it's done. It covers a layered review method, reusable checklists, and engineering practices that keep the feedback loop running on its own.

    AI coding agents have changed the mechanics of getting code written. What they haven’t changed is the moment of waiting: the few minutes while the agent produces a change. Developers now face a genuinely new question—what do I do while the agent writes? Scrolling your phone means missing the chance to correct course early; watching every line spends your attention on the parts least likely to go wrong. This article looks at the cost of both extremes and then reframes the problem: the core task during the downtime is not to monitor code but to use contracts to define what “correct” means.

    Why Both Extremes Have a Cost

    “Vibe coding”—the idea of immersing yourself in the flow of fast, high-throughput collaboration with an agent and, for a while, forgetting the code even exists—captures the experience well. But read it as “let it all go” and you can fall into a different trap. You click accept all the way through, the code generates, it runs. Then days later a strange bug appears. You spend two hours tracking it down, only to find the root cause was a design decision the agent made on day one that you never even noticed.

    That root cause is rarely a typo or a single misplaced condition—those surface at compile time or in unit tests. It’s usually a choice the agent made for you where there was no basis to decide: whether a table gets a unique constraint or relies on application-level deduplication, whether a failed task should retry or fail fast, whether a field may be null or must have a default. These decisions look unremarkable in the code, yet they quietly determine the system’s behavioral boundaries. The smoother the generation looks, the easier it is to let your guard down—and that is often the most expensive code.

    The other extreme carries a real cost too. Line-checking a standard CRUD endpoint—verifying every parameter validation and SQL statement—adds little value: the pattern is mature, the tools already run many checks, and your attention is spent where the fewest mistakes happen. The subtler risk is that the closer you look, the more you slide into “style review,” and the design decisions that actually shape system behavior get drowned out.

    Both extremes share one flaw: human attention is aimed at the wrong place. The question is not “should I look?” but “what do I look at, when, and in what role?”

    The Real Job of the Downtime: From Inspector to Designer

    To answer “what do I look at,” first understand the agent’s limits. It excels at local, pattern-driven implementation within a given context: writing endpoints, filling in tests, refactoring functions, and executing a plan that’s already been decided. What it struggles with is filling in the implicit constraints that were never written into the context—why a business rule exists, what production traffic actually looks like, which operations must never fail, why a module was changed the way it was six months ago.

    So the agent’s “local optimum” refers to more than local code; it’s a local point of view. It sees only the current task, not the coupling between tasks, not the consequences beyond the task. It writes the implementation that looks most reasonable in isolation, while system-level risk hides in the seams between one piece and the next.

    This defines the correct role for the downtime: it is a design window, not a monitoring window. While the agent generates code, you should be doing what it can’t—making implicit constraints explicit, and putting local implementations back into the context of the whole system. Concretely:

    • Before coding: state what “correct” means. Success criteria, the boundaries of inputs and outputs, expected behavior on failure, and the parts that must not be touched. The more complete the information, the less the agent has to guess for you, and the fewer decisions you’ll have to reconstruct after the fact.
    • During coding: don’t check line by line; compare against questions. Use the data flow and failure-mode list you drew yourself to compare against the implementation—what it covered, what it missed, and where it made a choice you didn’t authorize.
    • After coding: do system-level verification. Focus on how features interact, timing and state consistency across modules, and observability once it’s running.

    Before Coding: Define “Correct” With a Contract, Not Lines of Code

    The highest-leverage way to reduce rework happens before the agent writes its first line. You can’t review logic that doesn’t exist yet, but you can define the conditions it must satisfy. A lightweight task contract lets a team capture this. In essence, it writes down the definition of “done” up front, rather than guessing at the agent’s intent after the code exists.

    1. # Task contract example (illustrative; fields can follow your team's conventions)
    2. task: Batch export order data
    3. scope:
    4. include: [export_service.py, corresponding unit tests]
    5. exclude: [database table schema, frontend pages]
    6. invariants: # must hold for any implementation
    7. - An empty result set returns a success response with a header-only file
    8. - A single export is capped at 10000 rows; beyond that, reject with a clear error code
    9. - Resubmitting the same request does not create a duplicate export task
    10. acceptance: # acceptance criteria that convert directly into automated tests
    11. - Normal export produces complete fields with correct encoding
    12. - On dependency timeout, no data is lost and no partial file is written
    13. - Over-limit requests are rejected and produce no writes
    14. needs_human_decision: # decision points that must be made by a person
    15. - Whether an additional export audit record is needed
    16. - The timeout threshold value and whether it triggers an alert

    This contract does three things. First, it compresses the agent’s freedom into the “how,” while you lock down the “what” and “how far”—the design decisions that would otherwise surface three days later are pulled to the front. Second, the acceptance criteria convert directly into test cases the agent can run itself after writing the code, so pass/fail is objective. Third, the needs_human_decision field forces you to answer the questions the agent has no way to decide; if you can’t answer them, the requirement isn’t thought through yet—which is far cheaper to discover now than in later debugging.

    During Coding: Three Diagrams and One Checklist for Targeted Review

    1. Build a “correctness expectation” with a data flow diagram

    The most valuable practice here is simple: while the agent writes, sketch the feature’s data flow yourself, on paper or a whiteboard—where data enters, what transformations it passes through, where it lands, and how it returns. The diagram doesn’t need to be precise; the point is to force yourself to think through three things: what the input to each step is, how each step can fail, and which step is most likely to become a bottleneck.

    With this diagram, review shifts from “inspecting code” to “comparing against expectations.” A workable approach:

    1. After code is generated, locate key nodes in data-flow order:
    2. entry -> validation & auth -> core transformation -> storage/external call -> response exit
    3. For each node, ask four questions:
    4. 1. How is invalid input handled? What about boundary values (empty, over-limit, special characters)?
    5. 2. When this step fails, what state is the data in? Can it be retried? Will a retry duplicate work?
    6. 3. Under large-volume input, what happens to memory and response time?
    7. 4. Can downstream consumers actually use this step's output?

    2. A targeted checklist for failure modes

    The following is a general failure-mode checklist. It references no specific business domain and works as a questioning framework for reviewing the agent’s output:

    • Empty and boundary cases: empty lists, empty strings, null, oversized input, extreme numeric values, timezone and encoding differences.
    • Concurrency and timing: who wins when the same resource is modified concurrently; what happens if the order is reversed; whether race conditions exist.
    • Failure and recovery: timeouts, retries, idempotency; the data’s state on partial success; where the transaction boundary sits; how to compensate after a cross-service call fails.
    • Security and permissions: whether input is properly validated and escaped; whether permission checks sit at the right layer; whether sensitive data may end up in logs.
    • Observability: whether an error can be traced to a specific request and cause; whether key metrics are instrumented; whether the necessary alerts exist.

    Notice that the agent won’t consider any item on this list on its own—unless you put it in the task description.

    3. Guard the seams: interaction between new and existing features

    The class of problem an agent most easily overlooks is the seam between new code and existing code. It sees “implement this task,” while the system holds dozens of other features that share resources with it. So during the downtime, rather than line-checking the new code, concentrate on the seams most likely to break:

    • Shared state: Does the new feature read or write configuration, cache, or table fields that are used elsewhere? Is the write format compatible with old data?
    • Call order and timing: Does the new feature depend on a service that may not have finished initializing? What changes if startup order shifts?
    • Concurrent triggers: What happens when a user triggers two related operations at once? If both require “only one in progress at a time,” who enforces that constraint?
    • Failure propagation: Can an exception in the new feature bring down others in the same process? Is it swallowed somewhere so upstream never notices?
    • Configuration and release: What is the behavior when a new config item is absent? Do old clients or old data keep working?

    After Coding: Layered Review to Spend Attention on Decisions

    Once the code is generated, the most practical move is to layer the review by “cost of being wrong.” Look closely where the cost is high; skim the pattern-driven parts quickly.

    1. Layer 1: Contracts and interfaces (must read, a few minutes)
    2. Function/method signatures, external API paths and fields, table schemas, type definitions
    3. — highest change cost and widest blast radius; also the part most likely to slip through "accept-all"
    4. Layer 2: Control flow and state machines (focus here)
    5. Branch conditions, state transitions, loop termination conditions, paired resource acquisition and release
    6. Layer 3: Error handling and boundaries (follow the checklist)
    7. Exception types, return codes, retries and idempotency, input validation
    8. Layer 4: Implementation details and style (spot-check, or leave to tools)
    9. Variable naming, formatting, common code smells
    10. — leave to static-analysis and formatting tools; no need to verify each one by hand

    The key to layered review is admitting that human attention is finite. Rather than spreading effort evenly across every line, concentrate time on Layers 1 and 2—that’s where the decisions the agent made for you, without your knowledge, are hidden. You can treat the change itself as a code review: first look at what external behavior the diff adds or removes, then the key branches, and only then the individual statements.

    If you’re worried about missing something, append a “self-check” instruction asking the agent to review itself against the checklist before delivery and report its conclusions:

    1. Before delivery, self-check and answer each point:
    2. 1. Which external interfaces, fields, and data structures did you add or change?
    3. 2. Which design choices did you make on your own that the original spec did not specify? What were they, and why?
    4. 3. What happens with empty input, oversized input, and concurrent calls?
    5. 4. When a failure occurs, what state is the data in, and can it be safely retried?
    6. 5. Which behaviors changed in ways that could affect existing features?
    7. 6. Which parts are not covered by tests?

    The real value of this self-check isn’t the answers themselves—it’s that it exposes the places where “the agent decided for you and you didn’t know.” Pulling out item 2 alone usually reveals the decision points that need a human call.

    Make the Downtime Productive: Turn Waiting Into an Automated Loop

    Even with the right methods, if every generation is followed by half an hour of manual verification, the downtime just stretches out and you stay tied to the terminal. What actually makes the downtime valuable is letting the verification process run as automatically as possible.

    • Tests before generation. Have the key-path test cases (especially the acceptance criteria) written first, by a person or the agent, and run them the moment code is generated. An objective red/green signal is far more reliable than human eyes and removes the “should I look one more time?” hesitation.
    • Gates instead of watching. Automatically run static analysis, type checking, unit tests, and security scans before commit, and block the merge if any fail. Human review then only needs to cover what tools can’t: design soundness, business correctness, and cross-module impact.
    • Keep each change small. Have the agent complete one independently verifiable task at a time. The smaller the change, the easier to review and roll back; a single generation spanning several thousand lines across multiple modules is hard to guarantee quality on no matter how you review it.
    • Have the agent leave a decision trail. Ask it to list the assumptions and self-made choices in its completion notes. When you need to trace things later, this record is much faster than scrolling through chat history.
    • Set red lines that require human confirmation. Operations that delete or bulk-modify data, change table schemas, alter the permission model, introduce a new external dependency, or adjust encryption and authentication logic must not be executed by the agent directly—a person confirms them first.

    Conclusion: From Writing Code to Making Judgments

    The downtime while an agent writes code actually exposes a shift in role: the marginal cost of writing code is dropping fast, while the cost of judging what makes code correct has not dropped—and because generation is faster, that judgment now lands on the human more concentrated than before.

    So while the agent types in the terminal, you don’t need to scroll your phone or stare at every line. You should be drawing the data flow, listing failure modes, thinking through what happens when two features collide, and turning vague requirements into conditions you can verify automatically. And when it’s done, you go in with questions rather than checking aimlessly.

    What really separates good engineers isn’t who generates more code, but who already knows what the code should look like at the moment it’s being generated.