Exercise 2 — Configuring Claude Code for Team Development D3 · D2 ← Back to Study Guide
⚙️ Exercise 2 of 4

Configuring Claude Code for Team Development

A practical configuration exercise — not coding a feature but building the environment that makes Claude Code behave correctly for every developer on the team. Covers the 3-level CLAUDE.md hierarchy, path-specific rules with YAML frontmatter, skills with context: fork and allowed-tools, and the team-vs-personal MCP split.

D3 Claude Code — 20% D2 Tool Use & MCP — 18%

Exam Domains Covered

DomainNameWeightCoverage
D3Claude Code20%Primary — CLAUDE.md hierarchy, path rules, skills, planning mode, @path syntax
D2Tool Use & MCP18%Secondary — MCP config split, allowed-tools, team vs. personal servers

Project Files — Code Walkthrough

📋 CLAUDE.md D3 · Level 2 Project Standards

The project-root CLAUDE.md — committed to version control. This is Level 2 in the hierarchy and is shared by every team member who clones the repo. Contains universal coding standards (Python 3.11+, type annotations, Google docstrings, naming conventions, async guidelines, commit format) plus planning mode decision guidance.

LEVEL 1 — ~/.claude/CLAUDE.md (personal, never committed) ↓ merged with LEVEL 2 — <project-root>/CLAUDE.md ← THIS FILE (committed, team-shared) ↓ merged with LEVEL 3 — src/payments/CLAUDE.md (dir-specific, committed) ↓ plus LEVEL 4 — .claude/rules/*.md (path-scoped, load on file match)
  • Uses @path syntax to import 3 rules files: @./.claude/rules/api-conventions.md, @./.claude/rules/testing.md, @./.claude/rules/security.md
  • @ must be immediately adjacent to the path (no space) or it is treated as literal text
  • Maximum nesting depth for @path imports is 5 levels
  • Planning mode section: large refactors (3+ files), architectural decisions, unfamiliar code, debugging, security changes → use planning mode. Typo fixes, single tests → direct execution
Exam Trap: "A new developer doesn't get team standards." Root cause: standards were placed in ~/.claude/CLAUDE.md on one developer's machine. Fix: move to <project-root>/CLAUDE.md and commit. The project CLAUDE.md is the single source of truth for shared standards.
📏 .claude/rules/api-conventions.md D3 · Path-Specific Rules

Path-specific rule file loaded only when editing files under src/api/**/*. The YAML frontmatter paths: key triggers conditional loading. Without this file, a developer editing a CSS file would still load API rules — wasting context window tokens on irrelevant content.

# YAML frontmatter — triggers conditional loading
---
paths: ["src/api/**/*"]
---
  • Async/await required for all route handlers (no synchronous handlers)
  • Standard response wrapper: {"success": bool, "data": any, "error": str|null}
  • Pydantic validation on all inputs — never accept raw dict
  • Specific exceptions only — never bare except Exception
  • HTTP status codes: 200/201/422/404/401/403/503
  • Rate limiting decorator required on all public endpoints
Token Savings: 10 rule files × 800 tokens. A session editing 2 file types loads 2 files (1,600 tokens) vs. all 10 (8,000 tokens) — saving 6,400 tokens per session. For a team of 5 running 10 sessions/day: 320,000 tokens saved daily.
🧪 .claude/rules/testing.md D3 · Multi-Glob Path Pattern

Testing rule file with a multi-glob paths pattern. Test files can live anywhere in the project tree; this file targets them by naming convention rather than directory, ensuring the testing rules apply regardless of where the test is located.

---
paths: ["**/*.test.py", "**/test_*.py", "**/*_test.py"]
---
  • GIVEN / WHEN / THEN docstring required on every test function
  • Factory functions for all test data — no hardcoded inline data
  • Real database required — no DB mocking (mocking hides integration bugs)
  • Class-based test grouping (one class per endpoint/function)
  • Minimum 80% line coverage enforced in CI
  • Fixture scope guidance: function-scope DB sessions, module-scope clients, session-scope schema creation
Glob vs. Directory CLAUDE.md: Use paths: glob when the rule follows a file type (test files scattered across dirs). Use a directory CLAUDE.md when the rule follows a location (everything in src/payments/).
🔒 .claude/rules/security.md D3 · Multi-Path Frontmatter

Security rule file that loads for both API and auth directories — multi-path frontmatter. Security rules apply wherever inputs enter the system and wherever tokens/credentials are handled.

