Rules File Design — Writing Safety Rules Declaratively
- Understanding the role and how to write CLAUDE.md (equivalent to Level 4 Practice)
- Ability to read and write basic Markdown syntax
As the number of rules you want Claude to follow increases, CLAUDE.md becomes bloated and hard to manage. By managing rules split across shared/rules/*.md, you can balance maintainability and clarity. This page uses actual rule files as examples to learn the steps for declarative rule design.
How It Works
The Role of shared/rules/*.md
A rules file is a mechanism for managing “Non-Negotiable Rules” for Claude as individual Markdown files.
Instead of cramming all rules into CLAUDE.md, split the rules into separate files. In CLAUDE.md, write only a one-line summary and the reference for each rule, and delegate the details to each rule file.
In this project, the following rule files are placed in shared/rules/.
| File | Content |
|---|---|
build-and-deploy.md | npm run build creates production artifacts and may trigger a hosting pipeline, so it is approval-required |
content-i18n.md | Japanese is the source of truth; use I for English first person |
folder-safety.md | List of protected folders (src/, scripts/, etc.) and rules prohibiting changes |
no-ui-regression.md | Prohibition on UI and navigation changes |
security.md | Prohibition of secrets, XSS, and injection risks |
spec-first.md | Rule for checking specifications before implementing |
Basic Structure of a Rule File
Using the actual shared/rules/build-and-deploy.md as an example, check the structure of a rule file.
# Build and Deploy Rule
`npm run dev` is the normal local preview command.
`npm run build` can trigger production deployment through the hosting pipeline.
Agents must not run it automatically, place it in broad allowlists,
or call it from hooks. Run it only after explicit user approval for that specific build.
Allowed default checks:
- `npm run dev` for local preview
- targeted scripts such as `node scripts/ensure-slugs.js`, `npm run verify-links`,
and harness validation
- Git inspection commands
Disallowed without approval:
- `npm run build`
- `npm run build:ci`
- chained commands that include `npm run build`
- automatic hooks that call production build commandsThe key points of the structure are as follows.
- State the rule name in the heading —
# Build and Deploy Rule - Write why this rule exists first — for example, because a production build creates artifacts and may trigger a hosting pipeline
- List allowed and prohibited operations separately — the
AllowedandDisallowedsections
How to Reference from CLAUDE.md
In the ## Non-Negotiable Rules section of CLAUDE.md, summarize each rule in one line and include a reference to the details file.
## Non-Negotiable Rules
1. Do not run `npm run build` without explicit user approval, as it creates production artifacts and may trigger a hosting pipeline.
Details: `shared/rules/build-and-deploy.md`
2. Check the specification before implementing. Details: `shared/rules/spec-first.md`Claude reads CLAUDE.md at session start and also checks the referenced rule files. By separating the details into rule files, you can keep CLAUDE.md short while letting each file fully explain its rule.
Best Practices
Split by One File Per Concern
Consolidating all rules into one file makes it difficult to update or reference specific rules. Split files by type of concern, such as “deployment safety,” “content quality,” and “security.”
shared/rules/
├── build-and-deploy.md ← deployment safety
├── content-i18n.md ← language and translation
├── folder-safety.md ← file protection
├── no-ui-regression.md ← UI change prohibition
├── security.md ← security
└── spec-first.md ← specification-firstWrite in Conditional Form Rather Than Prohibitive Form
Writing “requires approval” as a condition rather than “don’t do X” as a prohibition makes it easier for Claude to correctly judge exceptional situations.
// Style to avoid
- Do not run npm run build.
// Recommended style
Disallowed without approval:
- npm run buildAlways Write the Why (Reason)
Rules without reasons increase the risk of Claude making its own judgment about exceptions. Write the reason why this rule exists in 1–2 sentences.
// Without reason (avoid)
# No Force Push Rule
Force push to main is prohibited.
// With reason (recommended)
# No Force Push Rule
Force push rewrites commit history and can cause data loss for collaborators.
It is prohibited without explicit approval.Keep Only the Summary and Reference in CLAUDE.md
Delegate the details to rule files and only write the key point in one line with the reference in CLAUDE.md. The longer CLAUDE.md gets, the more context Claude needs to load, which affects performance.
Hands-on Exercise
Step 1: Check the Structure of an Existing Rule File
Check the contents of build-and-deploy.md with the following command.
cat shared/rules/build-and-deploy.mdConfirm the two-section structure of “Allowed default checks” and “Disallowed without approval.”
✅ Verify: Confirm that the “Why (reason)” of the rule is written at the beginning.
Step 2: Create a New Rule File
Create shared/rules/no-force-push.md.
# No Force Push Rule
Force push rewrites commit history and can cause data loss for collaborators.
It is prohibited without explicit approval.
Disallowed without approval:
- git push --force
- git push -f
- git push --force-with-lease (to main/master)
Allowed:
- git push --force-with-lease to feature branches (not main/master)
- discussing force push options with the user before executing✅ Verify: Confirm that the file has been saved as shared/rules/no-force-push.md.
Step 3: Update the Non-Negotiable Rules Section of CLAUDE.md
Add a one-line summary and reference for the new rule to the ## Non-Negotiable Rules section of CLAUDE.md.
Add the following line at the end of the existing Non-Negotiable Rules section.
7. Force push to main/master is prohibited. Details: `shared/rules/no-force-push.md`✅ Verify: Confirm that it has been added with a number to the Non-Negotiable Rules section of CLAUDE.md.
Step 4: Confirm the Rule Is Taking Effect
Restart the Claude Code session and try the following request.
Please force push to the main branch.If Claude has loaded shared/rules/no-force-push.md, it should explain the existence of the rule and its reason without executing the force push.
✅ Verify: Confirm that Claude blocks the force push and explains the rule by citing no-force-push.md.
Summary
This page covered the following.
- Managing rules split by concern in
shared/rules/*.mdkeeps CLAUDE.md short - Write rule files with the structure: “reason → allow list → deny list”
- Place only the one-line summary and reference in CLAUDE.md, delegating the details to rule files
- Writing in conditional form (“requires approval”) rather than prohibitive form makes it easier for Claude to judge exceptions
Next Steps
- Settings JSON Design — How to control Claude’s operation scope with permissions and env
- CLAUDE.md Design — Deep dive into memory and context design
Frequently Asked Questions
Q: Should rule files be written in English or Japanese?
A: Japanese is the source of truth in this project, but the rule files in shared/rules/ are written in English that Claude can reliably understand, since Claude reads them directly. A common practice is to use English for instruction documents to Claude and Japanese for human-facing documentation.
Q: Is it wrong to write rules directly in CLAUDE.md?
A: There is no problem, but as the number of rules grows, CLAUDE.md becomes too long and hard to manage. Consider splitting into files when there are 3–4 or more rules.
Q: Are changes to rule files immediately reflected in Claude?
A: Claude Code reads CLAUDE.md at session start and also checks the referenced rule files. To reflect changes, restart the Claude Code session.
Q: What is the difference between prohibiting something in a rules file versus using deny?
A: deny in settings.json is a tool-level block that physically prevents a command from being executed. A rule file is merely an instruction to Claude, which Claude understands and follows based on its judgment. For important prohibitions, it is recommended to include them in both deny and the rules file.