Appearance
CLAUDE.md Style Guide
Your CLAUDE.md is already the source of truth for how your team writes code. Caliper reads it and compiles every mechanically-enforceable rule into a deterministic check — grep patterns, AST analysis, file-exists validations, and more. Rules that require human judgment become conventions for the AI review layers.
This guide shows how to write CLAUDE.md rules that Caliper can compile into checks, and how to recognize rules that will remain AI-evaluated conventions.
What Caliper extracts
When you run caliper refresh, Caliper scans your CLAUDE.md (and other instruction files) looking for rules it can enforce automatically. Each rule falls into one of two buckets:
- Compilable rules — mechanically checkable, deterministic. These become checks that run in milliseconds with no API calls.
- Conventions — judgment-based rules that require AI evaluation. These are surfaced during AI review phases.
The more rules Caliper can compile, the faster and more efficient your enforcement loop becomes. The rest of this guide is about maximizing that ratio.
Rule categories that compile well
Pattern bans (grep)
Rules that forbid a specific token or pattern in source code.
markdown
- Never use `eval()` in application code
- No `console.log` in production source files
- Do not use `any` as a type annotationCaliper compiles these into grep checks that scan changed files for the forbidden pattern.
Structural limits (AST)
Rules that constrain the shape of code — function length, nesting depth, parameter count, cyclomatic complexity.
markdown
- Keep functions under 30 lines
- No function should have more than 4 parameters
- Maximum nesting depth of 3 levelsCaliper parses the AST and measures each function against the stated threshold.
File conventions (file-exists)
Rules that require companion files — tests, migrations, index files.
markdown
- Every module in src/ must have a corresponding test file in tests/
- Every migration must have a rollback fileCaliper checks that the expected companion file exists on disk.
Import requirements (file-contains)
Rules that require certain imports or patterns to be present in matching files.
markdown
- Scripts in bin/ must import dotenv/config
- API route handlers must validate input with Zod
- Every React component file must import PropTypes or use TypeScriptCaliper compiles these into conditional checks: if a file matches the scope, it must contain the required pattern.
Naming conventions (file-path)
Rules about file and directory naming.
markdown
- Use kebab-case for all filenames in src/
- Test files must end with .test.ts or .spec.ts
- No uppercase letters in directory namesCaliper validates file paths against the naming pattern.
Security rules (grep + conditional)
Rules that forbid dangerous patterns, optionally with exceptions.
markdown
- Never use execSync with template strings — use execFileSync with array args
- No hardcoded API keys or secrets in source files
- Never use dangerouslySetInnerHTML without a sanitization wrapperCaliper compiles these into grep bans, sometimes with conditional logic (if file contains X, it must not contain Y).
Rule categories that become conventions
Some rules genuinely require judgment. Caliper passes these to the AI review layers rather than trying to automate them.
| Rule | Why it can't compile |
|---|---|
| "Functions should have clear, descriptive names" | "Clear" is subjective |
| "Error messages should be helpful to the user" | Requires understanding intent |
| "Code should be well-organized" | No measurable threshold |
| "Avoid unnecessary complexity" | "Unnecessary" requires context |
| "Comments should explain why, not what" | Requires semantic understanding |
These rules still have value — they guide AI review and human reviewers. But they produce zero deterministic checks.
Writing tips for maximum compilation
Be specific and quantitative
| Vague (convention) | Specific (compiles) |
|---|---|
| Keep functions short | Keep functions under 30 lines |
| Limit function complexity | Maximum cyclomatic complexity of 10 |
| Don't nest too deeply | Maximum nesting depth of 3 levels |
Name the exact pattern to avoid
| Vague (convention) | Specific (compiles) |
|---|---|
| Avoid shell injection | Never use execSync with template literals |
| Don't use unsafe patterns | Never use eval() or new Function() |
| Be careful with user input | Never use innerHTML — use textContent |
Specify file scope
| Unscoped (weaker) | Scoped (stronger) |
|---|---|
| No console.log in the codebase | No console.log in src/ files |
| Tests must exist | Every file in src/ must have a test in tests/ |
| Use strict mode | Files in scripts/ must start with 'use strict' |
Scoping tells Caliper exactly which files to check, reducing false positives and making checks faster.
Use negative framing for bans
Caliper looks for ban signals — words like "never", "no", "do not", "must not", "avoid". Positive framing works for requirements ("must import X"), but for prohibitions, be direct:
markdown
# Compiles well
- Never use `var` — use `const` or `let`
- No default exports in src/ modules
- Do not use `@ts-ignore` — use `@ts-expect-error` with a comment
# Less likely to compile
- Prefer const over var
- We like named exports better than default exportsExamples
Before and after
Here are real-world rules rewritten for maximum compilability:
Before: "Use modern JavaScript features"
After: "Never use var — use const or let. No arguments object — use rest parameters. No apply() — use spread syntax."
Three separate grep checks instead of zero.
Before: "Handle errors properly"
After: "Every async function in src/api/ must have a try-catch block or return a .catch() chain."
A conditional file-contains check.
Before: "Keep the codebase clean"
After: "No files in src/ longer than 300 lines. Keep functions under 30 lines. No TODO comments older than 30 days."
Three separate checks: max-lines, AST function length, grep for TODO.
Before: "Follow security best practices"
After: "Never use execSync with template strings — use execFileSync with array args. Wrap new RegExp() on user input in try-catch. Never store secrets in source files — use environment variables."
Three targeted grep/conditional checks.
Before: "Write tests for everything"
After: "Every .ts file in src/ must have a corresponding .test.ts file in tests/."
A file-exists companion check.
Before: "Use consistent naming"
After: "All filenames in src/ must use kebab-case. No uppercase letters in directory names under src/."
Two file-path checks.
Multi-tool support
Caliper does not only read CLAUDE.md. It scans all common AI instruction files in your repository:
| File | Tool |
|---|---|
CLAUDE.md | Claude Code |
.cursor/rules/*.md | Cursor |
.github/copilot-instructions.md | GitHub Copilot |
.windsurfrules | Windsurf |
CONVENTIONS.md | General |
All of these files are treated as sources of conventions. Rules from any of them can be compiled into checks. If your team uses multiple AI coding tools, you only need to write your conventions once in whichever file you prefer — Caliper will find them.
Summary
The key principle: write rules as if you're giving instructions to a machine, not advice to a human. Every time you can replace a subjective word ("clean", "good", "proper") with a measurable criterion (line count, pattern match, file existence), you convert a convention into a free, instant, deterministic check.
Run npx caliper refresh after updating your CLAUDE.md to see which rules compile and which become conventions.