---
paths: ["src/api/**/*", "src/auth/**/*"]
---
  • Never log sensitive data (passwords, tokens, PII)
  • Parameterized queries only — no string-formatted SQL (SQL injection prevention)
  • Auth dependency on every protected route: Depends(get_current_user)
  • Sanitize all external inputs via Pydantic first
  • Secret management: ${ENV_VAR} syntax only — real values in .env
  • CORS: never allow_origins=["*"] in production
.claude/skills/code-review/SKILL.md D3 · Skills — context:fork + least privilege

The code-review skill invoked via /code-review src/api/. Uses context: fork to run in an isolated subagent — all intermediate work (reading files, running grep) happens in that subagent's context. Only the final report returns to the main session.

---
context: fork
allowed-tools: ["Read", "Grep", "Glob"]
argument-hint: "Path to file or directory to review"
---
  • context: fork — isolated subagent; intermediate work discarded after completion; main session gets only the report (~300 tokens)
  • allowed-tools: ["Read","Grep","Glob"] — read-only; no Write, no Bash; principle of least privilege
  • Reviews 4 categories: SECURITY → PERFORMANCE → STYLE → TESTING (always in this order)
  • Output format: severity level (CRITICAL/HIGH/MEDIUM/LOW) + code snippet + fix recommendation
  • SUMMARY section: total findings by severity + files reviewed
context: fork benefit: Without fork, reviewing 20 files + 50 greps fills the main session with review artifacts. With fork, only the final report (~300 tokens) enters the main session. Development context stays intact.
.claude/skills/test-gen/SKILL.md D3 · Skills — Least Privilege Comparison

The test-gen skill invoked via /test-gen src/api/users.py. Demonstrates why the allowed-tools list differs from code-review: test generation must create files, so Write is added. But Bash is still excluded — the skill writes tests but does not run them.

---
context: fork
allowed-tools: ["Read", "Grep", "Glob", "Write"]
argument-hint: "Path to source file to generate tests for"
---
  • Adds Write vs. code-review — must create test file
  • Still no Bash — does not need to execute tests
  • Still no Edit — Write is sufficient for new file creation
  • Process: Read source → Grep existing tests → Read testing.md rules → Write complete test file
Principle of Least Privilege: code-review needs [Read, Grep, Glob]. test-gen needs [Read, Grep, Glob, Write]. The one-tool difference illustrates exactly what least privilege means: add only what the task genuinely needs.
🔌 .mcp.json D2 · Team MCP Servers (Committed)

Team-shared MCP server configuration. Committed to version control. Every developer who clones the repo gets these 3 servers automatically: GitHub (code search, PRs), PostgreSQL (team dev DB), Slack (notifications). Real credentials use ${ENV_VAR} placeholders — actual values in each developer's local .env file.

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
    }
  }
}
  • ${ENV_VAR} is mandatory — real tokens in .mcp.json are permanently embedded in Git history
  • Compromised token procedure: rotate immediately → git filter-branch or BFG to remove from history → audit access logs
Failure Mode: Alice configures postgres MCP in ~/.claude.json. Bob clones the repo. Bob can't access the postgres MCP tool. Root cause: personal file was never committed. Fix: move to .mcp.json with ${DATABASE_URL}, commit it.
👤 personal-claude-override.example.json D2 · Personal MCP Template

Template for the personal ~/.claude.json override file. Committed to VCS as a template so developers know what to set up, but the actual ~/.claude.json with real credentials is never committed.

  • For personal local dev database (different URL from team shared DB)
  • For personal tools not ready to propose to the team
  • For experimental MCP integrations being evaluated before team adoption
  • Developer copies to ~/.claude.json and fills in real values locally
src/api/users.py Compliant Example

The compliant API file. Every element traces to a specific rule. Used to demonstrate what Claude Code should produce when all rules files are active.

Code ElementRule Satisfied
async def create_user(...)api-conventions: All endpoints must be async
request: CreateUserRequest (Pydantic)api-conventions: All inputs validated with Pydantic
Depends(get_current_user)security: Auth on every protected request
return ok(UserResponse...)api-conventions: Standard response wrapper
except DuplicateEmailError:api-conventions: Specific exceptions, not bare except
Google-style docstrings on all functionsCLAUDE.md: All public functions need docstrings
UserResponse excludes password hashsecurity: Never expose sensitive data
src/api/orders.py Intentional Violations Example

