AI coding agents are part of my daily work now, on client projects and on side projects like this site. Over time I've stopped thinking of them as autocomplete and started treating them like a very fast new teammate. They've read every doc and none of the history, they never get tired, and they're confidently wrong often enough that review is never optional.
The quality of what I get back changed a lot once I changed how I hand work over. Here's the workflow I use, with real examples from this site's codebase.
Start with a written issue, not a chat prompt
A prompt disappears into chat history. An issue file stays around. It can be reviewed, prioritized, linked from other issues, and handed to a fresh agent session a week later without re-explaining anything.
In September I ran a full audit of this site with an agent: security, privacy, Server Actions, the database, caching, performance, SEO, accessibility, UX, design, the dashboard and tooling. The result was 83 tickets: 6 urgent, 27 high, 40 medium and 10 low. Each one is a markdown file with the same frontmatter and the same sections:
---
id: CACHE-01
title: Dashboard edits never invalidate the cached public pages
type: Bug
priority: Urgent
area: Caching
effort: M
status: Done
related: [API-04, SEO-01]
---
## Problem
## Evidence
## Impact
## Proposed fix
## Acceptance criteria
The Evidence section matters most. It makes the agent prove the problem exists before anyone fixes it: file paths with line numbers, a command that reproduces the issue, a screenshot, or a query. For CACHE-01, the evidence included a code search for cacheTag|revalidateTag|updateTag that returned zero matches, and a revalidatePath("/projects/[id]") call on a route whose segment is actually [slug]. That call compiled fine and did nothing. Two query bugs were confirmed by generating their SQL with Drizzle's .toSQL() and reading what would actually run.
An issue without evidence is a hunch. Hunches are fine, but they don't go into the fix queue.
Ask for a plan before any code
For anything larger than a one-file fix, I ask for a plan first: the goal, the approach, the files to create or modify, the steps, and how we'll verify it. Here's the shape of one from this repo, for adding automated tests:
# DX-04 Automated Tests Implementation Plan
**Goal:** Regression coverage for every completed urgent/high bug,
plus browser smoke and accessibility checks on preview deployments.
### Task 1: Cover the remaining completed urgent/high bugs
Files: tests/completed-bug-regressions.test.ts, tests/sitemap.test.ts
1. Add regression tests for A11Y-01, CACHE-01, SEO-01, ...
2. Verify the new sitemap test fails before the helper exists.
3. Extract sitemap assembly into a pure helper.
4. Run `pnpm test` and confirm everything passes.
Reviewing a plan takes a couple of minutes. Reviewing a wrong 600-line diff takes an hour, and by then everyone is anchored on code that already exists. The plan is also where I catch scope creep, like an agent deciding that a testing task is a good moment to refactor the data layer.
Tests are the contract
Agents are confident. Tests don't care about confidence.
For bug fixes the rule is simple: write a test that fails because of the bug, watch it fail, then fix it. This site has a regression suite named after the tickets it protects. The CACHE-01 test, for example, checks that every "use cache" reader in the service files also calls cacheTag, and that every content area's Server Actions invalidate its tag. If anyone, human or agent, adds a cached reader without a tag, the suite goes red.
The fast suite runs on Node's built-in test runner through tsx. Database queries run against PGlite, an in-process Postgres, so they're tested against real SQL without a database server. On top of that, Playwright with axe runs smoke and accessibility checks against every Vercel preview deployment.
I also have the agent run the checks itself before it reports back: tests, type checking, Biome and a production build. "It should work" isn't a status. Command output is.
Write down the project's rules
I keep an AGENTS.md in my repos with the things a new teammate would get wrong in their first week: how to run tests, naming and folder conventions, preferred libraries, and the quirks of the stack.
Next.js 16 makes a good case for this file, and it even writes part of it for you. Running next dev adds a block telling agents that this isn't the Next.js they know, and that they should read the docs bundled in node_modules/next/dist/docs/ before writing code. That's not an exaggeration: middleware.ts became proxy.ts, revalidateTag now expects a cache profile as its second argument, and caching is opt-in through Cache Components. Models trained mostly on older code will happily write the old version, and it often looks perfectly reasonable.
That one instruction prevents a whole class of plausible, outdated, subtly broken code.
Where agents still need me
Agents have taken over a lot of typing. They haven't taken over judgment.
- Deciding what matters. An agent-driven audit produces dozens of tickets quickly. Choosing the order (stop the bleeding, then foundations, then polish) is a product and risk decision.
- Catching plausible-but-wrong code. The bugs that matter compile. A cache that's never invalidated, an auth check on the page but not on the Server Action, a query that leaks rows through a missing condition. All of them look fine at a glance. I read every diff that touches auth, caching, payments or data access line by line.
- Holding the line on scope. Agents love to improve adjacent code. I ask for minimal diffs and reject unrelated changes, even good ones. Those can become their own ticket.
- Taste. Left alone, agents over-comment, over-abstract and add defensive code for situations that can't happen. Naming, structure and the right level of abstraction still need a human opinion.
- Context that isn't in the repo. Why a strange workaround exists, which customer depends on an odd behavior, what was tried last year and failed. If it isn't written down, the agent can't know it.
The workflow end to end
- Describe or audit. Turn the problem into an issue with evidence.
- Prioritize. That part is mine.
- Plan. The agent proposes, I review and adjust.
- Execute in small tasks. Test-first for bugs, one concern per change.
- Verify. The agent runs the full check suite, then I read the diff.
- Close the loop. Tick the acceptance criteria, update the ticket status, and commit with a conventional commit message.
None of this is new. It's how good teams already work with human engineers: clear problem statements, written plans, tests as the definition of done, and careful review. Agents just make the payoff obvious, because the better the input, the more of the work they can take on.
Share this article
Found this useful? Spread the word across your favourite networks or drop it in your team chat.
About the author
I’m Haris—partnering with product teams to ship resilient, measurable web experiences. Let’s connect if you’d like a deeper discussion about anything you read here or want to collaborate.

