← All posts

Guide

Setting up Claude Code for a team: what to commit, and what stays on your laptop

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.

same two scopes — three different outcomes ~/.claude  (personal) .claude/  (committed) settings.json user project repo wins skills/  commands/ personal project laptop wins CLAUDE.md user + project both load Permission rules are a fourth case: they merge across every scope, and deny always beats allow.
The direction of precedence depends on the mechanism. Committed settings override personal ones; a personal skill overrides the project's skill of the same name; CLAUDE.md files never override each other at all.

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.

ThingWhere it livesCommit it?
Project instructionsCLAUDE.md or .claude/CLAUDE.mdYes
Path-scoped instructions.claude/rules/*.mdYes
Permission rules, hooks, env.claude/settings.jsonYes
Shared procedures.claude/skills/<name>/SKILL.mdYes
Shared slash commands.claude/commands/*.mdYes
Shared subagents.claude/agents/*.mdYes
Project MCP servers.mcp.json (repo root)Yes
Your approvals and overrides.claude/settings.local.jsonNo — gitignore it
Your personal project notesCLAUDE.local.mdNo — gitignore it
Your preferences, all projects~/.claude/settings.json, ~/.claude/CLAUDE.md, ~/.claude/rules/Not in this repo
Credentials and API keysYour keychain / login, ~/.claude.jsonNever
Personal MCP servers~/.claude.json (local or user scope)Never
Auto memory~/.claude/projects/<project>/memory/Machine-local; not shareable
With BackgrindBackgrind 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:

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:

MechanismOrder (winner first)Can a developer override the repo?
settings.jsonmanaged → CLI args → local → project → userOnly via their own settings.local.json
Skills and commandsenterprise → personal → projectYes — a same-named skill in ~/.claude/skills/ wins
CLAUDE.mdno override; all files concatenateNo — both are in context together
.claude/rules/user rules load first, project rules take priorityNo
Permission rulesmerge across scopes; deny → ask → allowNever for a deny
MCP serverslocal → project → user → plugin → connectorYes — 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:

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:

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:

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.