The intentional violations file. Run /code-review src/api/orders.py to see what the code-review skill catches. Contains 8+ violations across 3 endpoints.

ViolationRule BrokenSeverity
def get_order(order_id: int):Synchronous handlerMEDIUM
f"SELECT...WHERE id = '{order_id}'"SQL injection (string-formatted SQL)CRITICAL
Missing Depends(get_current_user)No auth on protected routesCRITICAL
logger.info(f"email: {email}")Logs PII (email address)HIGH
Query inside for oid in order_ids:N+1 query patternHIGH
return ordersMissing response wrapperMEDIUM
except Exception as e:Bare exceptMEDIUM
data: dict parameterNo Pydantic validationMEDIUM
🧪 tests/test_users.py Compliant Tests Example

Compliant test file demonstrating all testing conventions: GIVEN/WHEN/THEN docstrings, factory functions, real DB fixture (no mocking), class-based grouping.

  • make_user_payload(**overrides) factory — schema changes require updating ONE place
  • db_session fixture uses real TestAsyncSession + rollback for clean state
  • Two test classes: TestUserCreation, TestUserRetrieval
  • Tests cover: valid payload, duplicate email, missing field, non-admin forbidden, existing user, unknown ID, unauthenticated request

Practice Questions (15)

Source: explanation Ex2.md

1
Your team established Python type annotation requirements and async-first coding standards. A senior engineer added them to ~/.claude/CLAUDE.md. Three weeks later, a new hire reports Claude Code doesn't follow any of these standards. What is the root cause?
D3
+
  • A) The new hire needs to manually copy the senior engineer's ~/.claude/CLAUDE.md to their machine
  • B) The standards should have been placed in the project-level CLAUDE.md and committed to VCS
  • C) The new hire needs to set CLAUDE_CONFIG_PATH to point to the team config
  • D) Standards must be duplicated in both ~/.claude/CLAUDE.md and the project CLAUDE.md
Correct: B — ~/.claude/CLAUDE.md is personal to one developer's machine and never committed. New hires only receive files committed to VCS. Team standards must live in the project-level CLAUDE.md (committed to the repo root). Options A and C don't scale; D creates redundancy and maintenance problems.
2
Two senior developers consistently get Claude responses following team standards. A new developer doesn't. All three work in the same repo. The seniors recall configuring Claude "a while ago." Most likely explanation?
D3
+
  • A) The new developer is running an older Claude Code version
  • B) The senior developers put team standards in their personal ~/.claude/CLAUDE.md, which the new developer doesn't have
  • C) The new developer has a conflicting ~/.claude/CLAUDE.md that overrides project standards
  • D) The project CLAUDE.md hasn't loaded because the new developer is in a subdirectory
Correct: B — Classic onboarding failure. Original team members configured personal user-level ~/.claude/CLAUDE.md. New developer has their own (empty/different) user-level file. Fix: commit team standards to project-level CLAUDE.md. Version differences (A) would affect all three developers.
3
A developer adds "@ ./.claude/rules/api-conventions.md" (with a space after @) to the project CLAUDE.md. Claude Code does not apply the API conventions when editing src/api/ files. What is the problem?
D3
+
  • A) The .claude/ directory must be at the project root, not inside a subdirectory
  • B) @path is only supported in directory-level CLAUDE.md files
  • C) The space between @ and the path prevents Claude Code from recognizing it as an import directive
  • D) The ./ prefix is not supported; the path must be relative without ./
Correct: C — The @path syntax requires @ immediately adjacent to the path with no space. "@ ./.claude/rules/..." (with a space) is treated as literal text — Claude reads the @ symbol followed by a path string, not as a file import. Correct syntax: @./.claude/rules/api-conventions.md
4
Your project has .claude/rules/database.md with paths: ["src/models/**/*", "src/migrations/**/*"]. A developer edits src/api/users.py. Will database.md be loaded?
D3
+
  • A) Yes, because all .claude/rules/*.md files are always loaded in every session
  • B) Yes, because src/api/users.py is in src/, a parent of src/models/
  • C) No, because src/api/users.py does not match either src/models/**/* or src/migrations/**/*
  • D) No, because .claude/rules/*.md files only load when explicitly referenced with @path
Correct: C — Path-specific rules load only when the file being edited matches a glob pattern in the paths: frontmatter. src/api/users.py doesn't match either pattern. Option A is what path-specific rules exist to prevent. Parent directory matching (B) is not how glob evaluation works. Rules files with paths: frontmatter auto-load on match (D is wrong).
5
Tests live in tests/unit/, tests/integration/, src/components/__tests__/, and tests/e2e/. Which paths frontmatter correctly targets all test files regardless of directory?
D3
+
  • A) paths: ["tests/**/*"]
  • B) paths: ["**/*.py"]
  • C) paths: ["**/test_*.py", "**/*_test.py", "**/*.test.py"]
  • D) paths: ["tests/unit/**/*", "tests/integration/**/*", "src/components/__tests__/**/*", "tests/e2e/**/*"]
