Skip to main content

Guide

Shipping AI-written code safely

A practical guide for engineering leads and CTOs on the workflow and checks that make coding agents safe to use on a production codebase, taken from the way we run them on client work.

By Corco Labs ·

For an engineering lead, the open question about coding agents in 2026 is whether their code can be trusted in production. The early numbers give reason to ask. CodeRabbit’s research, as reported by TFiR, found that AI-assisted code generation produces 1.7x more issues related to logical and correctness bugs than traditional development methods. In LangChain’s State of Agent Engineering survey of more than 1,300 professionals (June 2026), quality was the biggest barrier to getting agents into production, and a third of respondents named it as their primary blocker.

We use coding agents on everything we build, client work included. This guide is the workflow we run them under: what the agent reads before it starts, how the work is split, which checks run before anyone reviews the diff, what a second model and a person still look at, and the decisions an agent is never allowed to make. It ends with a checklist you can paste into your own repository.

What makes AI-written code risky?

A coding agent starts every session with no memory of your codebase, and it writes with the same confidence whether it is right or wrong. It does not know how your repository deploys or that a migration will lock a table under load. It will also describe a fix it never verified in exactly the tone it uses for one it did.

Volume makes both problems harder. When an agent writes most of the code, a review process that depends on a person reading every line does not scale with it.

So the safety has to come from the process around the agent. The same tools that let a small team ship like a large one will also let it ship a mess at the same speed.

We run that process in layers. Deterministic checks go first, then a review by a second model, then a review by a person, and each layer looks for a different kind of failure. Guestavo, our guest-engagement platform for hospitality venues and now live in beta, was built with Claude Code under exactly these three layers.

What should an agent read first?

The conventions, the decisions already settled, the deploy steps and the mistakes you have already paid for, written down as files in the repository the agent works in. An agent with a blank prompt is a fast junior with no memory, and anything that only lives in someone’s head will be missing from its work. We keep this material as short entry files with reference documents behind them, organized by domain, and the agent loads the ones that match the task.

The most useful reference documents record something that went wrong. One of ours opens, before anything about DNS or Docker, with an instruction to always pass the no-follow flag when tailing deployment logs, because otherwise the command never exits. A few lines later it says never to deploy every application at once, because concurrent builds have run the server out of memory. Neither would appear in a general guide, and an agent that read a general guide would repeat both failures.

Our test for whether a document earns its place is whether it could have come from a search result. If it could, the agent already knows it, and the document is filler that costs context on every session.

Keep the top-level instruction file short. Ours holds the rules that apply to every task (the verification gate described further down is one of them) and points to the documents an agent needs for a given kind of change, so an agent loads only what the change in front of it needs.

Reference material also goes stale. A document that was right in March can be quietly wrong by September, so the documents that drift fastest get a named owner and a review schedule, and anything about vendor pricing or platform behavior gets checked against a current source before an agent repeats it.

If the agent browses, every fetched page, document and search result is read for evidence and never for instructions. An agent that browses can be talked to by whoever controls the page it lands on, so our research instructions say this in their opening section, along with a block on requests to private-network addresses.

How should the work be split?

Into a written plan and a sequence of phases, each with a gate that has to pass before the next phase starts. On anything non-trivial the agent asks questions before it writes code, then writes the plan into the repository as a file, and only then builds. Keeping the plan in a file means a person can read and correct it before any code depends on it.

The questions come first because the mistakes that cost the most time rarely sit in the code. They happen in the first ten minutes, when something reasonable-looking gets built on a premise nobody checked.

Nothing gets built during planning, not even a helper file that seems obviously needed. Once building has started, the reviewer is judging a decision that has already been made instead of making it.

Work we do repeatedly is written down as a workflow. Each phase declares its goal, its inputs and outputs, the reference material it draws on, a model tier and the gate it has to pass. A runtime parses the definition into a graph and runs one agent per phase, with cheaper models on the deterministic phases and the expensive ones only where judgment is needed. Building an API is one workflow, and hardening it and shipping it to staging are the next two in the chain.

Each workflow also states what it does not cover. We added those lines after agents kept carrying on into the next piece of work without being asked.

Which checks should run automatically?

Everything a machine can decide without judgment: linting, type checks, tests and the smallest build that covers the change. These run before any model or person reviews the diff, so review time goes to the questions a tool cannot answer. When an agent repeats a mistake, we turn it into a lint rule, so the review effort does not grow with the amount of code the agents produce.

Run the smallest relevant check, and then read its exit status and its output. An agent that ran a command has not shown that the command passed, and our agent instructions spell that out.

A check is only worth having if it fails for the right reason. We once sat down to fix one failing check in a script that drives one of our apps in a real browser, and found four that were reporting something untrue:

  • One clicked a button before the page had hydrated, so no request was ever made. It failed on a warm development server and passed on a cold one.
  • One drove a screen that had been deliberately deleted months earlier, which left permanent red lines in the report.
  • One counted items in a review queue using an element the queue has never contained, so a queue holding three items reported itself empty.
  • One waited on a URL pattern that also matched a different endpoint, then looked for a draft that had never been written.

Three of those four looked like product bugs and were not. A check that fails for something that works teaches the team to skim the output, and a check that cannot fail for the right reason is better deleted than kept.

