5.6 KiB
CLAUDE.md
Cross-project preferences for working with me. Project-specific CLAUDE.md files extend or override these.
Writing
Linear prose
Avoid em-dashes (—), en-dashes (–), double hyphens (--) as em-dash substitutes, and semicolons in prose. Applies to anything checked in to a project: code comments, Markdown docs, commit messages, and PR descriptions. Code syntax isn't prose, so language constructs like ; as a statement terminator or separator don't count.
Sentences should read linearly. Em-dashes, en-dashes, and semicolons all introduce sub-clauses or asides that interrupt the flow. Swapping one for another (em-dash for semicolon, em-dash for double hyphen) shifts the punctuation without solving the underlying issue. Restructure instead:
- Split into two sentences with a period.
- Use a connective: "because", "since", "which", "and", "so", "while", "where".
- Use parentheses for a genuine aside, sparingly.
- Use a comma for a short, tightly-integrated clause.
- Rework so the sub-clause isn't needed.
Don't substitute a regular hyphen between words where an em-dash would have gone. That's broken English, not a fix.
No jargon acronyms
Don't use programming-culture acronyms like YAGNI, DRY, KISS, SOLID, TDD, BDD, DDD, MVP, SOA, NBO, TOCTOU. Applies in chat, code comments, commit messages, and docs. Even when the reader knows them, they read as in-group shorthand and force a mental expansion step. Say what you mean: "don't build it until a second caller exists" instead of "YAGNI", "extract this once it's duplicated three times" instead of "DRY", "network byte order" or "big-endian" instead of "NBO", and so on.
Common technical abbreviations that name a thing (HTTP, JSON, SQL, API, CLI, TCP, MAC) are fine. The rule targets acronyms that encode a principle, opinion, or piece of jargon, not those that name a protocol or format.
Code
No section-divider comments
Don't add section-divider comments in source files: no // --- horizontal rules, no // === banners, no // -- Label -- headers that announce the next region of a file. The struct / impl / class / function definitions already mark structure, and the banner just duplicates that visually.
If a file is large enough that its structure is genuinely hard to follow, split it into submodules or smaller files instead of layering dividers on top. Strip these when touching files that already have them.
Markdown section headers in docs (## Foo) are fine. They're the intended way to structure prose.
No milestone references in code docs
Don't write "for M2", "added in M1", "comes in M3", or similar milestone references in code comments or doc comments (rustdoc, JSDoc, equivalents). Describe what the code currently does or doesn't do, not which roadmap milestone it was written in or will be extended in.
Milestones live in roadmap docs (TODO.md, ROADMAP.md, equivalents) and are a planning artifact. Pinning them into code docs ties the code to a numbering that will keep shifting as milestones are added, renumbered, or dropped. The code's current behaviour is the durable thing to document. The project-management metadata belongs in roadmap docs.
If future work is worth flagging in a doc comment, say what that future work is, not when it's scheduled.
Commits
Use Conventional Commits
Commit messages follow the Conventional Commits format. Apply this to every new commit you make.
Format:
<type>(<optional scope>): <short description>
<optional body explaining the why>
<optional footers, e.g. BREAKING CHANGE: ...>
Common types:
feat: a new user-facing capability.fix: a bug fix.refactor: code restructuring with no external behaviour change.perf: a performance-focused change with no behaviour change.docs: documentation only.test: test-only changes.build: build-system, dependency, or configuration changes.chore: repo housekeeping that doesn't fit above.style: formatting only (rarely warranted if a formatter runs).
Subject line: imperative, lowercase after the colon, no trailing period, aim for <= 72 chars. Body paragraphs explain the why, not the what (the diff shows the what).
Scope may use slash-separated subscopes (fix(parser/lexer), feat(api/auth)) when the precision adds information about which submodule changed. Flat scopes (fix(parser)) are fine for broader changes. Inconsistency between commits is acceptable — subscope depth doesn't need to be uniform.
Breaking changes: append ! to the type or scope (feat(api)!: ...) and include a BREAKING CHANGE: footer when the change needs explanation.
Don't retroactively rewrite committed history unless the user explicitly asks.
No Co-Authored-By Claude line
Don't add Co-Authored-By: Claude ... <noreply@anthropic.com> (or any Claude co-author trailer) to commit messages. End the commit with the actual content. The user finds the trailer adds clutter without serving any audience.
Collaboration
Treat questions as questions, not directives
When the user asks a clarifying question about something I've done or written ("why did you do X?", "is X needed?", "what about Y?", "won't this cause Z?"), respond with the rationale and any tradeoffs, then wait for their decision. Don't immediately remove or change X based on the question alone.
A question is information-seeking, not an instruction. Acting on it skips the user's decision step and can revert work that was actually right, forcing them to re-prompt to keep it. The user wanted to know why, not for me to undo it.
Edit-and-explain together is fine when they explicitly request both ("why X, and fix it if it's wrong"). The rule applies to bare questions.