Claude Code Workflow Files: AGENTS.md, CLAUDE.md, Skills, and Repo Maps
Table of content
by Ray Svitla
most “Claude Code is amazing” posts assume one config file. real repos end up with six.
CLAUDE.md at the root. AGENTS.md from someone’s last cursor experiment. a .claude/rules/ directory the frontend lead added. a .claude/skills/ folder nobody can list from memory. a .claude/settings.json with hooks. a .mcp.json pointing at servers that may not still exist. plus an architecture.md the agent reads when it feels like it.
each surface loads at a different moment, with a different scope, against a different cost. confuse them and the agent ignores instructions you “wrote.” or worse: it follows instructions you forgot you wrote, on a file you forgot you committed.
this is the router. one table for where each thing belongs, one repo layout that works, one cleanup pass for when the surfaces drift.
it assumes you’ve already picked Claude Code. for a tool-by-tool filename comparison, see AGENTS.md vs CLAUDE.md vs INSTRUCTIONS.md . for what to actually put inside AGENTS.md once you have one, AGENTS.md: how to write instructions for AI coding agents . for the pre-session walkthrough that uses these files, the Claude Code session preflight .
if you only do one thing
write one CLAUDE.md at the project root, keep it under 200 lines, and treat it as a router — not a database. point at docs/architecture.md, package.json, AGENTS.md, the test command. don’t paste them. that single file does most of the work; everything below is how to handle the rest without losing your mind.
solo operator default
if you’re the only person on the repo: root CLAUDE.md + .claude/settings.local.json + .claude/skills/<name>/ only when you’ve repeated yourself twice. skip AGENTS.md, skip .claude/rules/, skip nested CLAUDE.md until the repo grows past one head. half the surfaces below exist for teams. you don’t need them yet — but knowing where they go means you won’t paint yourself into a corner the day a second contributor lands.
the surface map
| surface | when it loads | scope | what to put here |
|---|---|---|---|
CLAUDE.md (project root) | every session, full file | project | build/test commands, conventions, hard rules |
CLAUDE.local.md | every session, gitignored | personal-in-repo | local URLs, your test creds path, scratch context |
~/.claude/CLAUDE.md | every session of every project | you, globally | personal voice, default tone, universal preferences |
nested <subdir>/CLAUDE.md | on demand — when Claude reads files in that subdir | subdirectory | module rules that override the root |
.claude/rules/*.md (no paths) | every session, full file | project | topic-organized rules: testing, security, style |
.claude/rules/*.md (with paths) | only when matching files are touched | subset of project | API-only or frontend-only rules |
.claude/skills/<name>/SKILL.md | description always; body on invoke or path match | project | repeatable procedures, multi-step playbooks, slash commands |
~/.claude/skills/<name>/SKILL.md | same as above | you, globally | personal procedures you reuse across repos |
.claude/settings.json (+ .local.json) | every session — machine-enforced, not LLM context | project (+ personal) | permissions, hooks, env, MCP config |
.mcp.json | session start — servers run external | project | shared MCP servers for the team |
reference docs (docs/architecture.md, ADRs) | on demand — only when CLAUDE.md tells the agent to read them | varies | deep architecture, ADRs, generated maps |
three loading patterns to memorize:
- always-on context — root
CLAUDE.md,CLAUDE.local.md(appended after, last word wins),.claude/rules/*.mdwithoutpaths, user-levelCLAUDE.md. burns tokens every turn. should be small. - on-demand or path-scoped — nested
<subdir>/CLAUDE.md(loads when Claude reads files there, not at session start), rules withpaths, skill bodies, reference docs. cost is zero until needed. skill descriptions are always in context; only bodies wait. - machine-enforced —
settings.jsonpermissions, hooks. the model doesn’t see these as instructions; the harness enforces them regardless of what the model decides.
confuse these and you’ll write a “rule” the model never reads, or stuff the architecture into something that loads on every turn.
the AGENTS.md correction
Claude Code reads CLAUDE.md, not AGENTS.md. Anthropic’s documentation is explicit on this. if your repo uses AGENTS.md for codex or another agent, bridge the two with an import:
# CLAUDE.md
@AGENTS.md
## Claude Code only
- use plan mode for changes under `src/billing/`
- prefer `pnpm` for this repo
@path/to/file expands at session start. relative paths resolve against the file containing the import. the imported content lands in context as if pasted in.
this is better than a symlink: you can layer Claude-specific instructions below the AGENTS.md import without polluting the shared file. if you don’t run other agents, you don’t need AGENTS.md. just write CLAUDE.md.
a repo layout that doesn’t drift
your-repo/
├── CLAUDE.md # 1. project entrypoint, < 200 lines
├── CLAUDE.local.md # 2. personal, gitignored
├── AGENTS.md # 3. only if you also run codex/cursor
├── .claude/
│ ├── settings.json # 4. team-shared permissions, hooks, MCP
│ ├── settings.local.json # 5. personal overrides, gitignored
│ ├── rules/
│ │ ├── testing.md # 6. always-on rules per topic
│ │ ├── security.md
│ │ └── api.md # 7. with `paths: src/api/**`, scoped
│ └── skills/
│ ├── commit/SKILL.md # 8. /commit
│ └── deep-research/SKILL.md # 9. runs in subagent
├── .mcp.json # 10. shared MCP servers
├── docs/
│ ├── architecture.md # 11. read on demand from CLAUDE.md
│ └── adr/ # 12. ADRs, same pattern
└── packages/
└── frontend/
└── CLAUDE.md # 13. nested, frontend-only overrides
if any cell of the surface map surprises you, your current instructions are probably routed to the wrong file.
where does the next thing go?
a five-question router for whatever instruction you’re about to add.
must the model see it on every turn? yes →
CLAUDE.mdor.claude/rules/*.mdwithoutpaths. no → keep going.does it only apply to a specific area of the repo? yes → nested
<subdir>/CLAUDE.md, or.claude/rules/*.mdwithpaths. no → keep going.is it a multi-step procedure or a slash command? yes →
.claude/skills/<name>/SKILL.md. adddisable-model-invocation: trueif it has side effects (deploy, commit, send) so the model can’t trigger it on its own. no → keep going.must the harness enforce it regardless of what the model decides? yes →
.claude/settings.json(permissions, hooks). the model can want to runrm -rf; the harness still says no. no → keep going.is it big, deep, and rarely needed? yes →
docs/architecture.mdor similar, referenced from CLAUDE.md with one line. read on demand. no → it probably isn’t agent instruction at all. it’s a comment, a code change, or a README update.
if every answer is “kind of,” you’re either writing a rule too vague to follow, or a rule that should be code.
three “put this here” examples
walk-throughs for the three most common adds.
1. test command → root CLAUDE.md.
## commands
- test: `pnpm test`
- typecheck: `pnpm typecheck`
- build: `pnpm build`
one line per command, one source of truth, the agent quotes it back when it runs. if the command changes, you update one file and the rule updates everywhere it was referenced.
2. dangerous command denial → .claude/settings.json.
{
"permissions": {
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force *)",
"Bash(git reset --hard *)"
]
}
}
the harness blocks the call regardless of what the model intends. this beats “always remember to ask first” written in CLAUDE.md, because a CLAUDE.md rule depends on the model reading it, weighting it, and choosing to obey. the deny list doesn’t.
3. multi-step publish flow → .claude/skills/publish/SKILL.md.
---
name: publish
description: build, sign, and push the static site to the production bucket. invoke only on /publish.
disable-model-invocation: true
---
1. run `pnpm build`.
2. confirm `dist/` size hasn't dropped >20% vs last release.
3. run `./scripts/sign.sh`.
4. run `./scripts/upload.sh`.
5. tag the commit `release-<date>`.
the description loads on every turn so /publish autocompletes. the body loads only when you trigger the slash command. the frontmatter flag means the model can’t auto-fire it even if a user prompt sounds publish-shaped.
three different surfaces, three different cost profiles, three different enforcement levels. pick by what the instruction actually needs.
skills vs rules vs MCP
three surfaces people confuse most.
rules (.claude/rules/) | skills (.claude/skills/) | MCP servers | |
|---|---|---|---|
| primary job | shape behavior across many tasks | execute a specific procedure | give the agent new tools |
| invocation | always-loaded or path-scoped | model-invoked by description match, /slash-command, or paths | tool calls during reasoning |
| token cost | full body in context (always or on path match) | description in context; body only on invoke | server replies count, descriptions count |
| best for | “always validate API input,” “use 2-space indent” | “/commit,” “/deploy,” “/research X” | database access, web search, browser automation |
| worst for | step-by-step procedures (overflows the always-on budget) | universal style rules (description-matching is fuzzy) | static knowledge a markdown file would handle |
custom commands have collapsed into skills. a file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy. skills are the recommended shape now because they support invocation control via frontmatter and supporting files. existing .claude/commands/ files still work.
for MCP picks, see best MCP servers for Claude Code . for discovery and the curation layer, Claude Hub . for the broader ecosystem, best Claude Code plugins .
drift prevention
three rules.
1. one source of truth per concept. if pnpm test is the test command, it appears once — in CLAUDE.md, or .claude/rules/testing.md, or package.json referenced by @package.json import. not in three places. when it changes, you update one file.
2. import, don’t duplicate. imports keep AGENTS.md, README, and CLAUDE.md from contradicting each other. write the canonical content once, import it where needed.
3. the agent updates the rules, with a paper trail. when Claude makes a mistake you’ve corrected before, ask it to add a rule. when a rule no longer applies, ask it to remove it. commit those changes like code — they belong in PR review, not in machine-local notes.
stale instruction cleanup
run this monthly. quarterly minimum.
- read every
CLAUDE.md,.claude/rules/*.md, andSKILL.mdlike a stranger would. - grep for command names, package names, version numbers. confirm each still matches reality. agents repeat outdated patterns from training data; rules with stale versions actively make it worse.
- for each rule, ask: “have I corrected the agent on the opposite of this in the last month?” if yes, the rule isn’t working — rewrite more specifically, or move to a hook.
- for each skill, ask: “have I or the agent invoked this in the last month?” if no, archive it. dead skills clutter the description budget.
- check
.claude/settings.json. deleteallowentries for tools you no longer use; tightendenyrules to match the current threat surface. - check
.mcp.json. servers go offline, packages get yanked, auth expires. quietly broken servers waste tokens describing tools that don’t work. - check nested
CLAUDE.mdfiles in subdirectories you’ve refactored. the file may now describe a layout that no longer exists.
an instruction file that hasn’t been pruned in six months is a liability, not an asset. the agent follows what’s there, including the wrong things.
verification checklist
after editing any workflow file, before you trust the result. for the wider pre-session walkthrough, see the Claude Code session preflight .
- run
/memoryin a session. confirm the file you edited and any@-importsshow up. if not, the path doesn’t match Claude’s discovery rules. - for path-scoped rules and skills, open a file matching the
pathsglob and confirm activation. - for skills, type
/and confirm the description appears intact (not truncated). for skills withdisable-model-invocation, confirm the model doesn’t auto-fire them on prompts where the description would match. - for hooks in
settings.json, run a triggering event and confirm the hook fires. hooks fail silently when the path or shell is wrong. - for MCP servers, confirm the server appears in the session’s tool list. config can be right while the server is down.
- try to violate a rule on purpose. if the agent complies with your violation, the rule is too vague — rewrite as a hard constraint or move to a hook.
if any item fails, the agent is operating on different instructions than you think. that’s the failure mode behind most “the agent ignored my CLAUDE.md” complaints.
common failure modes
stuffing the architecture into CLAUDE.md. files past ~200 lines burn context every turn and dilute the rules that matter. move detailed reference into docs/architecture.md, point at it with one line, let Claude read it on demand. for path-specific guidance, .claude/rules/*.md with paths.
writing rules a hook should enforce. “never commit secrets” is not a CLAUDE.md rule — it’s a pre-commit hook that fails the commit. “always run tests before pushing” is not a CLAUDE.md rule — it’s a settings hook that intercepts the bash tool when it sees git push. CLAUDE.md guides; hooks enforce. don’t ask the model to police itself when the harness can do it. for the broader pattern, see agent failure modes
.
skill descriptions that don’t match user phrasing. the model loads skills by matching descriptions against what the user typed. if your /research skill is described as “deep investigation of source-backed claims,” and the prompt is “look this up,” the description doesn’t match, the skill never loads, and you don’t realize it. front-load the use case, include the natural phrases users actually say, verify with /-menu autocomplete. for activation mechanics, see the skills system in Claude Code
.
the operator point
the model is the part you rent. the workflow files are the part you own.
every surface above is a place to express something durable about your codebase to whatever agent runs against it next week, after the next CLI version, after the next model release. the dist-tag changes weekly. the model behind it changes too. the workflow files don’t.
that’s the leverage. write them like infrastructure: small files, single sources of truth, machine-enforced where it matters, audit-friendly when it doesn’t. when you’re done, you should be able to onboard a new contributor — human or agent — by handing them the repo and walking away.
→ the Claude Code session preflight — the pre-session walkthrough that consumes these files → AGENTS.md vs CLAUDE.md vs INSTRUCTIONS.md — filename comparison across coding agents → AGENTS.md: how to write instructions for AI coding agents — what belongs inside AGENTS.md once you have one → why your CLAUDE.md sucks — anti-patterns to avoid in instruction files → best MCP servers for Claude Code — server picks worth installing → Claude Hub — discovery layer for skills and curated lists → the skills system in Claude Code — how skills load, activate, and compose