← Back to homeai

Shipping with AI Coding Agents: Workflows, Guardrails, and Review in the Agentic Era

← All writing

Somewhere in the last two years, the question quietly changed from "should we let AI write code?" to "how do we run a team where AI writes a lot of the code?" At Luminary — a small senior team building web products for clients — coding agents like Claude Code, Cursor, and GitHub Copilot's coding agent are part of every working day. Not as a novelty, and not as a replacement for anyone: as a new class of collaborator — fast, tireless, occasionally brilliant, and completely without judgment unless you supply it. This is the writeup we wish we'd had when we started: what agents are genuinely good at, how to make a repository agent-friendly, the workflow patterns that survived contact with real client work, and the guardrails that keep an enthusiastic agent from becoming an incident report.

Illustration: small robots at desks while a human reviews their work at a corkboard

From autocomplete to agents

The first wave of AI coding tools was autocomplete with better manners: you typed, it suggested, you accepted or didn't. The unit of interaction was a line, maybe a function — useful, but passive.

Agents are a different species. A modern coding agent reads the repo (greps, follows imports, builds its own working model before touching anything), runs commands (your tests, linter, build — and reacts to the output), iterates (a failing test is the middle of the interaction, not the end), and produces reviewable artifacts — a branch, commits, a pull request explaining what it did and why. The unit of interaction moved from the line to the task: "add rate limiting to the two public API routes, follow the pattern in the middleware, and add tests" is a reasonable prompt now, answered with a branch to review rather than a snippet to babysit into place.

This shift has a consequence people underestimate: the bottleneck moves. When the tool suggests lines, your typing speed and attention are the constraint. When the tool ships branches, your review capacity is the constraint. Most of this post is downstream of that one fact.

What agents are good at — and where they burn time

Misallocating agent work is expensive in both directions: delegate too little and you're paying senior engineers to write test boilerplate; delegate too much and you spend Thursday untangling a plausible-looking refactor that subtly broke your caching semantics. The boundary as we experience it:

Genuinely strong todayStill burns time
Mechanical migrations (API version bumps, framework upgrades, codemods with judgment)Deep architectural decisions with long-term consequences
Test backfill for existing behaviorSubtle concurrency, race conditions, and distributed-systems edge cases
Boilerplate: CRUD endpoints, form wiring, config plumbingAnything where "correct" depends on taste or product intuition
Exploring unfamiliar code — "explain how auth works in this repo"Knowing which of five working solutions the team will still like in a year
Wide-but-shallow changes (rename across 80 files, add a field everywhere)Narrow-but-deep changes (rework the core state model)

The pattern underneath the table: agents excel where the definition of done is checkable — tests pass, types check, old and new APIs produce the same output — and struggle where done is arguable. A migration has a checkable end state; "make the dashboard feel faster" does not, and an agent will happily generate three hundred lines of memoization that makes it feel exactly the same.

Exploration is the underrated one. Dropping an agent into an unfamiliar client codebase and asking "where does billing state live, and what writes to it?" routinely saves us the first half-day of a takeover project. The answer isn't always complete, but a mostly-correct map beats no map.

Repo readiness: making your codebase agent-friendly

Agents inherit your codebase's ergonomics. A repo that's miserable for a new hire — undocumented setup, slow tests, tribal knowledge in someone's head — is exactly as miserable for an agent, except the agent won't ask the person next to them. Agent-friendliness is onboarding investment with a much faster payback loop.

Instruction files are the new README

Every serious agent tool reads a project-level instruction file — CLAUDE.md for Claude Code, the cross-tool AGENTS.md convention adopted by Codex, Cursor, and others. It's the highest-leverage document in your repository, because it's read at the start of every agent session. Ours answer three questions: what is this, how do I verify changes, and what will bite you.

# CLAUDE.md

## What this is
Marketing site for a design studio. Next.js App Router + TypeScript.
All styles live in app/globals.css — no Tailwind, no CSS modules.

## Commands
- `npm run dev` — dev server on :3000
- `npm run build && npm run lint` — run BOTH before declaring done.
  There is no test suite; build + lint is the verification bar.

