Setting up your work environment is basically mise en place before cooking. The chef who starts cooking without everything chopped, measured, and within arm's reach isn't more efficient — they're more chaotic. And when service blows up at 9pm, they wish they'd spent five minutes prepping beforehand.
I was that chef. Weeks using Claude Code like a glorified chat window, no routines, no persistent context, explaining the same things over and over at the start of every session. Convincing myself that setting any of that up was a waste of time.
Then a post about Claude Code Routines hit 611 points on Hacker News and I had to admit the problem was mine.
What routines in Claude Code actually are — and why I ignored them
A routine in Claude Code is essentially a file of persistent instructions that run automatically at specific moments in your workflow — when you start a session, before a commit, after running tests, when a certain type of file is detected.
They're not macros. They're not bash scripts in disguise. They're structured context where you tell Claude what role it plays in this project, how you want it to respond, what conventions you follow, what it should never break.
My resistance was purely irrational: "I know what I'm doing, I don't need training wheels." Same logic I used at 19 when I ran rm -rf on a production server fully convinced I knew what I was doing. Confidence without structure is technical debt waiting to execute.
The central file is CLAUDE.md in the project root. But routines go further than that.
# CLAUDE.md — Project Context
## Current stack
- Next.js 15 + React 19
- Strict TypeScript (no any, ever)
- PostgreSQL on Railway
- Docker for local development
## Critical conventions
- Components: PascalCase, one component per file
- API routes: always validate with Zod before touching the DB
- Errors: never swallow them, always log with context
- Tests: every utility function has a test, no exceptions
## What NOT to do
- No `any` in TypeScript — if you don't know the type, figure it out
- Don't install dependencies without asking first
- Don't modify DB schema without an explicit migration
## Business context
- This is a B2B SaaS, errors have real cost
- Users are non-technical, error messages must be human-readable
That's the baseline. What turns it into a real routine is the next level.
The actual architecture of routines: hooks and per-task context
Claude Code lets you define specific behaviors per task type. It's not one monolithic file — it's a layered system.
# Structure I ended up adopting
.claude/
commands/ # Reusable custom commands
review-pr.md # What to check in every PR
debug-api.md # Debugging protocol for endpoints
write-test.md # How to write tests in this project
hooks/
pre-commit.md # What to verify before committing
post-error.md # What to do when something breaks
CLAUDE.md # Global project context
Custom commands are where this gets powerful. Instead of typing "review this PR checking for performance, security, and consistency with the project conventions" every single time, you have:
# .claude/commands/review-pr.md
When reviewing a PR in this project, follow this order:
1. **Security first**
- User inputs always validated with Zod
- No hardcoded secrets (scan for patterns: key, token, secret, password)
- SQL queries through the ORM, never string concatenation
2. **Performance**
- N+1 queries (look for loops with DB calls inside)
- Images without next/image optimization
- Bundle size: full library imports when only one function is needed
3. **Consistency with the project**
- Naming conventions from CLAUDE.md
- Error handling per the defined standard
- Tests included where applicable
4. **Final summary**
- Blockers (don't merge without fixing)
- Suggestions (nice to have)
- What's good (important for the team)
You call this with /project:review-pr and Claude has all the context it needs without you repeating yourself. The savings aren't in characters — they're cognitive. Every time you explain the same context again, you burn mental energy you could've spent on the actual problem.
Working on projects like the Buenos Aires bus sonification experiment — where the stack combines real-time GTFS-RT processing with audio synthesis — having persistent project context was the difference between productive sessions and endless onboarding sessions.
The mistakes I made before I understood this
Mistake 1: Treating CLAUDE.md like documentation for humans
My first attempt was to copy-paste the project README. Intuitively it makes sense, but it's the wrong approach. Human documentation explains what the system does. Instructions for Claude need to explain how you want it to work with you. Those are different things.
A README says: "This service processes Stripe webhooks."
A good CLAUDE.md says: "When working with the payments module, always verify idempotency keys, always log the webhook ID, never modify payment state without going through the state machine in /lib/payments/state.ts."
Mistake 2: Generic routines that say nothing
# ❌ This is useless
Write clean, well-documented code.
Follow best practices.
Be consistent.
# ✅ This actually works
Every function you write needs:
- JSDoc with typed @param and @returns
- At least one unit test in __tests__/[name].test.ts
- Explicit error handling — if it can fail, it must throw an Error with a descriptive message
Vague instructions produce vague results. Same thing that happens when you describe a requirement badly to a junior dev — and I know this firsthand from leading teams since 2023.
Mistake 3: Not separating global context from specific context
Dumping everything into one giant CLAUDE.md becomes noise. Claude reads all the context on every operation. If you mix instructions for writing DB migrations with React component naming conventions, you're contaminating context that isn't relevant to the current task.
Separating by subdirectory solves this. Instructions in .claude/commands/ only activate when you explicitly call them.
Mistake 4: Not versioning the routines
This one cost me. I updated some instructions, broke behavior that had been working, couldn't remember what I'd changed. Routines are code — they go in the repository, they have history, they have descriptive commits. "chore: update review instructions to include accessibility checks" is as valid a commit as any other.
Same principle as distributed systems where shared state without version control generates race conditions — something I dug into in the post about multi-agent development as a distributed systems problem.
What concretely changed in my workflow
Before: every session started with five minutes of "this project uses strict TypeScript, the DB is on Railway, components go in /components, use Zod for validation." Pure repetition.
After: Claude already knows all of that. The session starts at the actual problem.
The most unexpected change was in code review. I have a team and PRs are where the most time gets burned. With the review routine defined, Claude reviews with real consistency — it doesn't depend on my mood or whether it's Friday at 6pm. The criteria are always the same.
On consistency in analysis tools: working with security benchmarks like N-Day-Bench for vulnerabilities, persistent context about what kind of analysis you want — and what you don't — is critical for not wasting time on false positives.
The other change was in complex projects with non-obvious architecture decisions. When I was exploring Rust runtime options for TypeScript, having documented why certain decisions were made inside the routines prevents Claude — or any collaborator — from reverting them through well-intentioned refactoring.
FAQ: the most common questions when I shared this
Do Claude Code routines work on all projects or just large ones?
They work especially well on projects that last more than a week or where you're working with a team. For a one-day script, it's real overhead. For anything with more than 20 files and its own conventions, the ROI is positive from the first week. The threshold dropped for me when I realized the initial setup is 30 minutes, not hours.
Does CLAUDE.md replace the project README?
No, they're documents with different purposes. The README explains the project to humans arriving fresh. CLAUDE.md explains to Claude how to work with you on that project. There can be overlap but they're not interchangeable. I keep both separate.
What if multiple devs on the team have different styles in the routines?
The routines that go in the repository (.claude/ and CLAUDE.md) are team decisions, like any linter or prettier config. You discuss them, agree on them, version them. Personal preferences go in local config that doesn't get committed. Same principle as .gitignore.
Do routines affect token consumption/cost?
Yes, they add tokens per request because the context is included. In practice the cost is less than the cost of re-explaining context every session. That also consumes tokens. The difference is that with routines the context is precise and relevant — without routines, your informal explanation is probably longer and less useful.
Can I use routines for projects with hardware or unconventional stuff?
Absolutely. The context doesn't have to be about code only. For projects like hardware displays with compressed air, you can document the physical constraints of the system, safe operating ranges, what not to touch because it has real-world consequences. Claude needs that context just as much as it does for a pure software project.
Is there a size limit for CLAUDE.md?
There's no hard documented limit, but pragmatically: if your CLAUDE.md goes past 500 lines, something's wrong. Either you're dumping everything in one file when you should be splitting into specific command files, or you're including information that's documentary rather than instructional. I keep the global CLAUDE.md under 150 lines and everything else in task-specific files.
The resistance was mine — and that's the whole point
There's a cognitive trap that people who've been doing this for a long time fall into: confusing experience with efficiency. Knowing how to do something fast doesn't mean it can't be done better.
It happened to me at 16 in the internet café — I diagnosed connection drops from memory, no documentation, no process. It worked. Until it was 11pm, the place was packed, three machines were down, and I realized a 10-minute checklist prepared beforehand would've saved me 40 minutes of chaos.
Claude Code routines are that checklist. They're not for beginners who don't know what they're doing. They're for anyone who wants their tool working with the right context from the first message, not the fifth.
The overhead I was afraid of turned out to be 30 minutes of initial setup and 5 minutes of maintenance per week. What I get back is real time in every working session.
Have you set up routines in your Claude Code workflow yet? Or were you in resistance mode like I was? Tell me in the comments which instructions turned out to be the most useful — I'm especially curious if you're working with non-conventional stacks.
Top comments (0)