Guide
Setting up Claude Code for a team: what to commit, and what stays on your laptop
Almost everything written about Claude Code assumes one developer on one laptop. Add a second engineer and a new question appears that no amount of personal tuning answers: what do you commit, so that everyone's agent behaves the same way in your repo — and what has to stay personal, because it's a credential, a machine path, or just taste?
The mechanics are all there, but they're spread across five documentation pages, and the one thing a team
guide has to get right — precedence — is not the same direction for every mechanism. For
settings.json, the repo beats your home directory. For skills, your home directory beats the
repo. For CLAUDE.md, nothing beats anything, because none of it overrides at all. Get that
backwards in a team setup and you'll ship a config that quietly does the opposite of what you documented.
Everything below is verified against Claude Code v2.1.221 and the docs at
code.claude.com as of August 2, 2026.
The split: repo versus home directory
The rule of thumb is simple even if the precedence isn't. Anything that describes the repository
goes in the repository. Anything that describes you — your credentials, your paths, your
keybindings, your taste in models — stays in ~/.claude. If a file would break on a teammate's
machine, or would leak something, it isn't a project file.
| Thing | Where it lives | Commit it? |
|---|---|---|
| Project instructions | CLAUDE.md or .claude/CLAUDE.md | Yes |
| Path-scoped instructions | .claude/rules/*.md | Yes |
| Permission rules, hooks, env | .claude/settings.json | Yes |
| Shared procedures | .claude/skills/<name>/SKILL.md | Yes |
| Shared slash commands | .claude/commands/*.md | Yes |
| Shared subagents | .claude/agents/*.md | Yes |
| Project MCP servers | .mcp.json (repo root) | Yes |
| Your approvals and overrides | .claude/settings.local.json | No — gitignore it |
| Your personal project notes | CLAUDE.local.md | No — gitignore it |
| Your preferences, all projects | ~/.claude/settings.json, ~/.claude/CLAUDE.md, ~/.claude/rules/ | Not in this repo |
| Credentials and API keys | Your keychain / login, ~/.claude.json | Never |
| Personal MCP servers | ~/.claude.json (local or user scope) | Never |
| Auto memory | ~/.claude/projects/<project>/memory/ | Machine-local; not shareable |
| With Backgrind | Backgrind wraps the CLI your team already runs, so all of the above is exactly the config your agent reads — the overlay adds no second config surface to keep in sync. | |
One thing on that list surprises people: auto memory is not shareable. The notes Claude
writes for itself live under ~/.claude/projects/<project>/memory/, keyed off the git
repository, and they are machine-local — worktrees and subdirectories of the same repo share one directory,
but nothing crosses machines. Useful knowledge that surfaces there is a signal, not a deliverable: when a
teammate's agent keeps rediscovering the same build quirk, that's a line for CLAUDE.md.
Precedence, mechanism by mechanism
This is the part worth being exact about, because a wrong precedence claim in a team guide gets copied into other people's repos. Four mechanisms, four different behaviours.
1. Settings files: highest scope wins
When the same setting appears in more than one scope, Claude Code applies them in this priority order, highest first:
- Managed — the enterprise policy file, which no other scope can override (bar a handful of documented exceptions).
- Command line arguments — temporary session overrides.
- Local —
.claude/settings.local.json, which overrides project and user settings. - Project —
.claude/settings.json, which overrides user settings. - User —
~/.claude/settings.json, which applies when nothing else specifies the setting.
For a team, the load-bearing line is the middle one: the committed project file overrides each
developer's personal file. That's what makes .claude/settings.json a policy surface
rather than a suggestion. But note the line above it — a developer's own
.claude/settings.local.json overrides the project file, which is exactly why that file has to
be gitignored and treated as personal scratch space, not as a second place to put team rules.
Managed settings live at /Library/Application Support/ClaudeCode/managed-settings.json on
macOS, /etc/claude-code/managed-settings.json on Linux and WSL, and
C:\Program Files\ClaudeCode\managed-settings.json on Windows. If you're an org that needs a
rule no repository and no engineer can turn off, that's the only layer that gives it to you. The older
Windows path under C:\ProgramData\ is no longer supported as of v2.1.75.
2. Skills and commands: the direction reverses
Here is the trap. Skills do not follow settings precedence. Straight from the docs: when skills share
the same name across levels, enterprise overrides personal, and personal overrides project. A skill at
any of those levels also overrides a bundled skill of the same name — a code-review skill in
your project's .claude/skills/ replaces the built-in /code-review. Custom commands
in .claude/commands/ work the same way, and if a skill and a command share a name, the skill wins.
So the two mechanisms a team most wants to standardise point in opposite directions:
| Mechanism | Order (winner first) | Can a developer override the repo? |
|---|---|---|
settings.json | managed → CLI args → local → project → user | Only via their own settings.local.json |
| Skills and commands | enterprise → personal → project | Yes — a same-named skill in ~/.claude/skills/ wins |
CLAUDE.md | no override; all files concatenate | No — both are in context together |
.claude/rules/ | user rules load first, project rules take priority | No |
| Permission rules | merge across scopes; deny → ask → allow | Never for a deny |
| MCP servers | local → project → user → plugin → connector | Yes — a local-scope server of the same name wins |
Read the second row and the fourth row together and the practical consequence is clear:
a project skill is a default, not a mandate. If your team's /deploy must be
the one in the repo, you can't rely on the skill layer to enforce it, because any engineer with a personal
~/.claude/skills/deploy/ silently shadows it — and nothing in the session tells them that
happened. Enforce with a hook or a deny rule; use skills to make the right thing convenient.
Two related details worth knowing before you shape a monorepo around skills. Project skills load from
.claude/skills/ in your starting directory and every parent up to the repository root, so
starting Claude in a subdirectory still picks up root skills. And skills in nested directories
below your starting point don't conflict — a deploy skill in
apps/web/.claude/skills/ appears as /apps/web:deploy alongside the root one, and
both stay available.
3. CLAUDE.md: nothing overrides anything
CLAUDE.md is not a settings file and doesn't behave like one. Every discovered file is
concatenated into context rather than overriding the others. The scopes load from broadest
to most specific — managed policy, then user (~/.claude/CLAUDE.md), then project
(./CLAUDE.md or ./.claude/CLAUDE.md), then local
(./CLAUDE.local.md) — so a project instruction lands in context after a user one. Across a
directory tree the ordering runs from the filesystem root down to your working directory, and within each
directory CLAUDE.local.md is appended after CLAUDE.md.
Because there is no override, a contradiction between your CLAUDE.md and a teammate's personal one
doesn't resolve — it just sits there, and Claude may pick either arbitrarily. That's a real team
failure mode: an engineer with "always use npm" in ~/.claude/CLAUDE.md working in a repo whose
CLAUDE.md says "always use pnpm" gets a coin flip, not an error. The fix is a project rule
stated specifically enough that it reads as the more concrete instruction, and — if it genuinely must hold
— a hook, which runs regardless of what the model decides. Our
CLAUDE.md vs AGENTS.md guide covers what belongs in the file
itself; the short version is under 200 lines, command-first, and split into
.claude/rules/ when it grows.
Note that .claude/rules/ — the path-scoped sibling of CLAUDE.md — goes the other way again:
user-level rules in ~/.claude/rules/ load before project rules, which the docs
describe as giving project rules higher priority. Same directory, adjacent mechanisms, opposite defaults.
4. Permission rules: deny wins from any scope
Permission rules are the one mechanism that doesn't override at all — they merge across scopes, and then evaluate in a fixed order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity does not change the order.
That has two consequences a team should internalise. First, a deny at any level cannot be overridden by
an allow at any other level — a project deny blocks a user allow, and a user deny blocks a project
allow. Second, a broad deny can't carry allowlist exceptions: Bash(aws *) blocks
aws s3 ls even if you also wrote Bash(aws s3 ls) into allow. Write
denies narrowly and deliberately.
Permission rules as team policy
Most teams arrive at Claude Code with permissions as a per-developer habit: everyone tabs through their own
prompts, everyone's allowlist drifts, and the one engineer who got tired of prompting is running with a
much wider blast radius than anyone realises. Committing .claude/settings.json converts that
into a policy you can review, diff, and reason about.
{
"permissions": {
"allow": [
"Bash(pnpm run lint)",
"Bash(pnpm run test *)",
"Bash(git status)",
"Bash(git diff *)"
],
"ask": [
"Bash(git push *)",
"Bash(pnpm publish *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(curl *)"
]
}
} Three things make this work as team policy rather than decoration:
- The deny list is the actual guarantee. Allows are conveniences a developer's local file can add to; denies hold from any scope, including managed settings, and can't be walked back.
- The ask list is where the interesting decisions live.
git push,publish, migrations — operations with no undo. See pre-approval policies for how to shape that list so the agent runs long stretches unattended and only stops for the moments that matter. - Allow rules from a project file need workspace trust.
permissions.allowandpermissions.additionalDirectoriesin a project's.claude/settings.jsongrant capability, so Claude Code applies them only after the developer accepts the workspace trust dialog for that folder — which lists exactly what the repo wants to grant.denyandaskaren't gated, because they only restrict. A cloned repo cannot silently widen anyone's permissions.
One monorepo gotcha while you're here: hooks and other .claude/settings.json keys load from the
current working directory's .claude/ folder with no parent-directory fallback, whereas
.claude/settings.local.json loads from the git repository root even when you start
Claude Code in a subdirectory. Start a session in packages/api/ and your root project settings
won't be picked up unless that package has its own.
.claude/settings.local.json — and why you should gitignore it yourself
.claude/settings.local.json is the personal layer inside a shared repo. It's where Claude Code
writes a rule when you pick "Yes, don't ask again" for a Bash command — saved at the git repository root,
resolved through worktrees to the main checkout, so the approval applies across your worktrees and
subdirectory sessions. It's also where the /skills menu writes
skillOverrides when you turn a noisy project skill off.
All of that is personal by construction, and it sits above the project file in precedence. It must not be
committed. Claude Code does try to help: when it saves a setting to this file in a repository that doesn't
already ignore it, it adds **/.claude/settings.local.json to your global git
excludes file — core.excludesFile from your global git config, otherwise
$XDG_CONFIG_HOME/git/ignore or ~/.config/git/ignore.
Read that carefully, because it's the reason to act. The protection is global to that machine and only appears once Claude Code has written there. A new hire who clones the repo, opens the file by hand, and commits it is not covered. So put the rule in the repository where it protects everyone from the first checkout:
# .gitignore
.claude/settings.local.json
CLAUDE.local.md
And commit a .claude/settings.json next to it. A repo with only a local file is a repo where
the team's rules live on one laptop.
Hooks and MCP servers in the repo
Hooks are the mechanism that turns "we agreed to do X" into "X happens." They live in the
hooks block of a settings file, and a hook committed to .claude/settings.json
applies to everyone — format on write, block edits to generated files, ping a channel when a run finishes.
Unlike CLAUDE.md, they aren't advice the model can weigh: they execute. Our
hooks guide covers the events and the JSON contract.
Two behaviours matter for a team specifically. Hooks are captured at Claude Code startup, and external modifications don't take effect until you restart — deliberately, so that a compromised process can't inject hooks mid-session. Practically, that means a hook you merge lands on a teammate's next session, not their current one, and "it works on my machine" often just means "I haven't restarted since the pull."
MCP servers split cleanly along the same repo/personal line. Project scope writes to .mcp.json
at the repository root and is meant to be committed; local and user scope both live in
~/.claude.json and never leave your machine. The commit-safe part of a project server config is
made possible by environment variable expansion — ${VAR} and
${VAR:-default} work
in command, args, env, url, and headers:
{
"mcpServers": {
"sentry": {
"type": "http",
"url": "https://mcp.sentry.dev/mcp",
"headers": { "Authorization": "Bearer ${SENTRY_TOKEN}" }
},
"db": {
"command": "npx",
"args": ["-y", "@org/db-mcp", "--root", "${CLAUDE_PROJECT_DIR:-.}"]
}
}
}
That's the pattern: the shape of the integration is committed, the token and the machine path stay
personal. Claude Code prompts each developer for approval before using a project-scoped server — and a
cloned repository can't approve its own servers, since enableAllProjectMcpServers committed to
the project's settings is ignored in a folder you haven't trusted. If you need to re-run those choices, use
claude mcp reset-project-choices. For picking servers in the first place, see our roundup of
MCP servers for Claude Code.
Reviewing a teammate's skill or hook in a PR
This is the part most teams get wrong, and the reason is a category error: a PR that adds
.claude/settings.json looks like a config diff, so it gets a config-diff review. It isn't one.
A hook is a shell command that will run on every engineer's machine, with their credentials,
outside the permission prompt. Anthropic's own documentation is blunt about it: hooks run
arbitrary code, can read files and make network requests, and hooks defined in a project's
.claude/settings.json run when you open that project — before you do, read the hooks to
understand what they do.
Compare the blast radius. Ordinary application code has to be deployed, and it runs in your infrastructure
under your observability. A merged hook is live on ten laptops on their next session, with each engineer's
shell, SSH agent, cloud credentials, and repository checkout. There is no staging environment for
.claude/.
So give these files a different review standard. A workable checklist:
- Read every command end to end. Including whatever the hook shells out to. A one-line hook that calls
./scripts/precommit.shmeans the script is part of the diff, whether or not git shows it that way. - Check for network egress. A hook that POSTs tool inputs somewhere is exfiltration with a friendly name. HTTP hooks should be constrained with
allowedHttpHookUrls, andhttpHookAllowedEnvVarscontrols which environment variables they can see. - Reject inline secrets, and reject
sudo. Hooks should run with minimal permissions and pull credentials from the environment, not carry them. - Watch for shell injection. Hooks receive untrusted JSON from the session. Prefer the exec form (
args), which doesn't invoke a shell, over interpolating a path into a command string. - Read
allowed-toolsin a skill's frontmatter as a permission grant. For skills checked into.claude/skills/,allowed-toolstakes effect once the workspace trust dialog is accepted — the same gate as permission rules. A skill can grant itself broad tool access; review it before trusting the repo. - Diff the whole
permissionsblock, not the added line. A new entry inallowis a widening. Ask what it makes possible, not whether it's convenient.
A good habit is to require a second reviewer on any PR touching .claude/ or
.mcp.json — a CODEOWNERS entry does it in one line. It costs nothing on a repo where those
files change monthly, and it's the difference between a reviewed supply chain and an unreviewed one. The
same reasoning applies to skills you install from outside your team; we went through it in detail in
the agent skills security model.
Two tools help during review. /hooks opens a read-only browser of every configured hook,
showing which settings file each one came from and the full command — useful for checking what a repo
actually installed, rather than what its PR claimed. And /context lists the memory files that
really loaded this session, which is how you confirm a committed CLAUDE.md is reaching people
at all.
Onboarding a new hire on day one
If the repo carries its own config, a new engineer's agent should be useful before they've made a single decision. What that takes:
- Commit a CLAUDE.md that answers the day-one questions. Install, build, test, lint — the exact invocations. The directories not to touch. The two non-obvious setup steps everyone gets wrong. This is the same list you'd give a human on their first morning, which is a useful test of whether a line belongs.
- Commit the permission rules. Nobody's first week should be spent building a personal allowlist by tabbing through prompts. Ship one that already covers your test and lint commands, and denies your secrets paths.
- Commit one or two skills that encode a real procedure. "How we cut a release", "how we add a migration" — the things currently living in a senior engineer's head. A skill's body only loads when it's used, so a long runbook costs nothing until it's needed.
- Commit
.mcp.jsonwith the tokens templated out, and document which environment variables to set. The new hire approves the servers on first run; nothing about the integration has to be rediscovered. - Tell them what to expect at the trust dialog. It's the first thing they'll see, it lists the allow rules and additional directories the repo wants to grant, and "just accept it" is bad advice to train into someone. Point at the PR where those rules were reviewed.
- Say out loud that
~/.claudeis theirs. Personal model choice, theme, keybindings, personal skills — none of it belongs in the repo, and the reversed skill precedence means their personal skills will win over the project's anyway. Better they know that than discover it.
Then have them run /context once. If the project CLAUDE.md shows under
Memory files, the setup landed. If it doesn't, they're working with a differently
configured agent than everyone else, and you want to know that on day one rather than in a code review
three weeks later.
Frequently asked questions
What should a team commit to the repo for Claude Code?
Commit CLAUDE.md (or .claude/CLAUDE.md), .claude/settings.json with your permission rules and hooks, .claude/skills/ for shared procedures, .claude/commands/ for shared slash commands, .claude/rules/ for path-scoped instructions, and .mcp.json for project MCP servers. Keep credentials, machine-specific paths, personal model and theme preferences, and anything Claude Code wrote into .claude/settings.local.json out of version control.
Does the project settings file override my personal one?
For settings.json, yes. Claude Code applies settings in the order managed, command line arguments, local (.claude/settings.local.json), project (.claude/settings.json), then user (~/.claude/settings.json), highest first — so a committed project setting overrides your personal one, and your own settings.local.json overrides both. Skills go the other way: when a skill name exists at more than one level, enterprise overrides personal and personal overrides project.
Should .claude/settings.local.json be gitignored?
Yes. It is your personal per-repository file — Claude Code writes "Yes, don't ask again" approvals into it at the git repository root. When it saves there, it adds **/.claude/settings.local.json to your global git excludes file, not to the repository's .gitignore, so that protection only exists on machines where Claude Code has already written. Commit the ignore rule yourself so every clone is covered from the first checkout.
Can a personal permission rule loosen a rule the team committed?
No. Permission rules merge across scopes and are evaluated deny, then ask, then allow, with the first match winning and specificity making no difference. A deny at any level cannot be overridden by an allow at any other level — a project deny beats a user allow, and a user deny beats a project allow.
Why does reviewing a teammate's hook matter more than reviewing normal code?
Because a hook is a shell command that runs on every engineer's machine, with their credentials, outside the sandbox and outside the permission prompt. Anthropic's own documentation says hooks defined in a project's .claude/settings.json run when you open that project, and to read them before you do. Normal application code has to be deployed to do damage; a merged hook is live for the whole team on their next session.
Where Backgrind fits
Committed config gets everyone's agent behaving the same way. It doesn't get everyone's agent
watched the same way — and on a team that's the next thing to break, because the moment a
PreToolUse ask fires is the moment a teammate's long-running task is stalled in a terminal tab
nobody is looking at. Backgrind is a bring-your-own-CLI overlay: it runs the Claude Code
you already have, with the same .claude/ config you just committed, in an always-on-top window
that pings you when a decision is waiting and stays quiet otherwise. Nothing to add to the repo, no second
config surface, and the agent content never touches our server.
If your team is running more than one agent at a time — one per worktree, one per service — that's exactly the case the overlay was built for. See it in the live demo, or start with running Claude Code in the background.