ES

Your repo is not ready for an AI agent

Leo G.8 minLeer en español

Tools hanging on a workshop wall, each with its outline marked behind it.
Tools hanging on a workshop wall, each with its outline marked behind it.

You ask the agent to fix a bug. Two minutes later it comes back with the files changed and a sentence: “the tests should pass now”. Should. It never ran them. It tried npm test, that failed for a reason it did not understand, and it carried on anyway. So the one who has to verify is you — which was exactly the job you wanted to hand off.

That does not get fixed by writing a better prompt. It gets fixed on the other side, in what the agent finds when it opens your project: whether it can run the tests without guessing, whether the error tells it what happened, whether the same concept is called the same thing everywhere.

Below are the six things that make the most difference, in order of what they pay back. None is a rewrite and none takes more than an afternoon; the first one is thirty minutes and it is what makes all the others possible. And they work the same with Claude Code, Codex, Copilot or Cursor, because all four work the same way: read, run a command, look at what came back, and correct.

1. One command per task, working on a fresh clone

An agent does not know that your project’s tests need an environment variable loaded, a database container running and an extra parameter so they do not run in parallel and trip over each other. It will try npm test, it will see it fail, and from there it does one of two things: invents another way to run them, or simply hands over the code without verifying it — the case we opened with.

The rule is that the four basic operations should each be a single command, with no prior steps:

{
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "test": "vitest run",
    "check": "astro check && eslint ."
  }
}

If something has to be started first, the script should start it, not the person running it. The agent runs commands; it does not read the README to find out there was a step before.

2. Tests that finish in seconds

An agent’s loop is write, run, look at the result, correct. That loop is what makes it deliver something verified instead of something plausible. And it is the first thing that breaks when the suite takes four minutes: the agent will still run it, but every iteration costs you four minutes of waiting and a context full of test output.

What pays off most is separating the fast suite from the slow one:

{
  "test": "vitest run test/unit",
  "test:all": "vitest run"
}

With that the agent iterates against the unit tests —seconds— and the full suite is left for the end, or for continuous integration, which runs it with nobody waiting. Not everything has to be fast: it is enough that a fast, trustworthy subset exists that can be run after every change.

3. Errors that say what happened

This is the most underestimated one. When something fails, the only thing the agent has to work with is the text of the error. It cannot see your screen, it has no intuition about the project, it does not know that module always acts up on Mondays. If the message does not say what happened, it will guess — and it guesses the way anyone does: by trying things.

// The agent can do nothing with this:
throw new Error('Invalid configuration');

// With this it fixes the problem on the first try:
throw new Error(
  `Missing PUBLIC_API_URL in .env (read from ${envPath}). ` +
  `Defined: ${Object.keys(config).join(', ')}`
);

The question to ask when writing an error message is: is this enough to know what to do, without opening the code? If the answer is no, it is missing the value that failed, the place it failed, or both. It is the same rule that has always applied to anyone getting paged at three in the morning; what changed is that an agent now reads it too, many more times a day.

4. One concept, one name

If in your project the same thing is called user in the database, usuario in the domain, account in the API and cuenta in the frontend, you got used to it. The agent did not: every search brings back half the places, it has to read three extra files to work out they are the same thing, and when it writes new code it picks any of the four names — adding a fifth dialect to the problem.

A project where each concept has a single name, and one text search finds all of it on the first try, saves the agent the most expensive part of its job: locating what it has to touch. And it saves it for the next person joining the team, too.

Fixing it does not require a mass migration: pick the right name for each concept, write it down in the AGENTS.md we will get to in a moment, and rename things as you touch them. Your editor’s rename refactor does it exactly and for free — and that is one of the tasks where using AI does not pay, because there is nothing to interpret.

5. Types and validation at the boundaries

Everything the compiler can guarantee is a class of error the agent cannot make silently. This is not an argument about static typing: it is that type checking is a verification that runs in seconds, needs nobody to interpret it, and tells the agent exactly which line is wrong.

Where it pays off most is at the boundaries of the system —what comes in from an API, what is read from a configuration file, what arrives from a form— because that is precisely where an agent has no way of knowing the real shape of the data:

// The unvalidated boundary: the agent assumes `price` is a number
// because it was a number in the example it saw. Sometimes it arrives as "12.50".
const { price } = await response.json();

// The declared boundary, here with Zod (any validation library will do):
// if text arrives where you expected a number, it fails on this line and says why.
const Order = z.object({ price: z.number(), currency: z.enum(['ARS', 'USD']) });
const { price, currency } = Order.parse(await response.json());

The second version turns a silent bug —the one that shows up three screens later, when somebody adds two prices and gets "12.5010.00"— into an error with a name and an address, on the line where the data came in. That is the kind of error an agent fixes on its own.

6. An AGENTS.md, and a short one

AGENTS.md is a file at the root of the project holding what the agent cannot work out by reading the code: the commands, the conventions that depart from the standard, the decisions specific to this project. The point is that the different tools on the market read it today, so it is not tied to the one you happen to use: if a teammate prefers another, they find the same rules.

If you use Claude Code, CLAUDE.md serves the same purpose and takes precedence; the simplest setup is to keep one of the two and, if you need both, make one a link to the other.

The temptation is to write three screens of it. That is exactly what not to do: everything you put there is loaded into every conversation, and the longer it gets, the more the rules that matter are diluted among the ones that do not. We already wrote in detail about what belongs there and what does not, but the summary is one question per line: if I remove this, does the agent get it wrong? If not, delete it.

What you do not need

  • Documenting the project file by file. It is the first thing everyone thinks of and it is wasted work: the agent reads the code faster than you write the description, and the description is out of date in two weeks.
  • Rewriting the project to be “AI friendly”. Nothing on this list is a rewrite. They are six things you already wanted for reasons that have nothing to do with AI.
  • An AGENTS.md per folder. Unless you have several large projects inside the same repository, a single one at the root is enough and stays maintained.

The repo is half the prompt

What you can ask an agent to do is bounded by what the repository lets it do. Without a command to run the tests, there is no way to ask it to verify. Without errors that say what happened, there is no way to ask it to fix without guessing.

If you only do one of the six, make it getting test and check to work in one command on a fresh clone. It is half an hour of work and it is the one that unlocks the rest: from there the agent can verify what it wrote, which is the difference between reviewing finished code and reviewing plausible code.

Comments