Validate a file with the code that actually reads it. The parser in our own workflow runtime once used a whitespace pattern that ate a level of indentation, and roughly four in ten phases quietly collapsed into a single task each. Nothing failed, and runs simply did less. The fix was a parity test that parses every definition the way the runtime does.

The checks in this guide, and the agent file at the end of it, are in the free workflow kit as templates you can drop into a repository.

What should a second model review?

The diff, read by a different model from the one that wrote it, before a person spends time on it. The reviewer reports findings and changes nothing, and each finding is checked before anyone acts on it, because the reviewer is also a model and can be wrong in the same confident way.

Our review step is non-mutating by default. Asking for a review returns findings, and fixing them is a separate request made after a person has read what came back. When review and remediation are one step, a request for a review can come back as a branch full of changes nobody asked for.

The kind of review depends on the question. A branch review checks the code. A comparison of staging and production looks for regressions between the two. An audit of an inherited repository goes after deploy reality, dependency risk and the unknowns, and a plan review checks scope and acceptance criteria before any code exists.

Every review ends with a matrix that marks each category as “reviewed”, “not applicable” or “untested”. Before we added it, reports were silent about whole categories, and silence reads as a pass. With the matrix, a design review cannot skip accessibility and leave the reader to assume it was fine.

What does a person still check?

Behavior. A person runs the real path and reads the real output, and for anything visual looks at a screenshot, because a passing build does not show that the page works. Most of our review time has moved from reading code line by line to reading test output and screenshots, which is a better use of it.

A green build has shipped a page that crashed on load more than once, which is why a screenshot is part of the gate for any visual change. When something comes back claimed as fixed, the check is the running system: the admin table, the queue depth, the browser console, the response body.

The person also reads how the agent reported its work. Every session ends under a verification gate:

  1. Turn the request and any specification into a list of requirements.
  2. Inspect the final diff against every item on that list, including the parts that were hard to change.
  3. Run the smallest relevant test, build or behavior check, and read the result.
  4. Report each requirement as verified or not, by name.

The report uses strict words. Complete means every requirement was verified and every required check passed. INCOMPLETE names the exact gap, and BLOCKED says what is missing and what would resolve it. Our agent instructions state that false verification is worse than an honest incomplete result.

What should an agent never decide?

Four decisions stay with a person: anything a third party sees, the architecture, bulk changes to production data, and the call that the work is finished (the gate above covers that last one). Where possible the restriction lives in the tooling, so it does not depend on the prompt being followed.

Anything a third party sees

A pull request is prepared by the agent and handed to a person to merge. Anything with a name on it outside the repository, such as an email or a post, is drafted and staged and never sent by the agent. We learned this after an agent opened a pull request on a public repository, acting on something that sounded like approval and was not. Decisions an agent records now land as proposals until a person accepts them, and the agents’ tool surface in our project manager has no accept action at all.

Architecture

Agents build to a design a person made. Which queue belongs between an ingestion pipeline and a search index, or whether a repair tool needs backpressure so it cannot take the platform down while it fixes data, is still an engineer’s call. Holding the design in your head and breaking it into pieces an agent cannot slip past is the job.

Production data

Database migrations never run unless a person asks for them. Batch jobs never run over every user at once. They are enqueued and capped, pointed at an allowlist that starts with our own account, and before they run they print exactly which records they are about to touch.

Put the approval at the consequential action, such as the merge or the migration, and expect the agent to finish everything before that point on its own, checks included. Our instructions tell the agent to prepare a concrete result before asking for any approval it needs.

What goes in your agent file?

The rules below, adapted to your stack. Paste them into the instruction file your coding agents read at the start of every session (we keep an AGENTS.md at the repository root), then delete anything your tooling already enforces.

  1. Read the README and the conventions for the area you are changing before editing anything.
  2. On any non-trivial change, ask clarifying questions first and write the plan to a file in the repository before building.
  3. Run lint, type checks and the smallest relevant test or build. Read the exit status and the output.
  4. Format only the files you changed. Never run repository-wide formatting.
  5. Never commit .env files or secret values.
  6. Never run a database migration unless a person asked for it.
  7. Run batch jobs capped and against an allowlist, and print the records they will touch before they run.
  8. Never send, publish, merge or post anything a third party will see. Prepare it and hand it to a person.
  9. For any visual change, take a screenshot and look at it before reporting.
  10. Before reporting, list the requirements from the request and check the final diff against each one.
  11. Say the work is complete only when every requirement is verified. Otherwise report INCOMPLETE with the exact gap, or BLOCKED with what is missing.
  12. Never report a result, test run or output you did not observe.
  13. When the same mistake shows up twice, propose a lint rule or a reference note that stops it from recurring.

Free download

Get the workflow kit

An AGENTS.md template, the verification gate, a pull request review checklist, and templates for workflows and skills. Plain Markdown, MIT licensed.

How does Corco Labs work this way?

Inside your repository, with your CI, under the same gates. The agents read your codebase and the decisions your team has already made before they change anything, and nothing runs in a sandbox that later gets pasted over. Pull requests are prepared by the agents and merged by a person.

What changes for the client is mostly throughput: a first release in weeks, and a bug-fix cycle measured in hours. The judgment stays with people who have been accountable for one platform for eight years. The longer account is in how we use AI coding agents on client work, and if a release is stuck or a senior seat has been open for months, tell us what’s stuck.