Claude Code best practices for shipping real apps
By Leon Mallett · Updated 9 October 2026 · 5 min read
Vibe Leagues, the site you're reading, was built almost entirely with Claude Code: accounts, a database, a public API, security, deploys. Getting an agent to write code is the easy part. Getting it to ship safely, session after session, takes some deliberate habits.
These are the ones we actually run on. Each is here because of something that happened.
1. Put the rules that must never break in CLAUDE.md
Claude Code reads a CLAUDE.md file at the start of every session. Treat it as the place for things that must stay true however the code changes, not as a tutorial.
Ours has a section called Product invariants: reactions are positive-only, sign-up is invite-only, nothing gives anyone a ranking advantage. It tells the agent that if a task conflicts with one of them, it must stop and flag it rather than work around it. That line has done real work. When I asked to open the site up, the agent pointed out that open registration broke an invariant and asked what I actually wanted. We ended up opening reading to everyone and keeping sign-up invite-only, which was the better answer.
Keep it short and current. A CLAUDE.md full of stale instructions is worse than none, because the agent believes it.
Tip: a CLAUDE.md in a parent folder applies to every project beneath it. I keep one for machine-wide rules, such as never killing processes by name on a shared machine and never printing a secret, and one per project for that product's rules.
2. Write down what it must ask before doing
The most useful document I have isn't about code at all. It's a short working agreement listing what the agent may do on its own and what it must stop and ask about first:
- merging to the main branch;
- deploying anything;
- running a database migration against production;
- adding or upgrading a dependency;
- touching credentials;
- deleting anything it didn't create;
- sending anything outward (an email, a message, a comment).
Everything else, like editing code, running tests or opening a pull request, it just does. The rule of thumb in the document is "prepare, do not enact": it drafts the migration, writes the release notes, opens the PR, and leaves the irreversible step to me.
This doesn't slow things down much. It means the expensive mistakes need two decisions instead of one.
3. Make it prove its tests can fail
AI-written tests have a habit of passing no matter what. A test that can't fail is decoration.
So for anything important, the agent breaks the code on purpose and runs the test again. It disables the duplicate-post protection, removes the login rate limit, lets draft articles leak into the sitemap. Then it checks that the right test fails at the right step, and puts the code back. So far the right test has failed every time, and that's exactly what the check is for. If one ever doesn't, we've found a test that wasn't testing anything, before it mattered.
4. Test against the real build, not a stand-in
Our end-to-end tests run in a real browser against the production build: the actual Cloudflare Worker bundle, on a throwaway database. That matters because the real runtime differs from a development server. Cloudflare Workers can't read files when a request comes in, for example, so our articles have to be compiled in at build time. Testing the real bundle is how we know that actually happened, rather than assuming it.
5. Read every database migration before it runs
This is the one I'd underline. I asked for a single new column, and the migration tool generated a script that would have rebuilt the table and, on our database, deleted every reaction on the site.
Now the agent reads every generated migration for DROP, table rebuilds and anything that switches safety off. It tests the migration on a throwaway copy with real-looking data, comparing row counts before and after. And before running it on production, it records a restore point.
6. Check the live site after every deploy
"Merged" isn't "live". One of our merges simply never deployed, with no error, nothing. We only noticed because the agent checks the live site after every change: is the new page there, are the security headers still present, does the old behaviour still work.
Make "verify it live" part of the definition of done.
7. Treat every new dependency as a decision
Before installing anything, the agent states the exact package and version, checks when it was published, and checks whether it runs scripts on install. Anything released in the last 72 hours needs my explicit OK, because brand-new versions are where supply-chain attacks hide. When we added a Markdown library, the newest version was a day old, so we pinned the previous one.
8. Keep secrets out of the conversation
Anything printed in a session is in the transcript for good. The agent reads secrets from the OS keychain inside a command, never echoes them, and leaves anything that involves typing a password to me.
9. Fact-check what it writes about you
The agent drafts these articles from what actually happened, and it still gets details wrong. In the first two drafts it rounded a timing it shouldn't have, credited a security setting with catching something it never caught, and blamed the wrong party for one mistake. The agent caught those by checking its own draft against the record, but I read every word before anything goes out under my name.
10. Give it a memory beyond one session
Each session starts fresh, so lessons have to live somewhere. I keep a shared log across all my projects. When the agent learns something that applies elsewhere, like "Cloudflare's build image read NODE_VERSION=24 as Node 4.9.1", it writes a short entry tagged to every project it could affect. The next agent working on any of them reads it before starting.
The same system lets projects ask each other questions. Before building an API for one of my other apps, the agent sent that project's agent the proposal and got back the one constraint only its codebase knew about.
None of this is clever. It's the boring discipline you'd want from any developer, written down where the agent reads it. The difference with an AI is that it will actually follow the list every time, if the list exists.
Building with Claude Code, or any agent, and found a rule that saved you? That's a story worth sharing on Vibe Leagues. Request an invite.