## Rules that will bite you
- Never hardcode the accent color. Use `var(--accent)`.
  Canvas components read it from computed styles at runtime.
- components/Interactions.tsx wires animations by CSS class name
  (.up, .rev-l, .svc-card). Markup is coupled to these classes
  by convention, not by import. If an animation doesn't fire,
  the class is missing — don't rewrite the observer.
- Sections commented out in app/page.tsx are intentionally
  hidden (placeholder content). Do not re-enable them.

Notice what this file is not: an architecture essay or a style guide. It's the stuff a sharp contractor would trip over in their first week, written down. The "will bite you" section earns its keep most — invariants that exist by convention rather than by type system are precisely what agents violate, because nothing in the code enforces them.

Fast feedback is the real guardrail

Instruction files tell agents what to do; your toolchain tells them when they're wrong. Agents iterate against feedback, so output quality is roughly proportional to the quality and speed of your checks. A fast test suite is the difference between an agent that self-corrects and one that hands you broken code with confidence — twenty-minute tests mean one or two shots per task instead of ten. Strict lint and type checking convert "conventions someone knows" into "errors the agent sees"; every rule expressible in ESLint or the compiler is a rule you never catch in review. One-command verification (npm run check, make verify) removes ambiguity about what "done" means — if verification takes four commands and a manual step, the agent skips the manual step every time, and so, honestly, do your humans.

The uncomfortable corollary: teams with weak test coverage get the least out of agents on exactly the tasks agents are best at. If that's you, the first agent task to assign is test backfill — the strongest use case, and one that compounds every future one.

Workflow patterns that actually work

After a lot of experimentation, three patterns account for nearly all our agent usage.

Agent first draft, human owner

The default. A named engineer owns the task; the agent produces the first draft; the engineer reviews, edits, and ships it under their own name. Ownership never transfers — the agent is a fast pair of hands, not a party to the commit. This matters because the failure mode of agent adoption isn't bad code, it's orphaned code — changes nobody fully understands because everybody assumed the agent understood them. Our rule is blunt: if you can't explain a diff you're merging, you're not done reviewing it.

Parallel agents for independent tasks

Agents don't context-switch, so we stopped pretending work is serial. On a typical afternoon one agent is backfilling tests, another is migrating an API route to a new SDK version, while the engineer supervising both does the design-heavy work agents are bad at. The tooling supports this natively — Claude Code runs subagents in parallel and isolates work in git worktrees; Copilot's coding agent runs asynchronously in the cloud and comes back with a PR.

Two constraints keep it sane. Tasks must be genuinely independent — two agents editing the same module is merge conflicts with extra steps. And parallelism is bounded by review capacity, not agent count: three unreviewed agent branches aren't progress, they're inventory.

Plan, then execute