Correct: C — Test files are identified by naming convention, not directory location. **/test_*.py matches any file starting with test_ anywhere. Option A misses src/components/__tests__/. Option B loads the testing rule for every Python file (too broad). Option D works but breaks when a new test directory is added.
6
Your payment subsystem lives entirely under src/payments/. Rules: amounts must be integer cents, operations must be wrapped in DB transactions, Stripe calls need idempotency keys. These rules never apply outside src/payments/. Which configuration is most appropriate?
D3
+
  • A) A .claude/rules/payments.md file with paths: ["src/payments/**/*"]
  • B) A src/payments/CLAUDE.md directory-level file
  • C) Add rules to the root CLAUDE.md so they are always available
  • D) Either A or B works, but A is preferred because it is more token-efficient
Correct: B — When rules are tightly scoped to one directory and never apply elsewhere, a directory CLAUDE.md is the natural choice. The rules follow the location. A .claude/rules/ path-scoped file (A) also works but the preferred convention for purely location-based rules is directory CLAUDE.md. Option C loads rules for every file.
7
A developer runs /code-review src/api/ on 20 files. After the review, the session seems to have lost context about the feature being built. The SKILL.md does not have context: fork. What is the most likely cause?
D3
+
  • A) Running a skill always resets the session context as a security measure
  • B) The code review read all 20 files and many grep results, filling the context window with review artifacts that crowded out earlier conversation
  • C) The allowed-tools list restricted Claude's access to prior conversation history
  • D) Directory-level code review requires a separate session
Correct: B — Without context: fork, the skill runs in the main session. Reading 20 files + 50 greps + analysis all accumulate. At the context limit, older content (including earlier development work) gets pushed out. With context: fork, only the final report (~300 tokens) enters the main session.
8
A /document skill reads source files and writes Markdown docs. A colleague suggests allowed-tools: ["Read","Grep","Glob","Write","Bash","Edit"]. What is wrong?
D3
+
  • A) Skills can only have a maximum of 4 allowed tools
  • B) Bash is not a valid tool name in Claude Code's allowed-tools list
  • C) Granting Bash and Edit violates least privilege — the task requires reading and creating files, not executing shell commands or modifying existing files
  • D) allowed-tools only restricts tools for user messages, not skill invocations
Correct: C — A documentation skill needs Read (understand source), Grep/Glob (find files), Write (create docs). It does not need Bash (no shell commands) or Edit (creating new docs with Write is sufficient). Granting Bash allows arbitrary shell command execution — a significant security over-grant. Least privilege: grant only what the task genuinely requires.
9
Two requirements: (1) "All async functions must include error handling at the service layer." (2) "When asked to generate a migration, read the current schema, identify the delta, generate the migration file, and print a summary." Which configuration belongs where?
D3
+
  • A) Both belong in CLAUDE.md
  • B) Both belong as skills
  • C) Requirement 1 in CLAUDE.md; Requirement 2 as a skill
  • D) Requirement 1 as a skill; Requirement 2 in CLAUDE.md
Correct: C — Req 1 is an always-apply coding standard — CLAUDE.md. Req 2 is a specific on-demand workflow with defined input (schema), process (read→diff→generate→summarize), and output — invoked explicitly. That is the definition of a skill. Skills are for specific repeatable workflows; CLAUDE.md is for universal standards.
10
8 developers use a shared Jira MCP server. One developer uses a personal Obsidian notes MCP server that no one else needs. Where should each live?
D2
+
  • A) Both in .mcp.json
  • B) Jira in .mcp.json (committed); Obsidian in ~/.claude.json (personal, not committed)
  • C) Jira in ~/.claude.json on each machine; Obsidian in .mcp.json
  • D) Both in ~/.claude.json — MCP servers contain credentials and should never be in VCS
