A practical guide to writing CLAUDE.md — commands, architecture, prohibited operations, and file references, illustrated with a real Rails project.
Every time you open Claude Code, it starts cold — no memory of your last session, no idea what your project does, no clue whether your test command is rspec or pytest, and no knowledge of which operations are off-limits.
CLAUDE.md fixes this. It's a persistent instruction file you write for Claude, loaded automatically at the start of every conversation. A well-written CLAUDE.md means Claude hits the ground running — no unnecessary questions, no rookie mistakes.
Claude Code supports a layered CLAUDE.md system with three levels:
~/.claude/CLAUDE.md: Global config, applies to all your projects. Use it for universal preferences like "never auto-commit git" or "reply in English."CLAUDE.md: Project-level config. The most common placement.CLAUDE.md: Only loaded when Claude works on files in that directory. Useful for giving frontend/, api/, or infra/ their own dedicated instructions.Multiple CLAUDE.md files stack — more specific files take precedence over broader ones.
One paragraph that tells Claude what the project is and what tech it uses:
## Project Overview
**Pickful AI** is a Ruby on Rails 8 cryptocurrency-focused social media platform.
Users can create posts, follow others, earn points, track coin prices,
and participate in a gamification system with leaderboards and VIP status.
- **Ruby Version:** 3.3.2
- **Rails Version:** 8.0.2
- **Database:** PostgreSQL with 4 separate databases (primary, cache, queue, cable)
Note the version numbers. Knowing it's Rails 8 prevents Claude from suggesting Rails 6-era patterns. Knowing there are 4 databases means it won't botch a migration.
This is the highest-ROI section in any CLAUDE.md. Without it, Claude guesses — and guesses wrong.
## Development Commands
### Running the Application
bin/dev # Start Rails server (port 3000) + Tailwind watcher
bin/rails server # Start Rails server only
### Testing
bundle exec rspec # Run all tests
bundle exec rspec spec/models # Run model tests
bundle exec rspec spec/path/to/file_spec.rb:42 # Run test at line 42
### Linting & Security
bin/rubocop # Run RuboCop linter (Rails Omakase preset)
bin/rubocop -a # Auto-correct offenses
bin/brakeman # Security vulnerability scan
### Deployment (Kamal)
bin/kamal deploy # Deploy to production
bin/kamal app logs # View application logs
bin/kamal app console # Remote Rails console
This tells Claude: tests run with bundle exec rspec, not rails test; deployment is Kamal, not Capistrano or Fly.io; the linter is RuboCop configured with the Rails Omakase preset. Without this, Claude has to guess all of it.
The purpose of architecture notes is to document decisions that aren't visible in the code itself. Claude can read your directory structure; it can't know why it's organized that way.
## Key Architectural Patterns
**Services Layer:**
Complex business logic extracted to `app/services/`.
Keep controllers thin, delegate to services.
**Authorization:**
Pundit policies in `app/policies/`.
Check UserPolicy, PostPolicy, etc. for permission rules.
**Background Jobs:**
Use `app/jobs/` for async processing.
Solid Queue handles job processing.
These three points tell Claude: don't pile business logic into controllers; find permission rules in app/policies/; use Solid Queue for anything async.
Grouping domain models by feature area is also worth doing:
## Core Domain Models
**Social Features:** User, Follow, Block, Referral
**Content:** Post, Comment, Topic, Tag, Draft
**Engagement:** Like, Favorite, Share, Report
**Cryptocurrency:** Coin, CoinPrice, Payment
**Gamification:** PointTransaction (VIP status at 400+ points)
This is faster than having Claude scan app/models/ and also carries business semantics — like the fact that 400 points is the VIP threshold, which isn't obvious from the code alone.
This is the most overlooked section, and often the most critical:
## Important Configuration
**Multi-Database:**
Always be aware of the multi-database setup.
Most migrations should target the primary database
unless working with cache/queue/cable features.
**Lexxy Integration:**
The app uses Lexxy gem (beta) for enhanced ActionText editing.
Configured in config/application.rb with:
config.lexxy.override_action_text_defaults = false
**Asset Handling:**
Uses Propshaft (not Sprockets).
Assets in app/assets/ are served without fingerprinting in development,
with fingerprinting in production.
All three of these are "skip it and you'll regret it" details: multi-database means migrations need an explicit target; Lexxy is a beta gem with different behavior from standard ActionText; Propshaft works differently from Sprockets. If Claude doesn't know these things, it'll operate on wrong assumptions and produce broken output.
This is the most underrated section. Telling Claude what not to do is far more efficient than correcting it after the fact.
## Do Not
- Do NOT run `git commit` automatically — always ask me to confirm first
- Do NOT modify files in `db/migrate/` that already exist
- Do NOT touch `.kamal/secrets*` files — production secrets, handle manually
- Do NOT run `bin/kamal deploy` without explicit instruction
The first item belongs in almost every project. Claude Code won't auto-commit by default, but leaving it unspecified creates ambiguity in edge cases. The deployment rule is even more important — a mistaken bin/kamal deploy hits production.
CLAUDE.md supports @ references to pull in other files:
Deployment config: @config/deploy.yml
Database schema: @db/schema.rb
Claude reads these files when relevant. This lets you keep CLAUDE.md concise while still giving Claude access to detailed reference material. db/schema.rb is an especially good target — in Rails projects it's the single source of truth for database structure, far more reliable than having Claude infer field names from model code.
Writing too much: CLAUDE.md consumes context window. Paste your entire README in there and Claude has less room to work with your actual code. Only write what Claude can't derive from reading the codebase itself.
Vague guidelines: "Write good code" is useless. Be specific: "Don't put business logic directly in controllers — delegate to app/services/."
Forgetting to update it: Switch from Sprockets to Propshaft, migrate from Sidekiq to Solid Queue — if CLAUDE.md doesn't keep pace, Claude operates on stale assumptions. Make updating CLAUDE.md part of your refactoring checklist.
Writing code examples: Examples eat context, and Claude reads real code more accurately than illustrative snippets. Use @ references to point at actual files instead.
# [Project Name]
[One-sentence description]
- **Ruby:** x.x.x
- **Rails:** x.x.x
- **Database:** PostgreSQL
## Development Commands
bin/dev # Start server
bundle exec rspec # Run tests
bin/rubocop # Lint
bin/kamal deploy # Deploy (ask before running)
## Architecture
[How Services / Jobs / Policies divide responsibility]
[Domain models grouped by feature area]
## Important Notes
[Non-obvious configuration, unusual gem behavior]
## Do Not
- Do NOT run git commit automatically
[Other high-risk operations]
Start here and fill in what your project actually needs. You don't have to cover everything — a CLAUDE.md with five sharp, accurate points beats one that's padded with noise.