Project layout — CLAUDE.md, .claude/, .mcp.json conventions
Where to put project-scoped config so Claude Code, Cursor, and Codex all read the same file. Plus the .mcp.json convention for sharing MCP servers with a team.
Project layout
Recipe 1.1 covered the global CLAUDE.md. This one is about the per-project files. They layer on top of global — Claude Code reads global first, then merges in project-specific overrides.
Five locations matter inside a repo:
| File | Read by | Purpose |
|---|---|---|
| CLAUDE.md | Claude Code | Project-specific context, stack, conventions, commands |
| AGENTS.md (symlink to CLAUDE.md) | Codex, Cursor (with rule), some Cursor configs | Same content, two tools |
| .claude/settings.local.json | Claude Code | Per-project allow-list (Recipe 3.2) |
| .claude/agents/<name>.md | Claude Code | Project-specific subagents (override global ones with same name) |
| .mcp.json | Claude Code, Cursor, Codex (with adapter) | MCP servers shared with the team — committed to git |
You do not need all five. Most repos do well with CLAUDE.md + AGENTS.md (symlink). Add the others when you actually need them.
Step 1: Bootstrap a fresh repo
From the repo root:
mkdir -p .claude
touch CLAUDE.md
ln -sf CLAUDE.md AGENTS.md
That is the minimum. CLAUDE.md is read by Claude Code, AGENTS.md is read by Codex (and by Cursor if you wire it up — see Recipe 3.5). Both files are now the same content via symlink. Edit one, both update.
Step 2: Write the CLAUDE.md as a router, not a manual
The pattern that ages well: short and skimmable. The internal CLAUDE.md for a real project at StudioMeyer is around 200 lines and acts like a router — top-level context plus pointers into docs/claude/*.md for detail. Files past 500 lines get summarized away by the model.
# <project name>
## What this is
One paragraph. What problem does this codebase solve, who uses it, what state is it in.
## Stack
- Language + version
- Framework
- Database
- Deploy target (and how)
## Commands
- `npm run dev` — start dev server
- `npm test` — run tests (vitest)
- `npm run build` — production build
- `npm run deploy` — deploy script (only if it exists)
## Conventions
- Test framework + how tests are organized
- Code style (TypeScript strict, no `any`, no comments unless WHY-explaining)
- Branch / commit / PR pattern
## Standing rules
- Always X before Y (e.g. "always run `prisma generate` after editing schema.prisma")
- Never X without Y (e.g. "never push to main without tests passing")
## Layout
- `src/` — source
- `tests/` — vitest specs
- `docs/` — runbooks
- `scripts/` — one-off scripts
## Detail docs (read on demand)
- `docs/claude/deploy.md` — deploy runbook
- `docs/claude/db-schema.md` — Prisma schema notes
- `docs/claude/incidents.md` — past outages and root causes
Keep CLAUDE.md as the index. Everything that needs more than three lines goes into a dedicated file under docs/claude/. The model can navigate to detail when it needs it instead of carrying everything in working memory.
Step 3: .mcp.json for team-shared MCP servers
If your project depends on specific MCP servers — a project-specific Postgres connection, an internal API client, a memory server scoped to this codebase — declare them in a .mcp.json file at the repo root. Claude Code picks it up automatically and offers your teammates the same servers when they open the repo.
{
"mcpServers": {
"internal-api": {
"type": "stdio",
"command": "node",
"args": ["./mcp-servers/internal-api/dist/server.js"]
},
"project-postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost:5432/myapp"]
}
}
}
.mcp.json is committed to the repo. Sensitive servers (anything with API keys) belong in ~/.claude.json (user scope) instead, or use environment variables in the .mcp.json so each developer sets their own keys locally.
The project-scope MCP config beats the user-scope MCP config when both define the same server name.
Step 4: Verify
Run aiguide_validate_step. The claude_md_exists validator looks for CLAUDE.md or AGENTS.md in the current working directory (or in ~/.claude/ / ~/.codex/ as a global fallback). Either is enough — symlinks count.
ls -la ./CLAUDE.md ./AGENTS.md ~/.claude/CLAUDE.md ~/.codex/AGENTS.md 2>/dev/null || true
Step 5: Test the merge
Open Claude Code from the repo root. Ask: "What does this project do?"
The first response should reference content from your CLAUDE.md (the stack, the commands, the conventions). If it does not, two likely causes:
- Claude is not running in this directory. Check
pwdinside the session. - The file is parseable but lives in
.claude/CLAUDE.mdinstead of<repo>/CLAUDE.md. Move it to the root.
Once it works once, keep CLAUDE.md alive. The most common decay path: someone changes the deploy command and nobody updates the file. Two months later every new session reads stale instructions and runs the wrong thing. Stale CLAUDE.md is worse than no CLAUDE.md.