Correct: B — .mcp.json is for team-shared servers (committed, with ${ENV_VAR} for credentials). ~/.claude.json is for personal tools. Jira is shared → .mcp.json. Obsidian is personal → ~/.claude.json. Option A forces everyone to have an Obsidian server they don't need. D is wrong — .mcp.json with ${ENV_VAR} is designed to be committed safely.
11
A developer asks: "Why can't I put the real GitHub token directly in .mcp.json to make it easier?" What is the correct response?
D2
+
  • A) Real tokens in .mcp.json work fine for development, but CI/CD pipelines require ${ENV_VAR} syntax
  • B) .mcp.json only supports ${ENV_VAR} syntax; real tokens cause a parse error
  • C) Real tokens in .mcp.json are committed to VCS history, where they are permanently visible — even after deletion, the token remains in git log
  • D) The ${ENV_VAR} syntax is just a convention; Claude Code reads both formats equally
Correct: C — .mcp.json is committed to VCS. A real token is permanently embedded in git history. Even deleting it in the next commit doesn't remove it from git log/git diff/any clone made before removal. The token must be treated as compromised immediately. ${ENV_VAR} keeps real values in .env (gitignored) or CI secrets.
12
Alice uses a postgres MCP server from Claude Code. Bob clones the same repo, opens Claude Code, and finds the postgres tool unavailable. Most likely root cause?
D2
+
  • A) Bob needs to install @modelcontextprotocol/server-postgres globally
  • B) Alice defined the postgres MCP server in her ~/.claude.json instead of the committed .mcp.json
  • C) Bob's Claude Code version is incompatible with Alice's postgres MCP version
  • D) The postgres MCP server requires admin permissions Bob's machine doesn't have
Correct: B — The most common cause of "works for one developer, not another" MCP availability is personal ~/.claude.json vs. committed .mcp.json. Bob cloned the repo and got everything in VCS, but Alice's ~/.claude.json was never committed. Fix: move to .mcp.json with ${DATABASE_URL}, commit it, Bob adds DATABASE_URL to his .env.
13
A refactor changes authentication from JWT to session-based across 22 files in src/auth/, src/api/, src/middleware/, and tests. Should planning mode be used?
D3
+
  • A) Direct execution — Claude Code is fast enough to handle 22 files sequentially
  • B) Planning mode — 22 files with cross-cutting dependencies warrants reasoning through the migration sequence first
  • C) Direct execution with /code-review after each file to catch mistakes
  • D) Planning mode is unnecessary because path-specific rules will guide Claude
Correct: B — A 22-file refactor with cross-cutting dependencies (auth module before callers, middleware before API layer, source before tests) is exactly what planning mode is designed for. Without planning, Claude might change files in an order that leaves the codebase in a broken intermediate state. Plan the dependency graph first, then execute.
14
A bug: POST /api/users returns HTTP 200 instead of HTTP 201. Stack trace is clear — line 69 of src/api/users.py returns ok(...) but the route decorator is @router.post("/") without status_code=201. Should planning mode be used?
D3
+
  • A) Yes — any API endpoint bug should use planning mode to prevent regressions
  • B) Yes — security-related endpoints always require planning mode
  • C) No — the bug has a clear, isolated root cause with a one-line fix; planning mode adds latency with no quality benefit
  • D) No — planning mode is only for architectural decisions, not bug fixes
Correct: C — Planning mode is for complex problems where jumping to execution risks missing something. This bug has a clear root cause (missing status_code=201) and a one-line fix. Planning mode would add latency and token cost for no quality gain. Direct execution: make the change, run the test. Option D overstates the limitation — planning mode is useful for some bug fixes, just not trivial single-line ones.
15
Your team is adding Claude Code to a GitHub Actions CI pipeline to run automated code review on every PR. The pipeline must not pause for user confirmation prompts. Which flag must be included?
D3
+
  • A) --no-prompts
  • B) --headless
  • C) --yes-to-all
  • D) --dangerously-skip-permissions
Correct: D — Claude Code's --dangerously-skip-permissions flag enables non-interactive mode by skipping permission confirmation prompts. Without it, Claude Code pauses for user input, hanging a CI pipeline indefinitely. The name is intentionally alarming — only use in trusted, controlled environments like CI pipelines. Options A, B, C are not valid Claude Code flags.