Development
09 minsUsing Claude Code Is Easy. Using It Well Takes More Than That.
Beyond installing it - how we use CLAUDE.md files, reusable skills and explicit guardrails to get consistent, production-quality AI-assisted code across every project.
Dan Newns
04.10.26
When Jamie wrote about his journey from AI sceptic to convert, he touched on something that I've been wanting to expand on ever since: the difference between using AI to write code and using it well.
There's a version of AI-assisted development that genuinely transforms how a team works - faster groundwork, more consistent code, less mental overhead on the structural stuff so you can focus on the interesting problems. And there's a version that produces plausible-looking code that subtly violates your architecture, ignores your conventions, occasionally modifies things it absolutely should not touch, and erodes trust in the tooling entirely.
The difference between those two versions is almost entirely about context engineering.
That's the thing most Claude Code tutorials don't say plainly: the model itself is almost not the point. Claude, GPT-4o, Gemini - at this level of capability, the differences between them for most day-to-day coding tasks are marginal. What matters dramatically more is the quality of the context you provide. Give an AI your coding standards, your architecture patterns, your project-specific conventions, and your explicit guardrails, and you get code that looks like it was written by someone who's been on your team for months. Give it nothing, and you get generic code that'll need significant rework to fit into your codebase.
We've spent the past several months figuring out what good context engineering looks like for a Laravel agency. This is what we've landed on.
What Context Engineering Actually Is.
Let me define this clearly, because the term gets used loosely.
Context engineering is the discipline of designing everything the AI sees at inference time. Not just the prompt - everything. The system-level instructions that define how the AI should behave. The project-specific knowledge it needs to do your work your way. The explicit constraints on what it should and shouldn't do. The examples that demonstrate the patterns you want it to follow.
Prompt engineering was about finding the right words to ask the right question. Context engineering is about building the right environment for the AI to work in.
For coding assistants like Claude Code, the primary mechanism is the CLAUDE.md file. But it's bigger than just that file - it's a system of layered context that we now design deliberately for every project.
CLAUDE.md: Your Project's AI Briefing Document.
The CLAUDE.md file lives in your project root. Claude Code picks it up automatically and treats it as standing instructions for everything it does in that project. Think of it as the onboarding document you'd give a new developer - except this one actually gets read from cover to cover, every single time.
We now write a CLAUDE.md for every client project before we start using Claude Code in earnest. Here's a representative example of what ours contain:
1# Project Guidelines 2 3## Stack 4- Laravel 13 with the Laravel AI SDK 5- Filament v4 (admin panel) 6- Livewire 3 (reactive UI components) 7- Pest (all testing — no PHPUnit) 8- Deployed on Laravel Cloud 9 10## Architecture Conventions11- Business logic lives in `app/Actions/` — one action per use case12- Controllers are thin: validate input, call an Action, return a response13- Complex queries go in `app/Queries/` — never inline in controllers or actions14- Use Form Requests for all validation, always15 16## Coding Standards17- `declare(strict_types=1)` at the top of every PHP file18- Always use `Model::query()` — never chain directly off the model class19- Type-hint everything; avoid `mixed` unless genuinely unavoidable20- Use named route helpers; never hardcode URL strings21- Follow PSR-12 (enforced by Pint in CI)22 23## Testing Standards24- Every new feature needs Pest tests — no exceptions25- Use `it('description', function() {})` syntax throughout26- Group related tests in `describe()` blocks27- Mock all external services — no real HTTP calls in tests28- Test the Action class directly, not just via the controller29- Factories must cover all nullable/optional fields30 31## Guardrails — Read These Carefully32- NEVER modify existing database migrations under any circumstances33 If data needs fixing, fix it in a seeder or factory34 If the schema needs changing, create a new migration35- NEVER add a Composer package without flagging it first36- NEVER refactor code that isn't directly related to the current task37- If you're uncertain about a business rule, ask — don't assume38- Do not create new Blade views; this project uses Livewire components
copied!
That file takes about twenty minutes to write properly at the start of a project. The return on that twenty minutes, across weeks of AI-assisted development, is substantial. The code comes out closer to production-ready because the AI understands what production-ready means for this project specifically.
Skills: Reusable Instructions for Recurring Tasks.
Beyond the project-level CLAUDE.md, Claude Code supports skills - reusable instruction sets for specific types of work that you can invoke across projects.
We've built a set of Jump24-specific skills for the patterns we use repeatedly:
Our Filament resource skill defines exactly how we structure Filament resources: the file organisation, the Action classes we expect to be created alongside, how we handle permissions and policies, our naming conventions, how we structure form() and table() methods. Without this skill, Claude generates Filament resources that work but don't match our patterns. With it, the output is immediately code-review ready.
Our Pest testing skill covers our testing conventions in detail: how we structure test files, the factory usage patterns we follow, how we mock external services, our expectations around test coverage for different types of code, how we use beforeEach() and shared fixtures. The tests Claude generates with this skill active look like they were written by someone who's been writing Pest tests here for years.
Our Livewire component skill handles our component architecture, how we handle form submissions, validation patterns, and how we structure components that interact with Action classes.
The key insight with skills is that they encode institutional knowledge. They're "the way we do things here" - the kind of knowledge that takes a new developer weeks to absorb through code review and pair programming. Skills make that knowledge immediately available to the AI.
Guardrails: The Things We Explicitly Prohibit.
Guardrails are the negative constraints - the explicit list of what the AI should never do. Some of ours exist because we learned them the hard way. Some because we can see exactly how they'd go wrong if we didn't explicitly prevent them.
The most important one, included in virtually every project we work on:
Never modify existing database migrations.
This came up directly in our own experience - at one point, Claude decided the best way to fix a failing test was to update an old migration. In a local development environment, that's annoying. In production, against a database that's been running for two years, it would be catastrophic. The guardrail is now in every CLAUDE.md .
Others that appear consistently across our projects:
1## Guardrails 2 3- Never modify existing migrations. New schema changes = new migration. 4 If data is wrong, fix it in a seeder or factory. 5 6- Never add Composer packages without flagging it first. 7 Some packages introduce licensing implications or conflicts we need to evaluate. 8 9- Never refactor code outside the scope of the current task.10 Scope creep is as much a problem for AI as it is for humans.11 12- If a business rule is ambiguous, ask. Do not infer from context.13 The AI's inference will be plausible but may well be wrong.14 15- Do not create or modify .env files.16 17- Test files should only test — no business logic in test files.18 19- Always use transactions when writing multiple related records.
copied!
The "ask rather than assume" guardrail is subtle but catches real issues. AI models fill gaps in their understanding with plausible-sounding reasoning, and they do it confidently. An explicit instruction to surface uncertainty rather than paper over it stops a surprising number of problems before they become embedded in the codebase.
The Code Review Mental Model.
The framing that works best for us: treat AI-generated code like a pull request from a capable junior developer.
That framing is worth unpacking, because it has practical implications for how you review the code as a developer.
You read the diff .
You don't just run the tests and call it done. Passing tests don't mean correct code - they mean the tests pass. You read what was actually generated. Claude is generally strong on structure and reasonable on implementation, but it will occasionally make an assumption about your business logic that's plausible given what it can see but wrong given what you know.
You're responsible for what gets merged.
This sounds obvious but it's easy to let the accountability erode when a tool is generating code automatically. If AI-generated code causes a production bug, the developer who merged it is responsible. That accountability keeps the review bar where it needs to be.
You contribute the domain knowledge.
Your CLAUDE.md can encode a lot. But there are things it can't: the conversation with the client last week about a specific edge case, the reason a piece of code that looks refactorable actually can't be changed yet, the domain rules that live in someone's head rather than in documentation. Catching those gaps is your job, not the AI's.
Consistency Across a Team.
Something we didn't fully anticipate when we started taking this seriously: the CLAUDE.md and skills approach is brilliant for team consistency. Every developer using Claude Code on the same project is working with the same guidelines. The AI-generated code follows the same architectural patterns regardless of which developer initiated the prompt.
Before this, one of the friction points in AI-assisted development on team projects was that different developers got wildly different quality output because they were prompting differently and providing different context. Standardise the context across the team, and you largely standardise the quality of the output.
There's also a secondary benefit: writing a CLAUDE.md properly forces you to articulate your conventions explicitly. Projects where we've done this properly have ended up with better-documented architecture decisions as a side effect.
What This Looks Like in Practice: A Typical Day.
To make this concrete, here's roughly how a feature development workflow looks for us now.
A ticket arrives: implement a new report type in a client's admin panel. Before writing a single prompt, I'll:
Check that the
CLAUDE.mdis up to date for this project (we update it when conventions evolve)Pull up the relevant skill for Filament resources if this report lives in the admin panel
Think about what guardrails are especially relevant for this task
Then I start working. For a Filament resource with an associated Action class and Pest tests, I'll typically start using the /grill-me skill by Matt Pocock https://github.com/mattpocock/skills: I will walk through this to plan out what we're going to build linking it to the ticket so it has scope of what is required.
With a well-designed CLAUDE.md and the right skills active, what comes back is really close to what I'd have written myself. It might need a few adjustments here and there - the occasional business rule tweak, a line break for readability, a method name that better reflects the domain - but the structural and architectural work is done, and done correctly.
The time I've saved goes into understanding the business problem better, reviewing the output thoughtfully, and thinking about edge cases. Which is, frankly, where my time was always better spent anyway.
More from the series.
More Laravel insights, technical deep-dives, and honest thinking from the Jump24 team.