AI coding agents look much better in demos than they do inside many real projects.
That does not always mean the model is bad. Often the project gives the agent very little to work with: inconsistent patterns, weak types, slow tests, unclear business rules, missing contracts, and documentation that explains installation but not intent.
In that environment, the agent still writes code. It just writes code by guessing.
The useful question is not only “Which agent should we use?” or “How good is the model?” A more practical question is:
Is this codebase ready for an agent to work in it?
I use JavaScript and TypeScript examples in this article because they are common in full-stack product work and map well to the talk this came from. The same model applies to other stacks. The tools will change, but the underlying requirements are similar: clear patterns, explicit contracts, useful tests, fast verification, and maintained context.
An agent-ready project is not a project where AI does everything. It is a project where the system gives the agent enough constraints, examples, and feedback to make useful changes without constantly drifting into local chaos.
The formula is simple:
Agent-ready project =
consistent patterns
+ strong contracts
+ useful tests
+ fast verification
+ enough project context
This sounds like ordinary engineering hygiene. It mostly is. The difference is that AI agents make the cost of weak engineering hygiene visible much faster.
Agents Amplify the Codebase
When a human engineer joins a project, they ask questions, notice inconsistencies, and slowly build judgment about what to copy and what to avoid.
An AI coding agent does not have that same social path into the system. It reads files, follows local examples, edits code, runs commands, reads failures, and tries again.
That workflow has a consequence:
The agent will often copy the strongest local pattern it can find, even when that pattern is not the one the team wants anymore.
If one part of the frontend uses React Query, another uses direct fetch, another uses a custom API wrapper, and another still has legacy Redux side effects, the agent has no obvious answer to a simple question: “How do we load data in this project?”
It may choose the nearest example. Or the newest file. Or the shortest path to passing TypeScript. Sometimes that works. Often it adds a fourth style to a codebase that already had three.
This is why “clean up your project” is not just aesthetic advice in the agent era. Consistency becomes an instruction surface.
Agents are strongest when the codebase has clear local gravity:
- one common way to call APIs;
- one common way to validate inputs;
- one common way to structure modules;
- one common way to handle errors;
- one common way to write tests for a given type of behavior.
The goal is not perfect architecture. The goal is fewer reasonable-looking wrong paths.
Counter-Patterns Are More Expensive Now
A normal anti-pattern is a bad pattern.
A counter-pattern is more subtle: two or three valid-looking patterns that solve the same problem in different parts of the codebase.
For humans, counter-patterns are annoying. For agents, they are dangerous because they create ambiguity at exactly the moment the agent needs a clear example.
Imagine a TypeScript service where request validation appears in three forms:
- one endpoint uses Zod;
- one manually checks fields with
ifstatements; - one trusts the generated API type and validates nothing at runtime.
Now ask an agent to add a new endpoint.
It may produce code that looks consistent with one nearby file but inconsistent with the intended direction of the system. In code review, the team says “we do not do it that way anymore.” The agent could not know that unless the project made it explicit.
The fix is not only documentation. The better fix is a stronger local path:
- a shared validation helper;
- a small example endpoint that represents the current pattern;
- lint rules or tests that fail when the old path is used;
- a short note in
AGENTS.mdor the project README: “New endpoints must use this schema pattern.”
For agents, the best guidance is executable or close to executable. A convention that appears in code, tests, and commands is stronger than a convention hidden in team memory.
Less Code Means Less Context
There is a simple reason to care about code size in an agent-ready project:
Every unnecessary line is another line the agent may read, copy, misunderstand, or carry into its context.
Small code is not automatically good code. But dead code, duplicated branches, outdated comments, abandoned helpers, unused feature flags, and “just in case” abstractions all increase the amount of context the agent has to sort through before making a useful change.
This is different from the old argument that “clean code is nicer to read.” In an agentic workflow, noisy code has a direct operational cost. It consumes context budget, creates false examples, and makes retrieval less precise.
The same applies to comments. Good comments explain intent, business rules, risk, or surprising constraints. Bad comments repeat what the code already says, describe an old implementation, or preserve a decision that is no longer true.
For agent-ready projects, the useful target is:
- less dead code;
- fewer unused abstractions;
- fewer stale comments;
- fewer duplicated implementations;
- more self-explaining names and module boundaries;
- comments only where they explain why the code behaves this way.
This is also why cleanup should not be treated as cosmetic. Removing unused code improves the signal the agent receives from the repository. A smaller, clearer codebase gives the model fewer wrong paths to explore.
Sometimes the best refactor is not rewriting code. It is deleting a large piece of logic that the product no longer needs.
That is a product-engineering decision as much as a technical one. Before making a complex area “agent-ready,” ask whether the feature, workflow, or edge case still earns its place in the system. If it does not, deletion can improve the codebase faster than abstraction.
Types and Contracts Are Instructions
TypeScript is not only a developer-experience tool anymore. In an agentic workflow, it becomes one of the main feedback channels.
Strong types tell the agent when its mental model of the system is wrong.
For a JavaScript or TypeScript project, the baseline should be boring and strict:
strictTypeScript;- no implicit
any; - typed environment variables;
- typed API clients;
- generated types from OpenAPI, GraphQL, tRPC, or protobuf where appropriate;
- runtime validation at trust boundaries with tools like Zod;
- clear domain types instead of loose object shapes.
There is another small but important layer: import and dependency hygiene.
Agents often remove code, move logic between files, or replace one implementation with another. After that, projects accumulate unused imports, stale exports, dead files, and dependencies that are no longer reachable. TypeScript catches some of this with noUnusedLocals and noUnusedParameters, but it does not always see the whole dependency graph the way a large JS project actually behaves. Monorepos, multiple tsconfig files, generated code, barrel exports, dynamic imports, test-only paths, and build-tool-specific resolution can all hide unused code from a basic compiler pass.
This is where dedicated cleanup tools help:
eslint-plugin-unused-importscan remove unused imports witheslint --fix;eslint-plugin-importcan catch unresolved imports and some module-boundary issues;Knipcan find unused files, exports, dependencies, and scripts;depcheckcan catch unused package dependencies;ts-pruneor similar tools can find unused exports in TypeScript projects;- Biome or TypeScript organize-imports can keep imports sorted and normalized.
The goal is not to add tools for the sake of tools. The goal is to make leftover code visible. Agents are good at local edits, but they need automated cleanup checks to avoid leaving small pieces of entropy after each change.
This matters because agents tend to move quickly across boundaries. They may update a UI component, touch an API client, add a backend field, and modify a test in one loop.
If the project has weak contracts, the agent can make a change that is locally plausible but systemically wrong. If the project has strong contracts, the system pushes back earlier.
There is a simple rule here:
Every important boundary should have a machine-readable contract.
Frontend to backend. Service to service. Environment to application. Database row to domain model. External webhook to internal command.
The exact tool matters less than the property: the contract should be explicit enough that both humans and agents can use it as a source of truth.
Tests Are Feedback, Not Decoration
Many teams talk about test coverage. Agents care more about test usefulness.
An agent does not need a high coverage number if the tests are slow, flaky, vague, or disconnected from the behavior being changed. It needs feedback that helps it understand whether the change is correct.
Good tests for agent workflows have a few properties:
- they fail for real behavior changes;
- they have readable names;
- they are close to the business rule they protect;
- they can be run locally without a long setup ritual;
- they produce errors that point toward the broken assumption.
Bad tests create bad feedback. A flaky test teaches the agent to retry. A test full of mocks can pass while the real integration is broken. A snapshot test with a thousand lines of output tells the agent almost nothing about intent.
This does not mean every project needs huge test suites before agents can be useful. It means the most important flows need reliable checks.
For most product code, a practical testing shape is:
- unit tests for domain logic and pure transformations;
- integration tests for API, database, and service boundaries;
- end-to-end tests for critical user flows only;
- regression tests for bugs that agents or humans are likely to reintroduce.
The phrase “critical user flows only” matters. E2E tests are valuable, but if every small change requires a slow browser suite, the agent’s iteration loop becomes expensive. Use E2E tests for the paths where confidence matters most, not as a replacement for lower-level tests.
Also, do not blindly delete bad tests. Fix them, quarantine them, or remove them deliberately. Sometimes a bad test still contains a real business rule. The useful work is to preserve the rule while improving the signal.
Speed Is Part of Correctness
Agents work through loops:
edit -> run checks -> read errors -> fix -> run again
If that loop takes thirty seconds, the agent can explore and converge. If it takes ten minutes, every mistake becomes expensive. The agent waits, loses local momentum, and may overfit to partial checks because running the full suite is painful.
For agent-ready projects, verification speed is not a nice-to-have. It is part of the architecture.
At minimum, a project should have clear commands:
npm run typecheck
npm run lint
npm test
npm run test:unit
npm run test:e2e
Better projects also have scoped checks:
- run related unit tests for changed files;
- cache test and build outputs;
- split fast local checks from slower CI checks;
- use watch mode during active work;
- keep lint and formatting deterministic;
- make the same commands available locally and in CI.
In the JS ecosystem, this might mean Vitest watch mode, Turborepo or Nx caching, ESLint cache, Playwright projects for critical flows, and a plain tsc --noEmit command that fails quickly.
The important part is not the specific toolchain. The important part is that the agent can ask the project, “Am I still correct?” and get an answer quickly.
One caution: affected-test selection is useful, but it should not become the only source of confidence. Related tests are a fast local signal. Full CI is still the final judge.
Context Should Be Small, Useful, and Maintained
Large projects have a context problem.
Where does the real business logic live? Which module is legacy? Why is this field optional? Which workflow matters to operations? What should never be changed without talking to another team?
That problem deserves its own discussion. Context engineering for large codebases can involve documentation systems, indexed knowledge bases, architectural decision records, retrieval, ownership metadata, and human review loops.
For this article, the smaller point is enough:
A project does not need infinite context to become more agent-ready. It needs maintained context at the most important decision points.
A simple AGENTS.md can be surprisingly valuable.
It can tell the agent:
- how to install and run the project;
- which commands must pass before a change is done;
- where business rules live;
- which patterns are current and which are legacy;
- how to add a new API endpoint;
- how to add a new UI component;
- which directories should not be edited casually;
- what “done” means for this repository.
This file should not become a dumping ground. If it is too long, it becomes another stale artifact. The best version is short, specific, and maintained when project conventions change.
Think of it as an operating manual for a new engineer who only has five minutes before making the first change.
When This Starts to Matter
This advice is mostly for mid-size and large projects: products with real users, multiple contributors, important workflows, accumulated decisions, and enough code that local inconsistency starts to compound.
For a greenfield prototype, an MVP, or an early startup still searching for the right product shape, the tradeoff is different. At that stage, speed often matters more than cleanliness. You may not need strict architecture, full test coverage, perfect documentation, or a polished agent workflow before you know whether the product should exist.
That is fine.
But the tradeoff does not disappear. It is deferred.
At some point, usually when more people touch the codebase, customers depend on the behavior, and changes start slowing down, the team hits the limits of the first version. In the past, that might have taken a year or more. With AI-assisted development, teams can generate and ship code faster, so they may also reach the complexity wall faster. For some startups, that might be six to nine months. For others, sooner.
When that happens, the work is not “stop moving fast and become pure.” The work is refactoring so the team can keep moving fast.
That refactoring may include:
- removing features that no longer matter;
- deleting old experiments;
- collapsing duplicate flows;
- replacing one-off code with a standard path;
- adding tests around the workflows that survived product discovery;
- turning learned business rules into contracts and documentation.
In that sense, agent-readiness is not a phase that replaces product speed. It is what lets speed remain possible after the prototype becomes a real system.
A Concrete Example
Suppose a team asks an agent to add a new “review required” status to an internal workflow.
In a weak project, the agent finds:
- three different status enums;
- UI labels duplicated in several components;
- backend validation written manually in one route and missing in another;
- no clear test for the workflow transition;
- no documentation explaining when review is required;
- a full test suite that takes eight minutes.
The agent can still produce a patch. It might even look reasonable. But the chance of a subtle miss is high: one screen does not show the new status, one API accepts an invalid transition, one test fixture uses the old enum, and one operations rule remains hidden in someone’s head.
In an agent-ready version of the same project, the status is represented by:
- one domain enum or schema;
- generated or shared API types;
- a transition function with unit tests;
- UI labels derived from a single mapping;
- an integration test for the API boundary;
- one critical E2E test for the workflow;
- a short note explaining the business rule.
Now the task is much safer. The agent has a path to follow, the compiler catches incomplete changes, tests describe the expected transition, and the documentation explains the reason behind the rule.
The agent did not become magically smarter. The system became easier to reason about.
What This Does Not Solve
Making a project agent-ready does not remove the need for senior engineering judgment.
It does not solve ambiguous product requirements. It does not decide ownership boundaries across teams. It does not replace code review. It does not make security-sensitive changes safe by default. It does not solve the full context problem of a large monorepo.
It is also not the first thing every early product team should optimize. If the product is still a prototype, it may be rational to accept mess temporarily. The important word is temporarily.
It also does not mean every project should be rebuilt around agents. For many teams, the right first step is smaller:
- make the main patterns obvious;
- remove dead code and stale comments;
- make the contracts explicit;
- clean up unused imports, exports, files, and dependencies;
- make tests useful;
- make checks fast;
- write down the business rules that people keep explaining in Slack.
That is enough to improve both human and agent work.
The Agent-Ready Checklist
Before expecting an AI coding agent to work well in a project, ask:
- Is there one preferred pattern for common tasks?
- Are old patterns marked as legacy or removed?
- Is dead code removed instead of preserved as context noise?
- Do comments explain intent instead of repeating the code?
- Is TypeScript strict enough to catch wrong assumptions?
- Are important boundaries protected by contracts?
- Are runtime inputs validated at trust boundaries?
- Can the project detect unused imports, exports, files, and dependencies?
- Do tests protect real business behavior?
- Are flaky or misleading tests fixed, quarantined, or removed?
- Are critical user flows covered by E2E tests?
- Can local checks run quickly?
- Can the agent run the same verification commands as CI?
- Is setup reproducible from the repository?
- Is there a small project guide for agents and new engineers?
This is not a maturity model for perfect engineering organizations. It is a practical readiness check for teams that want AI agents to do more than generate plausible code.
The main takeaway is simple:
Preparing for AI agents mostly means making the project easier to understand, safer to change, and faster to verify.
That was already good engineering. Agents just make the feedback loop more visible.
There is also less excuse to let the codebase drift forever. If AI tools make writing code faster, they should also make cleanup, refactoring, test creation, contract updates, and architectural alignment easier to do continuously. The bar for code quality should not go down because code is cheaper to generate. In many teams, it should go up, because the tools can now help maintain the structure that speed depends on.