Writing "Write clean code" in CLAUDE.md changes nothing.
During the process of building 10 personal apps in three months, I rewrote CLAUDE.md many times.
Since it became clear what worked and what didn't, I will outline that distinction.
What Doesn't Work
Giving instructions with adjectives
- Write clean code
- Design for maintainability
- Handle errors appropriately
- Consider performance
None of these work. Because "clean" and "appropriate" cannot be objectively judged.
Instructions that cannot be judged cannot even be verified by yourself as to whether they are followed.
And the person who wrote them cannot verify later if they were followed.
Rules that cannot be verified are the same as non-existent.
Writing general best practices
- Follow the DRY principle
- Adhere to the Single Responsibility Principle
- Do not use magic numbers
The model already knows these. Writing them adds no information.
The role of CLAUDE.md is to convey what the model does not know (project-specific circumstances).
Writing things that can be understood by reading the code
- We use Zustand for state management
- We use Vitest for testing
You can see this in package.json. If you write anything, it should be "why we chose it" or "what not to do".
- State management is Zustand. Migration to Redux was considered but rejected due to boilerplate increase. Do not suggest it.
This is worth writing. You will stop receiving the same suggestions every time.
What Works
Writing prohibitions in a verifiable format
- Do not use pure black `#000000` or pure white `#ffffff`
- Do not use gradient backgrounds or gradient heading text
- Limit to 3 types of motion per screen
You can verify this with grep '#000000'. Because it is verifiable, you can mechanically inspect if it is followed.
The shape of a UI belongs in a UI specification, not in CLAUDE.md. What goes here
is the floor beneath the specification — the line you do not want crossed even
when no specification exists. The principle does not change: the persona that writes
the code does not decide how it looks.
"Make the UI clean" does not work, but "Do not use pure black" does. The difference lies not in the model's comprehension, but in whether the instruction is verifiable.
Reducing permissions
This was the most effective.
- Do not modify paths outside the scope described in the assigned Issue
- If changes outside the scope are needed, stop implementation and report it
- Only Reviewers may merge to main
"Cannot do ~" is more effective than "Do ~".
Instructions that increase what you can do have a wide range of interpretation, while prohibitions are narrow.
Especially the phrase "stop implementation and report it" was effective. Without this,
when the model hits constraints, it tries to push forward somehow.
Providing an exit allows it to retreat there.
Explicitly stating exceptions
When writing prohibitions, cases of "but what about this exception?" always arise. Write them in advance.
Things not treated as out-of-scope:
- Automatic updates of lock files due to dependency additions
- Test files corresponding to modified files
If you don't write them, judgments will vary each time. Inconsistent judgments hollow out the rules.
Writing order and dependencies
- Do not start issues involving UI until the UI specification status is:done
- Coders in the parallel execution group must be launched simultaneously within one message
The second point actually worked. Separating calls makes them serial, so
without explicit instruction, they will not run in parallel.
Using tables
For lists of states or labels, I have the impression that tables are referenced more often than bullet points.
| Label | Meaning | When to assign |
|---|---|---|
| `status:planned` | Issue created, not started | When Architect creates the Issue |
| `status:review` | PR created, waiting for review | When Coder creates the PR |
Writing "when to assign" is important. If you only write the meaning, you will forget to assign them
(in the end, I shifted this to GitHub Actions, but that's a different story).
Regarding Length
Shorter is better.
I once wrote a CLAUDE.md that swelled to 74KB, but the latter half was followed less.
I haven't verified this definitively, but the experience was clear.
The one I use now is around 7KB. The breakdown is as follows:
| Section | Proportion |
|---|---|
| Permissions by role (what can and cannot be done) | 40% |
| Overall flow (who receives what from whom) | 30% |
| State management (labels and when to assign them) | 20% |
| Explicit exceptions | 10% |
It contains zero general knowledge.
The cause of the swelling was "just in case I write it." Lines written "just in case" tend to become unjudgable instructions. Unjudgable instructions don't work, so writing them only dilutes the file.
How to Verify
Whether a written rule works is judged by whether you can notice when it is broken.
- Scope violation → Can be seen with
gh pr diff --name-only - Hardcoded colors → Can be seen with
grep - Missing labels → Can be seen by checking the Issue list
- "Clean code" → Cannot be seen
There is no verification method for the last one. That's why it doesn't work.
Before writing, asking "can I notice if this is broken?" helps you avoid writing ineffective lines.
Summary
- Do not give instructions with adjectives. Unjudgable instructions don't work.
- Do not write general best practices. The model already knows them.
- Do not write things that can be understood by reading the code. If writing, include "why" and "what not to do".
- Write prohibitions in a mechanically inspectable format.
- "Cannot do ~" is better than "Do ~". And always provide an exit (stop and report).
- Explicitly state exceptions in advance. Inconsistent judgments hollow out rules.
- Keep it short. Lines written "just in case" tend to be ineffective.
- Before writing, verify "can I notice if it is broken?"
I have published the CLAUDE.md written with this approach and sub-agent definitions for four personas under the MIT license.
I publish the configuration for splitting Claude Code into separate personas —
Architect, Coder, Reviewer, Conflict Resolver — under MIT. Copy it, run
./setup.sh, and it works. It does not depend on your tech stack.
https://github.com/quintetkit/quartet
I built one real tool using nothing but this workflow. Every Issue, PR, review
and merge is still there. The parts that went wrong were not deleted.
https://github.com/quintetkit/mdlinkcheck
The version that adds a UI Designer persona, review criteria, a per-Issue
parallel execution script and a 10-chapter guide is on the
product page.
Top comments (0)