Chapter 07
Claude-Specific Practices
Most of this book assumes the project is yours to set up from the start: the CLAUDE.md written before the first feature, the tests built alongside the first services, the conventions agreed while the team is still small. Most real projects are not like that. They were running before you arrived, with no CLAUDE.md, partial tests, and a deploy half in someone’s shell history, and the discipline has to be retrofitted around a system that is already shipping. The direction does not change between the two; the pace and the chunk size do. In a new codebase you put the conditions in place before drift starts. In an existing one you bring them in gradually, starting with the surfaces that change most and the paths that carry the most risk. The same gradualism keeps a rewrite survivable when cheaper construction makes one tempting, because the migration and the organizational patience a rewrite needs did not get cheaper just because the typing did.
The rest of this chapter is the concrete layer: the exact files and keys Claude Code reads as of this writing. Expect them to move. The categories from the last chapter are the part that lasts.
CLAUDE.md
The constitution loads at the start of every session. It can live at the project root, in .claude/CLAUDE.md, in your user file at ~/.claude/CLAUDE.md, or in a gitignored CLAUDE.local.md; the discovered files stack together. Pull other files in with an @path reference, and keep each file small.
# CLAUDE.md
Stack: Flask, Jinja, Pico.css. No build step.
See @docs/architecture.md for the layer model.
- Run tests with `pytest`.
- Never add a fallback for a required env var; fail at boot.
Path-scoped rules
Files in .claude/rules/ carry a paths: frontmatter and load only when the agent reads a matching file, so instructions that apply to one part of the tree do not sit in context the rest of the time. A rule with no paths: loads every session.
---
paths:
- "app/templates/chapters/**"
---
# Writing the prose
First person, plain declaratives, no em-dashes.
settings.json
Technical configuration resolves across scopes, with the higher scope winning. It holds permissions, hooks, environment variables, and the default model.
| Scope | File | Applies to |
|---|---|---|
| Managed | A system file an org deploys | Everyone; cannot be overridden |
| Project | .claude/settings.json |
The team, checked into git |
| Local | .claude/settings.local.json |
You, on this project, gitignored |
| User | ~/.claude/settings.json |
You, across every project |
Command-line flags override the lot for a single session.
Permissions
Permission rules decide what runs without asking. They are tiered: deny is checked first and blocks the call, ask prompts you, and allow approves automatically. Scope a rule to a whole tool or to a pattern within it.
{
"permissions": {
"deny": ["Read(.env)", "Bash(rm -rf *)"],
"ask": ["Bash(git push *)"],
"allow": ["Bash(pytest *)", "Read(./docs/**)"]
}
}
Hooks
A hook ties a command to a point in the session’s lifecycle. The events you reach for most are these.
| Event | Fires |
|---|---|
SessionStart |
When a session begins (load context, set state) |
UserPromptSubmit |
When you submit a prompt, before the agent reads it |
PreToolUse |
Before a tool runs; can block it |
PostToolUse |
After a tool runs (lint, log, inject context) |
Stop |
When the agent finishes a turn |
PreCompact |
Before the context window is compacted |
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": ".claude/hooks/guard.sh" }] }
]
}
}
Subagents
A subagent is a Markdown file in .claude/agents/ for the team, or ~/.claude/agents/ for you. The frontmatter names it, describes when to use it, lists the tools it may use, and can pin a model. The body is its system prompt.
---
name: security-reviewer
description: Review a diff the way a security engineer would.
tools: Read, Grep, Bash
model: sonnet
---
Read the diff. Flag injection, leaked secrets, and unsafe defaults.
Report findings; do not change code.
Skills
A skill is a folder under .claude/skills/<name>/ with a SKILL.md inside. Its frontmatter description tells the agent when the skill applies, and you can invoke it directly with /<name>. The body and any bundled files load only when the skill is used.
Slash commands
A Markdown file in .claude/commands/ becomes a /<name> command, which is handy for a prompt you run often. Skills cover the same ground with bundled files and the option for the agent to invoke them on its own.
MCP servers
External systems connect as tools through .mcp.json at the project root, shared with the team, or through your user configuration for personal servers. Each entry names a server, a transport (a local stdio command, or a remote http or sse URL), and any environment it needs.
{
"mcpServers": {
"playwright": { "command": "npx", "args": ["-y", "@playwright/mcp@latest"] }
}
}
Plan mode and the permission modes
Plan mode is one of several permission modes, which run from prompting before every action to working unattended. Enter it for a single session or set it as the default. When a step goes wrong, the tool can rewind a session’s file changes to an earlier point.
Pin what you rely on
These paths and keys are current as of this writing and will move. Pin the model and the tool version you depend on, write the rules you care about where they will load, and treat the specifics here as a snapshot. The categories from the last chapter are what stays true.