For large changes — a framework upgrade, a data-model rework — we split the interaction: ask the agent to investigate and produce a plan, review the plan as a document, and only then let it execute. Most agent tools support this natively (Claude Code's plan mode, for one), and it front-loads human judgment to where it's cheapest: rejecting a wrong plan costs five minutes; rejecting a wrong 3,000-line diff costs an afternoon and some goodwill. Plan review is also where senior experience earns its keep — "step 4: update all call sites" is a red flag worth catching before the agent discovers there are 200 call sites with two incompatible usage patterns.

The review bottleneck

The uncomfortable arithmetic: agents increase the supply of code without increasing the supply of judgment. If your team could review N pull requests a week before agents, it can review roughly N after — and now there are more of them, they're larger, and they're written in a uniformly confident style. Human-written code telegraphs its author's uncertainty; agent code does not. The hesitation is gone, but the mistakes aren't.

Adaptations that actually helped us:

  • Smaller PRs, enforced. The single biggest lever. An agent will happily deliver a 2,000-line branch; nothing obliges you to accept one. Ask agents to decompose work into sequential PRs the way you'd ask a person to — review quality falls off a cliff with diff size.
  • Review the tests first. Tests are a compressed statement of what the change claims to do. If they're shallow, wrong, or asserting the mock rather than the behavior, stop — the implementation doesn't matter yet. This also catches the classic agent move of making a test pass by weakening the test.
  • Provenance labels. Agent-authored PRs are labeled as such (Copilot's coding agent does this automatically; for terminal agents we use a label and co-author trailers). Not as a scarlet letter — the review bar is identical — but so reviewers know to check for characteristic agent failure modes: invented APIs, over-general abstractions, silent behavior changes in code the diff "just cleaned up."
  • Review for intent, not syntax. Lint and CI caught the mechanical stuff. The human question is whether this does the right thing and whether we want to live with its shape. Spending review attention on formatting an agent's code is a category error.

Guardrails: containment before capability

Every guardrail below exists because the alternative eventually happens. Agents are agreeable, literal, and fast — a combination that turns small ambiguities into large messes at machine speed.

Sandboxing and permission modes. Modern agent tools run with OS-level sandboxing and explicit permission gates: reads are free, writes and shell commands are mediated, network access is scoped. Use them — "auto-approve everything" is a setting for demo videos, not for a machine with production credentials in its environment. Tune the gates to sit at irreversibility: free to read and experiment, checked at the moments that are hard to undo.

Protected branches, no exceptions. Agents get no direct push access to anything that deploys. Our own flow is feature/* → PR → dev → PR → prod, with rulesets blocking direct pushes to both integration branches — for humans and agents alike. The agent's write access ends at the pull request.

CI as the arbiter. The merge gate is a status check, not anyone's assurance — including the agent's. Agents report success optimistically ("all tests pass!") based on a partial run or stale state; CI doesn't. A minimal policy fragment:

# .github/workflows/ci.yml — the merge gate agents can't talk past
name: ci
on:
  pull_request:
    branches: [dev, prod]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: npm }
      - run: npm ci
      - run: npm run lint
      - run: npm run build
# Branch ruleset (configured in repo settings):
#   - require PR before merging, require "verify" to pass
#   - block force pushes and deletions
#   - no bypass actors — not admins, not bots, not agents

Never let agents deploy to production directly. Preview environments, fine — genuinely useful, even. But the path to production runs through a human clicking merge on a reviewed PR with green checks. That click is the accountability boundary, and it stays human.

Security: the parts that are actually new

Two threat classes are specific to the agentic era.

Prompt injection via repo content. An agent that reads your repository treats everything in it as context — a README in a third-party dependency, a comment in a vendored file, an issue body it fetched, the output of a compromised MCP server. Any of those can carry adversarial instructions aimed at the agent rather than the human. The defense is layered, not clever: least privilege, secrets kept out of agent-readable environments, scoped outbound network access, and everything the agent produces still passing through review and CI. Treat agent-ingested content like user input — untrusted by default.

Dependency hallucination and slopsquatting. Models sometimes cite packages that don't exist — plausible names conflated from real ones. Attackers noticed: register the hallucinated name on npm or PyPI, then wait for someone (or some agent) to install it on a model's recommendation. The term of art is slopsquatting, and it isn't hypothetical — a USENIX Security 2025 study of 16 models across 576,000 generated code samples found roughly a fifth of recommended packages didn't exist, with hallucinated names following predictable, registerable patterns. Mitigations are mostly hygiene: lockfiles, supply-chain scanning in CI, a human eyeball on any new dependency an agent proposes, and a standing rule in your agent file that adding dependencies requires explicit approval.

Instruction rot is the new documentation rot

Instruction files decay the way wikis do, but the failure is worse: a stale wiki is ignored, while a stale CLAUDE.md is actively followed by every agent session, at scale, forever. If it says the test command is npm test and you've moved to vitest, every agent run starts with a lie.

What keeps ours honest: update the instruction file in the same PR that changes the convention it describes — part of the change, not a follow-up. Let the agent propose the edit — when it hits a discrepancy mid-task, the cheapest moment to fix the doc is right then, by the party that found it. And prune quarterly — a 400-line instruction file is functionally an unread one; shorter files followed consistently beat comprehensive files followed approximately. The same rot applies to skills, slash commands, and MCP configurations: anything an agent consumes automatically needs an owner, or it needs to be deleted.

Measuring impact honestly

The temptation is to measure agent impact in volume — lines generated, PRs opened, "acceptance rate." All of these go up when things get worse: more unnecessary abstraction, more PRs clogging review, more accepted suggestions rewritten a week later. Lines of code was a bad metric when humans wrote them all, and it didn't improve.

Measure the things you cared about before agents existed: cycle time (idea to production, per change — the number agents should actually move), review latency and PR size (leading indicators of the bottleneck above), rework rate (how often merged code gets substantially modified within weeks — the honest counterweight to speed), and escaped defects (if this rises while cycle time falls, you've automated the production of bugs).

And accept an unglamorous truth: on small teams the biggest wins often don't fit a dashboard — the migration that was never going to get scheduled, done in an afternoon; the test suite that finally exists. The honest posture is "cycle time plus judgment," not a single agent-productivity number.

Growing juniors when the agent writes the boilerplate

The standard worry: juniors learned by writing the boring code, agents now write the boring code, therefore juniors stop learning. The premise is half-right and the conclusion doesn't follow. Grinding through boilerplate was never the point — it was the available form of repetition. What builds engineers is forming a hypothesis, being wrong, and finding out why, and agents compress that loop dramatically: a junior can attempt things that used to be out of reach, get a working draft, and — the crucial part — be required to understand and defend it.

The discipline that makes this work, for the juniors we mentor and frankly for ourselves:

  • You can explain every line you ship. "The agent wrote it" is never an answer in review.
  • Some work stays manual on purpose. Debugging without the agent, reading framework source, writing one gnarly thing by hand — deliberate practice, prescribed like a workout.
  • Use the agent as a tutor, not just a typist. "Explain why this approach over the alternative" is the highest-value prompt a learning engineer has — available on demand, without embarrassment, at 11pm.

The engineers who struggle in the agent era aren't the ones who use agents too much; they're the ones who use them as an oracle rather than a collaborator, accepting output they can't evaluate. That failure mode existed with Stack Overflow — this is just higher bandwidth.

What we expect next

Predictions, lightly held. Review tooling catches up — the gap between agent code-production and human review capacity is too obvious a market to stay open; expect review interfaces built around intent-and-risk summaries rather than raw diffs. Long-running agents get boring — cloud agents that take a ticket and return a PR hours later will become as unremarkable as CI, which also once felt exotic. Instruction files become load-bearing infrastructure — versioned, linted, owned, with AGENTS.md-style conventions hardening into a standard. The capability boundary keeps moving; the judgment boundary doesn't — agents take more of the checkable work every quarter, which makes taste, architecture, and knowing-what-to-build a larger share of the human job, not a smaller one.

The teams that win this era aren't the ones with the most agents. They're the ones that redesigned their workflow around the new bottleneck first.

Takeaways

  • Agents moved the unit of work from lines to tasks — and the bottleneck from writing code to reviewing it. Plan around review capacity.
  • Delegate the checkable (migrations, test backfill, boilerplate, exploration); keep the arguable (architecture, concurrency, taste).
  • A repo that's good for new hires is good for agents: a sharp instruction file, one-command verification, fast tests, strict lint.
  • Three patterns cover most usage: agent drafts + human owner, parallel agents for independent tasks, plan-then-execute for big changes.
  • Fight the review bottleneck with enforced small PRs, tests-first review, and provenance labels.
  • Guardrails are non-negotiable: sandboxed permissions, protected branches, CI as the only arbiter, no agent path to production that bypasses a human merge.
  • Treat agent-ingested content as untrusted input, and every new dependency an agent proposes as guilty until verified — slopsquatting is real.
  • Instruction files rot at scale; update them in the same PR as the convention change, and prune ruthlessly.
  • Measure cycle time, rework, and escaped defects — never lines of code.
  • Juniors still grow, faster even — if "I can explain every line I ship" stays the house rule.

Enjoyed the read? We build this stuff for clients too.

Start a project