4.2 KiB
Exercise 02: Hierarchy in Action
Concept: CLAUDE.md (CC-010) Level: Intermediate Time: ~15 minutes
Objective
See how global, project, and subdirectory CLAUDE.md files work together. Claude reads all three and applies them simultaneously, with more specific files taking precedence over broader ones.
Exercise 01 covered a single CLAUDE.md. This exercise shows the full stack.
Before You Start
Confirm you have:
- Completed Exercise 01 (or understand what CLAUDE.md does)
- Claude Code open in this repo directory
Important: This exercise creates a file at ~/.claude/CLAUDE.md, which
is your global Claude Code configuration. If you already have one, back it up first:
cp ~/.claude/CLAUDE.md ~/.claude/CLAUDE.md.bak
Restore it after the exercise with:
mv ~/.claude/CLAUDE.md.bak ~/.claude/CLAUDE.md
Instructions
Step 1: Create a global CLAUDE.md with a personal preference.
This file applies to every project you open with Claude Code, everywhere.
mkdir -p ~/.claude
Then paste this prompt into Claude Code:
Create a file at ~/.claude/CLAUDE.md with exactly this content:
# Global Preferences
Always respond in British English. Use "colour" not "color",
"organise" not "organize", "realise" not "realize".
When writing prose, prefer shorter sentences.
Step 2: Create a project-level CLAUDE.md with a project rule.
This file applies only when Claude Code is open in this directory. Paste this prompt:
Create a CLAUDE.md in the current directory (not ~/.claude/) with exactly this content:
# Project Rules
Language: TypeScript only. No JavaScript files.
Indentation: 2 spaces. No tabs.
Imports: named imports preferred over default imports.
Step 3: Create a subdirectory CLAUDE.md with test-specific rules.
mkdir -p tests
Then paste:
Create a file at tests/CLAUDE.md with exactly this content:
# Test Rules
Test framework: vitest only.
Pattern: describe/it blocks with descriptive names.
Assertions: use expect() with .toBe(), .toEqual(), or .toThrow().
No jest, no mocha, no chai.
Step 4: Ask Claude to create a function and a test, then observe.
Paste this prompt:
Write a TypeScript function called formatDate that takes a Date object
and returns a string in the format "DD Month YYYY" (e.g. "04 April 2025").
Then write a vitest test for it in tests/formatDate.test.ts.
Watch the output carefully. Claude should:
- Use TypeScript (project rule)
- Use 2-space indentation (project rule)
- Use named imports (project rule)
- Use vitest with describe/it (test rule)
- Write in British English where prose appears (global rule)
Expected Output
After completing all four steps, you should see:
- A
formatDate.tsfile using TypeScript, 2-space indentation, named imports - A
tests/formatDate.test.tsfile using vitest, describe/it pattern - Any comments or prose Claude writes use British English spellings
- Claude did not ask which framework to use or what indentation to apply
How you know hierarchy worked: All three levels applied at once. The test file followed both the project rules (TypeScript, 2-space) AND the test-specific rules (vitest, describe/it). The global preference (British English) applied throughout.
What You Learned
- Global scope:
~/.claude/CLAUDE.mdapplies to every project - Project scope:
./CLAUDE.mdapplies only in the current directory - Subdirectory scope:
tests/CLAUDE.mdapplies only when working intests/ - More specific overrides broader: If a test-specific rule conflicts with
a project rule, the test-specific rule wins inside
tests/ - All levels apply simultaneously: Claude does not choose one level. It reads all of them and follows all of them
Clean Up
rm -f CLAUDE.md formatDate.ts tests/CLAUDE.md tests/formatDate.test.ts
rmdir tests 2>/dev/null || true
And if you backed up your global CLAUDE.md:
mv ~/.claude/CLAUDE.md.bak ~/.claude/CLAUDE.md
Or remove the test global file if you created a fresh one:
rm ~/.claude/CLAUDE.md
Next
Ready to take a bad CLAUDE.md and make it effective? Move to Exercise 03: Audit and Improve.