Skip to content
Chapter 4 of 8

Domain 3: Claude Code configuration and workflows

Domain 3 rewards hands-on Claude Code experience, and it turns on one idea: where a rule lives decides who gets it. CLAUDE.md has three levels. User-level at the home directory applies to that user across all projects and is not shared. Project-level at the project root or in the project's .claude directory applies to all contributors and is shared through version control. Directory-level adds specificity for one part of the codebase. The most common exam trap is a new teammate who never receives the project coding standards because someone put them in the user-level file instead of the shared project-level file. Separate from CLAUDE.md, settings.json controls runtime behavior: tool permissions and allowlists belong in the committed project settings.json, not in CLAUDE.md natural language, because CLAUDE.md is for behavioral guidance and settings.json is for programmatic permission control. The rules directory is an alternative to a monolithic file, where each file carries YAML frontmatter with a paths pattern so it loads only when Claude Code touches a matching file, which saves context. Skills with context set to fork run in an isolated subagent so verbose output does not pollute the main session. And planning mode is for large or unfamiliar changes where investigation must precede action, while direct execution is for single-file fixes with a clear cause. In this lab you route configuration items to the correct file, reproduce the teammate-misses-standards trap, match path-scoped rules to their files, and pick the workflow mode.

The lab: read it, then run it

labs/cca-f/cf4-claude-code-config.py
#!/usr/bin/env python3
"""
LAB CF4: Claude Code configuration and workflows (Domain 3, 20%).

Where a rule lives decides who gets it. This lab routes configuration items to
the correct scope and file, and reproduces the single most common exam trap: a
new teammate never receives the project coding standards because they were put
in user-level ~/.claude/CLAUDE.md (not shared) instead of project-level
.claude/CLAUDE.md (shared via version control). It also matches path-scoped
rule files to the files they should load for, and picks planning mode vs direct
execution.

Deterministic, offline, standard library only.
Run: python3 modules/academy-content/labs/cca-f/cf4-claude-code-config.py
"""
import sys
import fnmatch

# Each config file: (scope, shared via VCS?). Straight from the study guide.
FILES = {
    "~/.claude/CLAUDE.md":        ("user, all projects",        False),
    ".claude/CLAUDE.md":          ("project, all contributors", True),
    "subdir/CLAUDE.md":           ("that directory and below",  True),
    "~/.claude/settings.json":    ("machine-wide",              False),
    ".claude/settings.json":      ("project-wide permissions",  True),
    ".claude/settings.local.json":("personal project override", False),
    ".mcp.json":                  ("project MCP servers",       True),
    "~/.claude.json":             ("personal MCP servers",      False),
}


def is_shared(path: str) -> bool:
    return FILES[path][1]

# STEP 1: route each requirement to the correct file.
# (requirement, correct file)
ROUTING = [
    ("Team coding standards everyone must follow", ".claude/CLAUDE.md"),
    ("A personal preference for just my machine",  "~/.claude/CLAUDE.md"),
    ("Tool permission allowlist for the whole team", ".claude/settings.json"),
    ("A shared MCP server for all contributors",   ".mcp.json"),
    ("My own experimental MCP server",             "~/.claude.json"),
]
print("STEP 1: route configuration to the correct file")
routing_ok = True
for req, path in ROUTING:
    shared = is_shared(path)
    print(f"  {req}\n      -> {path}  (shared={shared})")
    # team-wide things MUST be shared; personal things MUST NOT be
    expect_shared = req.lower().startswith(("team", "tool permission", "a shared"))
    routing_ok = routing_ok and (shared == expect_shared)

# STEP 2: the classic trap. Standards placed user-level do not reach a teammate.
print("")
print("STEP 2: the 'new teammate misses standards' trap")
wrong_placement = "~/.claude/CLAUDE.md"
right_placement = ".claude/CLAUDE.md"
teammate_gets_wrong = is_shared(wrong_placement)
teammate_gets_right = is_shared(right_placement)
print(f"  standards in {wrong_placement:<22} reach teammate? {teammate_gets_wrong}")
print(f"  standards in {right_placement:<22} reach teammate? {teammate_gets_right}")

# STEP 3: path-scoped rules load only for matching files.
RULE_PATHS = ["**/*.test.ts", "**/*.test.tsx"]


def rule_loads_for(filename: str) -> bool:
    return any(fnmatch.fnmatch(filename, p) for p in RULE_PATHS)

print("")
print("STEP 3: .claude/rules/ path matching")
cases = [("src/auth/login.test.ts", True), ("src/auth/login.ts", False)]
paths_ok = True
for fname, expect in cases:
    got = rule_loads_for(fname)
    paths_ok = paths_ok and (got == expect)
    print(f"  {fname:<26} loads test rule? {got}")

# STEP 4: planning mode vs direct execution.
def mode_for(task: str) -> str:
    big = task in ("cross-codebase refactor", "unfamiliar codebase",
                   "architectural decision")
    return "planning" if big else "direct"

print("")
print("STEP 4: workflow mode")
mode_cases = [("cross-codebase refactor", "planning"),
              ("single-file fix with clear stack trace", "direct")]
mode_ok = True
for task, expect in mode_cases:
    got = mode_for(task)
    mode_ok = mode_ok and (got == expect)
    print(f"  {task:<40} -> {got} mode")

# Invariants.
trap_ok = (teammate_gets_wrong is False and teammate_gets_right is True)
ok = routing_ok and trap_ok and paths_ok and mode_ok
print("")
print(f"  config routed to correct scope        : {routing_ok}")
print(f"  teammate-misses-standards trap proven : {trap_ok}")
print(f"  path-scoped rules match correctly     : {paths_ok}")
print(f"  planning vs direct mode chosen right  : {mode_ok}")
print("")
print(f"CONFIG ROUTED TO CORRECT SCOPE: {'YES' if ok else 'NO'}")
if not ok:
    sys.exit(1)
print("Shared standards go project-level and get committed. settings.json holds permissions. Next: prompt engineering.")
Runnable lab
cf4-claude-code-config.py

Route configuration to the correct scope, prove the teammate-misses-standards trap, and match path-scoped rules to files.

Proves: CONFIG ROUTED TO CORRECT SCOPE: YES

Open the notebook

Runs in your browser via Pyodide. First run loads the runtime once; no install, no server.

The routing made the hierarchy concrete: team standards and shared MCP servers land in committed project files, personal preferences and experimental servers stay in unshared user files, and the classic trap is nothing more than shared standards placed one level too high. Two more facts the exam checks. The dash-p flag switches Claude Code into non-interactive mode, which is the correct and required way to run it in a CI/CD pipeline, often with a JSON output format so downstream steps can parse the result. And the code-generation session and the code-review session should be separate Claude instances, because a session that wrote the code is less likely to challenge its own reasoning. Next you move into the prompt engineering domain and structured output.
Check your understanding
  1. 1. A new teammate does not get the project's coding standards. What is the cause?

  2. 2. Where do tool permission allowlists belong?

  3. 3. When should you use planning mode instead of direct execution?

  4. 4. How do you run Claude Code inside a CI/CD pipeline?