CLAUDE.md as a System Prompt Layer
Request processing stack:
┌──────────────────┐
User request │ User Message │
└────────┬─────────┘
│
┌────────▼─────────┐
Session system prompt (D4) │ Session Prompt │ ← runtime D4 prompt
"You are a code reviewer..." └────────┬─────────┘
│
┌────────▼─────────┐
Project-level CLAUDE.md (D3) │ Project CLAUDE.md│ ← processed as system content
"Repository pattern required..." └────────┬─────────┘
│
┌────────▼─────────┐
Directory-level CLAUDE.md (D3) │ Directory Rules │ ← path-specific injection
"API layer conventions..." └────────┬─────────┘
│
┌────────▼─────────┐
User-level CLAUDE.md (D3) │ User Prefs │ ← personal layer
"Prefer verbose output..." └────────┬─────────┘
│
Claude
All four layers are effectively instructions to Claude. D4 principles improve every layer.
Applying D4 to CLAUDE.md
Before (vague — D4 violation)
# CLAUDE.md rule
- Write comprehensive tests
- Handle errors properly
- Keep functions small
After (explicit criteria — D4 applied)
# CLAUDE.md rule
## Test Requirements (D4: explicit, verifiable criteria)
Every new public function must have:
- At minimum ONE happy path test
- At minimum ONE error path test for each documented exception
- Tests use pytest fixtures from tests/conftest.py (not setUp/tearDown)
- External services mocked — no real API calls in tests
Example of SUFFICIENT test coverage:
def test_get_customer_success(mock_db):
result = get_customer("C-123456")
assert result["name"] == "Test Customer"
def test_get_customer_not_found(mock_db):
mock_db.returns_none()
with pytest.raises(CustomerNotFoundError):
get_customer("C-999999")
Example of INSUFFICIENT test coverage (do not accept PRs with only this):
def test_get_customer():
# only tests that function runs, not correct behavior
result = get_customer("C-123456")
assert result is not None
The D4 improvements:
- Explicit criteria (D4 T4.1): “ONE happy path + ONE error path” not “comprehensive”
- Positive examples (D4 T2.1): shows what sufficient coverage looks like
- Negative/rejection examples (D4 T2.1): shows what INSUFFICIENT looks like
- Verifiable (D4 T4.1): a reviewer can check these requirements objectively
Path-Specific Rules as Conditional Prompt Injection
# .claude/rules/api-conventions.yaml
# D3: Only loads when editing src/api/** files
# D4 lens: This is conditional system prompt injection
---
paths:
- "src/api/**/*.ts"
description: "API layer conventions"
---
# D4 principle: Specific and verifiable criteria
Response validation requirements:
- All responses use ErrorResponse schema: {error: string, code: string}
- Status codes: 400 (input invalid), 401 (auth required), 403 (forbidden), 404 (not found)
# D4 principle: Include rejection examples
WRONG — do not do this:
return res.status(400).json({message: "Invalid input"}) // not using ErrorResponse schema
CORRECT:
return res.status(400).json({error: "Invalid input", code: "VALIDATION_ERROR"})
Key Takeaways
- CLAUDE.md is system prompting — D4 principles apply when writing it
- Replace vague rules with explicit criteria — verifiable, not aspirational
- Include both examples (positive and negative) in CLAUDE.md rules
- Path-specific rules = conditional prompt injection — different files, different instructions
- Two-layer hierarchy: project CLAUDE.md for team conventions, session prompt for task specifics