Coding Conventions & Style Guides in CLAUDE.md
Coding conventions are one of the easiest CLAUDE.md sections to get wrong in a specific way: restating what your linter and formatter already enforce mechanically, while leaving out the conventions that actually require human judgment — the ones no tool can auto-fix.
Skip What’s Already Enforced
<!-- Redundant if ESLint already enforces this -->- Always use semicolons- Use 2-space indentation- No unused variables
<!-- Worth stating — these require judgment a linter can't automate -->- Prefer composition over inheritance for shared behavior between components- Error messages shown to users must never include raw exception text or stack traces- New API endpoints must be added to `openapi.yaml` in the same PRIf a rule is fully enforced by tooling, the agent will encounter it as a lint error regardless of whether CLAUDE.md mentions it — restating it adds nothing. Reserve the file for conventions that are matters of judgment, not mechanically checkable rules.
State the “Why” When It’s Non-Obvious
A convention with an unstated rationale is easy to accidentally violate in an edge case the rule-writer didn’t anticipate; a convention with its reasoning attached is much easier to apply correctly to new situations.
<!-- Just the rule -->- Don't use `Array.prototype.sort()` without a comparator function.
<!-- Rule plus reasoning — generalizes better -->- Don't use `Array.prototype.sort()` without a comparator function — the default sort coerces to strings, which silently misorders our numeric IDs. This applies to any sort of numeric or mixed-type data, not just the specific case that originally surfaced the bug.The second version equips the agent to recognize other situations the same underlying issue applies to, not just the one example given.
Naming and Organization Conventions
## Naming
- React components: PascalCase, one component per file, filename matches component name (`UserAvatar.tsx` exports `UserAvatar`)- Hooks: camelCase prefixed with `use` (`useUserData`, not `getUserData`)- Test files: colocated, `<name>.test.ts` next to `<name>.ts`- Boolean variables/props: prefixed with `is`/`has`/`should` (`isLoading`, not `loading`)Naming conventions are a case where being explicit genuinely changes agent output — without guidance, an agent will pick a reasonable-but-possibly-inconsistent convention of its own, and consistency across a codebase compounds in value the larger it gets.
Error Handling and Defensive Patterns
## Error Handling
- User-facing errors go through `formatUserError()` — never surface raw error messages or stack traces in UI-visible text- Internal service errors should be logged with `logger.error()` including a request ID, then re-thrown — don't swallow errors silently- Prefer typed error classes (`ValidationError`, `NotFoundError`) over generic `Error` when the error type needs to be distinguished downstreamError-handling conventions are especially worth documenting because inconsistency here often isn’t caught by tests (a swallowed error might not cause a visible failure) but has real production consequences.
Testing Philosophy
## Testing Philosophy
- We favor integration tests over heavily-mocked unit tests for anything touching the database — mocks have drifted from real schema before and masked real bugs- New features need at least one test covering the primary success path; 100% branch coverage is not required or expected- Snapshot tests are avoided — they tend to be updated reflexively without review rather than genuinely verifiedThis kind of philosophical guidance — not just mechanical style rules — is exactly the sort of context a new human contributor would only pick up after several code reviews, and exactly what CLAUDE.md can shortcut.
Common Mistakes
Documenting style choices a formatter (Prettier, Black, gofmt) already enforces automatically. These tools exist specifically so nobody — human or agent — needs to think about them; restating them in CLAUDE.md is pure redundancy.
Writing conventions as bare rules without examples. “Prefer composition over inheritance” is more useful with even a short code snippet showing what that looks like in this specific codebase’s idioms than as an abstract principle alone.
Conventions sections that contradict what the linter config actually enforces. If CLAUDE.md says “we use single quotes” but ESLint is configured for double quotes, the file is actively wrong — treat convention documentation as something that needs to stay synchronized with the actual enforced configuration, not just written once and assumed accurate.
Frequently Asked Questions
Should I document a full style guide, or link to an external one? If your team already has a comprehensive external style guide (a company-wide engineering handbook, for instance), link to it and use CLAUDE.md only for genuine deviations or project-specific additions — duplicating an entire external document into CLAUDE.md creates a second copy that will drift out of sync.
How do I handle conventions that are actively being changed/migrated? State the transition explicitly rather than presenting the old convention as current: “New code should use the Result<T, E> pattern for error handling; older code still uses exceptions and is being migrated incrementally — don’t convert existing exception-based code unless that’s the specific task.”
Is it worth documenting conventions the team disagrees about? Better to resolve the disagreement (even provisionally) and document the resolution than to leave it ambiguous — an unstated internal disagreement just means the agent’s behavior on that point becomes inconsistent and unpredictable across sessions.
Summary
The highest-value convention documentation is exactly the material a linter can’t enforce and a new hire would only learn through code review: naming philosophy, error-handling patterns, testing approach, and the reasoning behind non-obvious rules. Skip what tooling already guarantees, and where you do document a rule, attach its “why” — that’s what lets an agent apply it correctly to situations the original rule-writer never explicitly anticipated.