Claude Code Team Guide
Set up Claude Code and the foundation for a development team
Why a shared configuration
Working as a team without a common configuration produces three concrete problems: each developer invents their own conventions, onboarding a new member takes weeks instead of a few hours, and quality audits give inconsistent results from one workstation to another.
A shared configuration via the foundation solves these three problems in a single move:
| Benefit | Without foundation | With foundation |
|---|---|---|
| Code conventions | Each dev decides | .claude/rules/ rules committed |
| Onboarding | 1 to 2 weeks | Less than 2 hours |
| Code quality | Variable | Uniform audit score |
| Workflow | Improvised | Explore → Specify → Plan → TDD → Audit → Commit |
| Secrets | Risk of accidental commit | Blocking gitleaks hook |
1. Shared CLAUDE.md
Project-level CLAUDE.md (committed in git)
The CLAUDE.md file at the root of the project is the entry point for any Claude Code session. It is loaded automatically and applies to all team members.
This file should contain:
- The team's mandatory workflow (Explore → Specify → Plan → TDD → Audit → Commit)
- Project-specific code conventions (naming, structure, stack)
- References to internal documentation
@importsto modular files to avoid overloading the context
Example of a project CLAUDE.md:
# Project my-api
> Node.js/TypeScript REST API with PostgreSQL
@.claude/docs/reference/best-practices.md
@.claude/docs/reference/project-structures.md
## Mandatory Workflow
Explore → Specify → Plan → TDD → Audit → Commit
1. EXPLORE: /work:work-explore before any modification
2. SPECIFY: P1 User Stories (MVP) with Given/When/Then criteria
3. PLAN: Architecture and file list before coding
4. TDD: Tests BEFORE the code, Red-Green-Refactor cycle
5. AUDIT: /qa:qa-loop "score 90" before any commit
6. COMMIT: Conventional Commits, reference issues
## Conventions
- TypeScript strict, no `any`, interfaces for complex objects
- camelCase (vars), PascalCase (classes), kebab-case (files)
- Test coverage 80%+
- Branches: feature/xxx, fix/xxx
## Stack
Node.js 20, TypeScript 5, Express, Prisma, PostgreSQL 16
Personal CLAUDE.md (~/.claude/CLAUDE.md)
Each developer can have their own CLAUDE.md in ~/.claude/ for personal preferences. This file is not committed to git and only applies to their machine.
Examples of personal preferences:
# Personal preferences
- Preferred response language: English
- Preferred model: claude-opus-5-5 for complex tasks
- Response format: concise, no repetition
- My shortcuts: /w = work, /q = qa
What goes where
| Element | Project CLAUDE.md | Personal CLAUDE.md | .claude/rules/ | Memory |
|---|---|---|---|---|
| Team code conventions | Yes | No | Yes (per language) | No |
| Mandatory workflow | Yes | No | workflow.md | No |
| Documentation references | Yes | No | No | No |
| Response preferences | No | Yes | No | Yes |
| Preferred model | No | Yes | No | Yes |
| Architecture decisions | No | No | No | Yes (auto) |
| TypeScript rules | @import link | No | typescript.md | No |
2. Team configuration
.claude/settings.json (committed) vs .claude/settings.local.json (gitignore)
The .claude/settings.json file is committed to git. It contains the team's shared configuration: permissions, hooks, common environment variables.
The .claude/settings.local.json file is in .gitignore. Each developer can override personal settings there without impacting the rest of the team.
| Setting | settings.json (shared) | settings.local.json (personal) |
|---|---|---|
| Permissions (allow/deny) | Yes - team security rules | No |
| Format/lint/tests hooks | Yes | Override possible |
| Common env variables | Yes (INSIDE_CLAUDE_CODE) | Yes (tokens, local paths) |
includeCoAuthoredBy | Yes (false recommended) | No |
| Default model | No | Yes |
Shared hooks
The foundation provides pre-configured hooks in settings.json that apply to the whole team:
PostToolUse: Auto-format (prettier, ruff, gofmt, dart format)
TypeScript type-check after modification
ESLint check after modification
PreToolUse: Tests before git commit (blocking)
Local CI before git push (blocking)
Gitleaks on Write/Edit (blocking if secret detected)
Main branch protection (auto-creates a feature branch)
SessionStart: Verify .env in .gitignore
Detect missing node_modules
To disable a hook on the fly without modifying the shared config:
# Skip pre-commit tests for one Claude Code launch (hooks read Claude Code's
# environment: a prefix on the git command does not reach them)
SKIP_PRE_COMMIT_TESTS=1 claude
# Allow a direct modification on main (exceptional case)
ALLOW_MAIN_EDIT=1 claude
MCP servers: shared .mcp.json
The .mcp.json file is committed to git empty ("mcpServers": {}) — no server is active by default. There is no per-server enabled flag in the .mcp.json format: a server is active iff it is listed in .mcp.json. The curated catalogue ships alongside as .mcp.json.example (a reference file Claude does not load); each developer copies the server blocks they need into .mcp.json and provides the referenced env vars. Project-scoped servers prompt for approval on first use.
// .mcp.json (committed empty — no server active by default)
{
"mcpServers": {}
}
To enable a server, copy its block from .mcp.json.example into .mcp.json (there is no enabled flag — a server is active iff it is listed) and provide the referenced env vars:
// .mcp.json (github enabled)
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
}
}
}
Environment variables: .env.example pattern
# .env.example (committed - contains ONLY placeholders)
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
GITHUB_TOKEN=ghp_your_token_here
SENTRY_AUTH_TOKEN=your_sentry_token
API_SECRET_KEY=your_secret_key_32_characters
# .env (gitignore - contains the real values)
# NEVER committed
When .claude/ is gitignored — scope choices for plugins & skills
Some teams gitignore .claude/ entirely (treating Claude Code config as personal tooling, not part of the codebase). That's a valid choice, but it changes how plugins, skills, and MCP servers should be installed because nothing under .claude/ will follow the project for teammates.
(a) Why a team would gitignore .claude/
| Reason | When it makes sense |
|---|---|
| Treat AI tooling as personal preference | Polyglot teams where members use different AI assistants (Claude, Cursor, Copilot, none) |
| Avoid leaking workflow opinions | Open-source projects where contributors shouldn't be forced into one workflow |
| Faster, cleaner PR diffs | Large monorepos where .claude/ churn would dominate git log |
| Vendored secrets concern | Teams that prefer to keep all .claude/settings.local.json material out of history, full stop |
(b) Consequence: project-scope installs do not propagate
When .claude/ is gitignored, anything you install with project scope vanishes for the next teammate who clones the repo:
claude plugin install foowith--scope project→ writes to.claude/settings.json→ lost on clone.npx skills add bar --to ./.claude/skills/→ writes under.claude/skills/→ lost on clone.- A custom hook script under
scripts/hooks/→ committed (outside.claude/) → kept, but the hook reference in.claude/settings.json→ lost.
The teammate sees a perfectly working repo, runs claude inside it, and silently loses every project-scoped extension you added. No error, no warning. This is the trap US-5 documents.
(c) Recommended scope per use case
Three install scopes are available; pick the one that survives the gitignore boundary:
| Scope | Where it lives | Survives .claude/ gitignore? | When to use |
|---|---|---|---|
user | ~/.claude/ (per-developer) | Yes — outside the repo | Personal preferences (theme, status line, keybindings); skills that all teammates will install anyway via shared onboarding doc |
project | <repo>/.claude/ (per-repo) | No if .claude/ is gitignored | Conventions you're willing to commit; rules that should activate automatically when anyone opens the repo |
local | <repo>/.claude/settings.local.json | No (always gitignored by convention) | Per-developer, per-repo overrides (env-specific paths, secrets) |
If .claude/ is gitignored, the practical advice is:
- Default to
userscope for plugins and skills. Each teammate runs the install command themselves (one-time, documented in the onboarding section of TEAM-GUIDE). - Document the recommended set in the project's README or
docs/guides/onboarding.md— including the exact install commands. The foundation'sprint_recommended_vendor_skills(re-printed at the end of everyupdate) helps here: it lists the curated skills with theirclaude plugin install <id>/git clone --depth 1 <url>pointers. - Track the foundation version via the
.claude/.foundation-versionmarker the foundation now writes (US-1). Even though.claude/is gitignored locally, that file gives you a stable reference if a teammate hits drift between their local foundation version and yours — they can ask you to share which version of claude-base produced the project.
(d) Concrete example per scope
| Scope | Example | Command |
|---|---|---|
user | The whole team uses frontend-design for UI work | claude plugin install frontend-design@claude-plugins-official (each dev runs this once on their machine) |
project (only if .claude/ is committed) | Project-specific rule that auto-activates on *.tsx | cp my-rule.md .claude/rules/ + commit |
local | Personal API key for a vendor MCP server | .claude/settings.local.json with the vendor section, never committed |
The trade-off:
userscope keeps the gitignore clean but adds onboarding friction (each teammate must install the recommended set themselves).projectscope auto-propagates if.claude/is committed but breaks completely if.claude/is gitignored.localscope is always per-developer, per-repo — useful for secrets but unsuitable for shared conventions.
If you want auto-propagation without committing .claude/ wholesale, a partial-gitignore pattern works: gitignore .claude/settings.local.json and .claude/.foundation-version, but commit .claude/rules/, .claude/agents/, and .claude/commands/. The foundation's update flow respects this — it is copy-only by default, and the wipe variant (--all --clean) takes a full backup of every managed dir before touching anything.
What ships in .github/
GitHub Actions
- ci.yml: Tests (bats + node), shellcheck, lint, build
- security.yml: Gitleaks + shellcheck-security workflow
- pr-check.yml: PR format / size / labels validation (uses
amannn/action-semantic-pull-request) - docs.yml: Builds and deploys the Docusaurus site to GitHub Pages
- release.yml: Automated releases with changelog
- dependabot-auto-merge.yml: Auto-merges dependabot PRs that pass CI
Full file-by-file at .github/workflows/. These six are the foundation's own CI and are never
copied into your project.
What --ci installs in your project
claude-base init --ci (also --all, and the presets whose defaults.ci is on) installs three
stack-neutral workflows from templates/github-workflows/. Each looks at what the repository has and
runs only that, so a fresh project's first push is green:
- ci.yml: detects Node (
package.json), Python (pyproject.toml/requirements.txt) and Go (go.mod). Node runs thelint,typecheck,testandbuildscripts that exist, with npm, pnpm or yarn chosen by lockfile; npm'snpm init -yplaceholder test is skipped with a notice. Python installs with pip, uv or poetry by lockfile, then runs ruff and pytest when installed (no tests collected is a notice, not a failure). Go runsgo vetandgo test. No stack found is a notice. - pr-check.yml: Conventional Commits PR title, and no
WIPin the title. - security.yml: Gitleaks over the whole history, from its pinned container image rather than the gitleaks Action, which needs a license key on organization-owned repositories.
There is no release workflow: how a project releases is its own decision. A workflow file the project
already has is never overwritten, except by --ci-existing replace, which deletes the project's
workflows before installing these three. --ci-existing merge adds only the missing ones and says
when release automation or a secret scan is missing.
Every action in these workflows is pinned to a commit SHA, its version in a trailing comment: a tag
is a pointer its owner can move, and the workflows run with your repository's token. So that the
pins do not go stale, the install also adds .github/dependabot.yml, watching GitHub Actions only,
when the project has no Dependabot config. One the project already has (.yml or .yaml) is never
edited; if it does not watch GitHub Actions, the install says so.
Pre-commit Hooks
claude-base init --hooks (or --all) installs two git hooks into .husky/: auto-lint on staged
files (lint-staged, pre-commit) and Conventional Commits validation (commitlint,
commit-msg). Both are guarded on npx and a package.json — without them each one steps
aside rather than refusing the commit, so a project that never set up the Node tooling is not
blocked by a hook it cannot feed. To re-enable manually in an existing install: npx husky install
(assumes husky + lint-staged + commitlint are in your project's devDependencies).
Secret detection is not in these hooks. It ships in .pre-commit-config.yaml (the Python
pre-commit framework, detect-secrets), opt-in via pip install pre-commit && pre-commit install
— a separate tool with its own installation step. On the assistant side, secret-scan.sh covers
the same ground on every Edit/Write.
3. Code conventions
Shared rules (.claude/rules/)
Files in .claude/rules/ are committed to git and activate automatically based on the modified files. This is the most efficient mechanism to share code conventions without putting them in CLAUDE.md.
The foundation includes 34 pre-configured rules. For a team, the most important to commit are:
| Rule | Automatic activation | Team usefulness |
|---|---|---|
workflow.md | Global | Mandatory cycle for everyone |
git.md | Global | Conventional Commits, branches |
typescript.md | **/*.ts, **/*.tsx | Strict mode, no any |
security.md | **/auth/**, **/api/** | OWASP, XSS, injection |
tdd-enforcement.md | All languages | Mandatory proactive TDD |
verification.md | All languages | 4 verification phases |
deploy-safety.md | Dockerfile, .env* | Pre-deploy checklist |
Create a team-specific rule
For conventions not covered by the standard rules, create .claude/rules/team-conventions.md:
---
paths:
- "**/*.ts"
- "**/*.tsx"
- "**/services/**"
---
# My-API Team Conventions
## Service Naming
- One service per business domain: `UserService`, `OrderService`
- Methods as verb + noun: `createUser()`, `findOrderById()`
- NO `Manager`, `Handler`, `Helper` in names
## Error Handling
- Always use `AppError` (never `new Error()` directly)
- Error codes in SCREAMING_SNAKE: `USER_NOT_FOUND`
- Log errors with context: userId, requestId
## Imports
- Absolute imports only (no `../../`)
- Order: node_modules / types / services / utils / local
Recommended effort levels per phase
| Workflow phase | Effort | Justification |
|---|---|---|
| Explore (reading code) | low | No deep reasoning needed |
| Specify (user stories) | medium | Clarifying needs |
| Plan (architecture) | high | Structuring decisions |
| TDD (implementation) | medium | Implementation guided by tests |
| Audit (quality) | high | Detection of subtle problems |
| Complex debug | xhigh | Deepest routinely-useful reasoning (max is the ceiling above it — reserve it) |
Recommended models per usage
| Usage | Model | Why |
|---|---|---|
| Hardest / long-horizon autonomous work (rare) | Fable 5.1 (claude-fable-5-1) | 2.5× Opus 5.5 on input and output, and dearer per cache read too ($0.25 vs $0.20) — deliberate niche use |
| Architecture, design | Opus 5.5 | The default Opus since 2026-09-22, $4/$20 per MTok, 1M context, xhigh effort |
| Feature implementation | Sonnet | Speed/quality balance |
| Exploration, reading | Haiku | Fast for simple operations |
| Security audits | Sonnet or Opus 5.5 | Detection of subtle flaws |
| PR reviews in CI | Haiku | Low cost, high volume |
| Cloud review (large PRs) | /code-review ultra | Parallel agents in cloud (/ultrareview is a deprecated alias) |
Running the foundation's own heavy sessions on Fable 5.1: Opus 5.5 is the right pick for large migrations and deep audits too — this is Anthropic's own guidance, which says to start from Opus 5.5 and reach for Fable 5.1 when evals on Opus 5.5 at higher effort still fall short. Reserve
--model claude-fable-5-1(or/model) for those runs. Two updates since 2026-09-01:claude-fable-5-1is the default Fable model, and afablealias now exists in sub-agent frontmatter. This foundation still never pins an agent to Fable — that is a cost decision, not a limitation. On cost, Fable 5.1 is 2.5× Opus 5.5 on input and output, and its cache reads ($0.25per MTok) now cost more than Opus 5.5's ($0.20); the September argument that Fable read cache at half the Opus price held against Opus 5 and Opus 4.8 only (pricing).
4. Onboarding a new member
Complete checklist for a new developer joining the team:
Step 1: Clone the repo
git clone https://github.com/org/my-project.git
cd my-project
Step 2: Install Claude Code
npm install -g @anthropic-ai/claude-code
Configure the API key:
export ANTHROPIC_API_KEY=sk-ant-your-key
# Or add to ~/.bashrc / ~/.zshrc
Step 3: Initialize the foundation
./bin/claude-base init --simple .
This dispatcher invocation configures the hooks, the permissions, and verifies the .claude/ structure.