A Pattern I Kept Seeing
Over the past couple of months I have been integrating AI coding assistants into my day-to-day work across multiple Laravel projects. Not as an experiment, but as a real part of how I write, review, and refactor code.
What I noticed early on was that the quality of AI output had almost nothing to do with which tool I was using. It had everything to do with the state of the codebase I was pointing it at. Well-structured code produced useful, predictable suggestions. Code that had grown organically over time, without clear conventions, produced confident-sounding output that could easily slip past a distracted reviewer.
So I started making specific changes before bringing AI into a codebase. The same changes, in roughly the same order, every time. And the results became measurably more predictable. Fewer hallucinated patterns, fewer suggestions in the wrong layer, less time spent rejecting generated code that looked right but wasn’t.
This post is a distillation of that experience. It is not a complete list since every codebase is different, but these are the changes that made the biggest difference across the projects I have worked on.
AI Agents Read Your Code Too
Most production Laravel applications did not start as architecture projects. They started as a proof of concept, or an MVP that needed to ship. Features got added as customers asked for them. The team grew. New developers brought different conventions. And somewhere along the way the codebase accumulated patterns that made sense at the time but were never revisited.
That is not a failure. That is how software grows when a product is finding its market. Some level of technical debt is a reasonable trade-off when the alternative is shipping too slowly to survive.
The challenge is that AI coding assistants change the equation. When you add one to your workflow, you are not just adding a faster typist. You are adding a collaborator that reads your entire codebase, reasons about it, and generates new code based on what it finds. It does not distinguish between an intentional pattern and an accidental one. It mirrors what is there.
If your codebase has inconsistent naming, buried business logic, and undocumented conventions, the AI will reproduce all of it. It will make confident suggestions in the wrong layer, copy patterns you were planning to clean up, and occasionally do something that passes code review because it looks plausible.
The good news is that the same work that makes your code more machine-readable also makes it more human-readable. Preparing your Laravel application for AI assistance is simply good engineering practice with a better-articulated reason to finally prioritise it.
The Four Patterns That Confuse AI Agents
After working across many production Laravel codebases with history behind them, the same structural challenges appear. These are the ones that most reliably cause agents to produce incorrect or risky output.
1. Business Logic in Controllers
Controllers that span hundreds of lines, mixing HTTP concerns with billing logic, email sending, and database writes, are the most common pattern I encounter. In many cases they started small and grew as the product did. Everything lives in one method: validation, queries, business rules, notifications, and the response.
When an AI agent reads a controller like this, it cannot reason clearly about what belongs where. If you ask it to add a filter, it adds the query logic directly into the controller. If you ask it to move a notification to a scheduled job, it struggles to isolate that concern from the rest. Every change risks touching something unrelated.
One approach that has worked well for me is introducing a consistent pattern such as action classes paired with single-invokable controllers. It is not the only solution, but the consistency is what matters. When every controller follows the same shape, the AI agent stops guessing where logic lives and starts finding it reliably.
When you ask an AI agent to modify behaviour, it opens the action class, finds the right logic, and makes the change in the right place. The controller stays untouched.
Fix: Extract domain logic into action classes. Use single-invokable controllers. A controller should do one thing: validate input, call an action, return a response.
2. Implicit Conventions
Laravel applications develop conventions that exist only in the minds of the original developers. Variable names that mean something specific to the team. Query scopes with non-obvious side effects. Config keys checked in unexpected places. The original developer knew. A new developer would have to ask. The AI has no one to ask.
Fix: Make conventions explicit. Use docblocks on model classes to describe their scopes. Use typed DTOs instead of raw arrays. Add annotations to service methods that document what can fail and why.
3. Magic Numbers and Strings
One of the most common patterns in codebases that have evolved quickly is status checks written as raw integers or hardcoded strings scattered across the code. These made sense when the application was small. As the codebase grew, the meaning of those values became implicit knowledge. AI agents will reproduce them in generated code, and may guess at the meaning in context they have not seen before.
Fix: Use PHP enums, available since PHP 8.1, anywhere your application has a finite set of states. They make intent explicit for both developers and agents.
4. No Tests, No Constraints
AI agents learn from your test suite. Applications with comprehensive tests give agents reliable signal about expected behaviour. Applications with sparse tests, which is common in codebases that prioritised shipping over coverage, give agents no constraints. They generate code that satisfies the happy path and ignores everything else.
One thing worth clarifying here: the tests that matter most before handing a module to an AI agent are not feature tests that express what you wish the code did. They are characterization tests, a term from Michael Feathers, that document what the code actually does today. You write them before touching anything, so you have a safety net if the agent changes behaviour you did not intend to change.
Fix: Before inviting AI into your workflow, ensure critical paths have test coverage that documents current behaviour. Pest makes this tractable even for teams with little prior testing discipline.
A Practical Refactoring Order
You do not need to fix everything at once. Here is the sequence I recommend:
-
Introduce typed configuration. Replace scattered config calls throughout the codebase with a dedicated config class loaded at boot. This gives agents a single source of truth for application constants rather than values buried in unexpected places.
-
Flatten your longest controllers. Take your five longest controllers and extract their logic into action classes. This alone dramatically improves AI output quality in those flows.
-
Add enums for status fields. Review your migrations for integer or string columns that represent state. Introduce enums and update your model casts.
-
Write characterization tests. For any module you plan to hand to an AI agent, write tests that document current behaviour first, not what you wish it did, but what it actually does today. This gives you a safety net and gives the agent a spec to work against.
-
Add a
CLAUDE.mdorAGENTS.mdfile. This file lives in your repository root and tells the AI assistant about your project’s specific patterns: naming conventions, service layer structure, deployment process. Every major AI coding tool reads it. Most teams skip this step entirely. -
Install Laravel Boost if you are on Laravel 12. If your current project supports it, there is an official first-party package that takes this a step further. Laravel Boost auto-generates your
CLAUDE.mdandAGENTS.mdfiles, wires up an MCP server your AI tool can query directly, and connects to a documentation API with over 17,000 pieces of Laravel-specific context. Install it as a dev dependency, runphp artisan boost:install, and your agent immediately has richer, more accurate context about how your project is supposed to work, including support for Livewire, Inertia, Pest, and most major ecosystem packages.
If you are not on Laravel 12 yet, the manual AGENTS.md from the previous step is your starting point. Getting to 12 is worth prioritising anyway.
The Payoff
The improvement in AI output quality is noticeable within a few weeks of doing this work. The agent stops suggesting changes in the wrong layer. Generated code starts following your conventions rather than generic Laravel tutorials. Review time drops.
More importantly, the codebase itself becomes easier to onboard new developers, easier to audit, and easier to maintain. The investment pays dividends regardless of which tools you use or how AI development evolves.
If you are not sure where your codebase stands, a structured audit is the fastest way to find out. I identify the highest-impact changes for your specific application, so you are not refactoring for the sake of it, but addressing what actually costs you the most time and risk.
The goal is always the same: code clear enough that anyone, human or machine, can understand what it does and safely change it.