# D7 · Claude Code

Core components, CLAUDE.md hierarchy and imports, settings.json scopes and permissions, session management, slash commands, headless and streaming modes, permission modes, hooks, MCP config and plan mode.

import { Accordions, AccordionItem, Tabs, TabItem } from '@prosefly/astro-components';

This domain is roughly **2 of 53 items**. It tests whether you know how Claude Code is configured and operated: the `CLAUDE.md` hierarchy, `settings.json` scopes and permissions, session management, slash commands, headless mode, hooks, MCP config and plan mode. The theme: **behaviour comes from configuration files, and permissions/hooks – not prose – enforce control.**

## Learning objectives

By the end of this page you should be able to:

1. Identify Claude Code's **core components**: Rules/`CLAUDE.md`, Skills, Commands, Agents/subagents, Agent Memory.
2. Explain the **`CLAUDE.md` hierarchy** and `@path` **imports**.
3. Configure **`settings.json`** scopes and **permissions** (allow/deny/ask).
4. Manage sessions (`/compact`, `/clear`, resume) and use **slash commands**.
5. Use **headless** (`-p`, `--output-format`) and **streaming** modes and **permission modes**.
6. Configure **hooks**, **MCP**, and **plan mode**.

---

## 7.1 Core components

| Component | Where | Purpose |
| --- | --- | --- |
| **Rules / `CLAUDE.md`** | Hierarchy of files | Persistent project/user instructions |
| **Skills** | `.claude/skills/<name>/SKILL.md` | Progressive, on-demand capabilities (name + description frontmatter) |
| **Commands** | `.claude/commands/*.md` | Custom slash commands with `$ARGUMENTS` |
| **Agents / subagents** | `.claude/agents/*.md` | Own system prompt, tool allowlist, model; isolated context |
| **Agent Memory** | `/memory` | Durable cross-session notes |

---

## 7.2 CLAUDE.md hierarchy and imports

`CLAUDE.md` files are memory: persistent instructions Claude loads at session start. They **compose** from broad to narrow, with more-specific files layered on top of (not replacing) broader ones. Managed policy sits at the top and cannot be overridden.

```text
                 ┌─────────────────────────────────────────┐
  highest ►      │  enterprise / managed policy             │  admin-controlled, NOT overridable
  precedence     └─────────────────────────────────────────┘
                                  ↓ composes down
                 ┌─────────────────────────────────────────┐
                 │  user       ~/.claude/CLAUDE.md          │  personal, spans all your projects
                 └─────────────────────────────────────────┘
                                  ↓
                 ┌─────────────────────────────────────────┐
                 │  project    ./CLAUDE.md                  │  checked in; the team standard
                 └─────────────────────────────────────────┘
                                  ↓
                 ┌─────────────────────────────────────────┐
                 │  subdirectory  ./services/api/CLAUDE.md  │  module-specific, loaded when working there
                 └─────────────────────────────────────────┘

  CLAUDE.local.md = git-ignored personal override that lives beside a project file
  @path imports   = pull shared files into any CLAUDE.md, e.g. @docs/standards.md
```

### What belongs where

| Content | File | Reason |
| --- | --- | --- |
| Org-wide security rules, forbidden tools | managed policy | Must not be overridable by any developer |
| Personal preferences (editor style, alias notes) | `~/.claude/CLAUDE.md` | Applies to you across all projects |
| Team coding standards, architecture, build/test commands | `./CLAUDE.md` | Checked in; single source of team truth |
| Module-specific conventions (e.g. API layer rules) | `./services/api/CLAUDE.md` | Loaded only when working in that subtree |
| Your local scratch notes, experimental instructions | `CLAUDE.local.md` | Git-ignored; never shared |
| Shared standards referenced from many places | separate file via `@path` import | Write once, import into project `CLAUDE.md` |
| Secrets, tokens, API keys | **none of the above** | Version-controlled; use `env` / a secret manager |

### Example project CLAUDE.md

```markdown
# Payments Service — Claude memory

## Stack
- Python 3.12, FastAPI, PostgreSQL, pytest.

## Commands
- Install: `uv sync`
- Test: `uv run pytest -q`
- Lint: `uv run ruff check .`

## Conventions
- Money is always integer cents; never floats.
- All external calls go through `app/clients/` with retries and timeouts.
- New endpoints require a test and an entry in `CHANGELOG.md`.

## Imports
@docs/api-style.md
@docs/security-checklist.md

## Guardrails
- Do not run destructive DB commands.
- Do not edit files under `infra/` without an explicit request.
```

:::caution[Secrets never go in CLAUDE.md]
`CLAUDE.md` is version-controlled and shared. Put secrets in environment variables or a secret manager and reference them by name. A leaked key in `CLAUDE.md` is an exfiltration incident.
:::

---

## 7.3 settings.json scopes and permissions

`settings.json` controls **behaviour** (model, permissions, hooks, environment). Like memory, it composes across scopes, and managed policy cannot be overridden.

```text
managed policy  →  user ~/.claude/settings.json  →  project .claude/settings.json  →  .claude/settings.local.json
(not overridable)   (personal, all projects)        (checked in, team baseline)        (git-ignored, personal)
```

A checked-in project `settings.json` with `permissions`, `hooks`, and `env`:

```json
{
  "model": "claude-sonnet-5",
  "permissions": {
    "allow": ["Read", "Grep", "Glob", "Edit"],
    "deny": ["Bash(rm -rf:*)", "Bash(git push --force:*)", "Read(./.env)"],
    "ask": ["Bash", "WebFetch"]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": ".claude/hooks/guard-bash.sh" }
        ]
      }
    ]
  },
  "env": {
    "ANTHROPIC_MODEL": "claude-sonnet-5",
    "DEPLOY_ENV": "development"
  }
}
```

- `permissions.allow` runs the tool without prompting; `ask` prompts for confirmation; `deny` blocks outright.
- **`deny` beats `allow`.** A tool matched by both is denied.
- Rules are **patterns**, e.g. `Bash(rm -rf:*)` denies that command family while allowing other Bash.
- Prefer deny-by-default for destructive commands; keep `allow` to the tools a task genuinely needs.

:::tip[Exam signal]
'Enforce a rule / block a command / no one can override' → **permissions + managed policy**, not a sentence in `CLAUDE.md`. Prose is guidance; permissions and hooks are enforcement.
:::

---

## 7.4 Hooks

Hooks are deterministic shell or HTTP handlers that fire on lifecycle events. Unlike prose instructions, they **always** run and can block an action — the mechanism for enforcing critical business rules (anti-pattern #3 is enforcing rules in prose instead).

| Event | Fires when | Typical use |
| --- | --- | --- |
| `PreToolUse` | Before a tool runs | Validate/block a command; `exit 2` denies it |
| `PostToolUse` | After a tool runs | Auto-format, lint, run tests on edited files |
| `UserPromptSubmit` | User submits a prompt | Inject context; scan for secrets |
| `Stop` | Main agent finishes responding | Enforce completion checks |
| `SubagentStop` | A subagent finishes | Validate subagent output |
| `SessionStart` | Session begins | Load environment info, print reminders |
| `Notification` | Claude sends a notification | Route to Slack/paging |
| `PreCompact` | Before context compaction | Persist state that must survive compaction |

**Exit code 2 from a hook blocks the action** (stderr is shown to Claude); other non-zero codes are non-blocking errors.

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if grep -qE 'rm -rf|drop table' <<< \"$CLAUDE_TOOL_INPUT\"; then echo 'blocked: destructive command' >&2; exit 2; fi"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          { "type": "command", "command": "uv run ruff format $CLAUDE_FILE_PATHS" }
        ]
      }
    ]
  }
}
```

---

## 7.5 Skills vs slash commands vs subagents

Three ways to package reusable behaviour. The exam tests which one fits a scenario.

| Dimension | Skill | Slash command | Subagent |
| --- | --- | --- | --- |
| File | `.claude/skills/<name>/SKILL.md` | `.claude/commands/<name>.md` | `.claude/agents/<name>.md` |
| Trigger | Model loads it **on demand** when relevant | User types `/<name>` explicitly | Delegated a task (auto or explicit) |
| Context | Progressive; loaded only when needed | Injected into current context | **Isolated** own context window |
| Own system prompt / model | No | No | **Yes** (own prompt, tools allowlist, model) |
| Best for | A capability Claude should reach for automatically | A repeatable prompt you invoke by hand | A specialised worker that needs isolation |

Skill (`.claude/skills/api-docs/SKILL.md`):

```markdown
---
name: api-docs
description: Write and format REST API reference docs in the house style. Use when documenting endpoints.
---

# API documentation style

- One H2 per endpoint: `## METHOD /path`.
- Document auth, params (table), request body, responses by status.
- Include a curl example and a JSON response example.
```

Slash command with `$ARGUMENTS` (`.claude/commands/fix-issue.md`):

```markdown
---
description: Investigate and fix a GitHub issue by number.
---

Investigate issue #$ARGUMENTS. Read the linked code, reproduce the bug,
propose a fix in plan mode, then implement it with a regression test.
```

Invoke with `/fix-issue 482` — `$ARGUMENTS` becomes `482`.

Subagent (`.claude/agents/reviewer.md`):

```markdown
---
name: reviewer
description: Reviews diffs for security and style. Use proactively before commits.
tools: Read, Grep, Glob
model: claude-opus-5
---

You are a senior code reviewer. Review only the staged diff.
Report findings by severity. Do not modify files.
```

:::tip[Exam signal]
'Loads automatically when relevant / progressive disclosure' → **Skill**. 'A command the developer runs with an argument' → **slash command** with `$ARGUMENTS`. 'Needs its own context / narrow tools / different model / isolation' → **subagent**.
:::

---

## 7.6 Plan mode

Plan mode (enter with **Shift+Tab**, or `--permission-mode plan` headless) makes Claude explore **read-only** and produce a plan before it edits anything. It is the safe first step for large or risky changes: a migration, a cross-cutting refactor, or unfamiliar code. You review the plan, then approve execution.

The exam pairs plan mode with **large automated migrations** and **risk reduction**: explore → plan → approve → apply with tests.

---

## 7.7 Headless mode, streaming and permission modes

<Tabs>
  <TabItem label="Headless">
```bash
# One-shot, machine-readable output for CI
claude -p "Summarise the failing tests" --output-format json

# Streaming JSON events (parse incrementally)
claude -p "Refactor utils" --output-format stream-json --allowedTools "Read,Edit"

# Read-only review with a restricted toolset
claude -p "Review the staged diff for security issues; output JSON." \
  --output-format json \
  --allowedTools "Read,Grep" \
  --permission-mode plan
```
`-p` runs non-interactively; `--output-format` is `json` or `stream-json`; `--allowedTools` restricts the toolset; `--permission-mode` sets the gating behaviour.
  </TabItem>
  <TabItem label="Permission modes">
`--permission-mode` (or `permissionMode` in the SDK):

| Mode | Behaviour |
| --- | --- |
| `default` | Ask before non-allowlisted tools |
| `acceptEdits` | Auto-accept file edits, still gate other tools |
| `plan` | Read-only; explore and plan, no changes |
| `bypassPermissions` | Skip all prompts — dangerous; only in a trusted, sandboxed CI |
  </TabItem>
  <TabItem label="Plan mode">
Interactive **Shift+Tab** enters plan mode: read-only exploration, then a proposed plan you approve before any change. The headless equivalent is `--permission-mode plan`.
  </TabItem>
</Tabs>

:::tip[Exam signal]
'Run Claude Code in CI / non-interactively / machine-readable output' → headless `-p` with `--output-format json|stream-json` and a restricted `--allowedTools`. 'Explore safely before changing anything' → plan mode. Never `bypassPermissions` outside a trusted sandbox.
:::

---

## 7.8 Session commands and MCP configuration

Slash commands during an interactive session:

| Command | Effect |
| --- | --- |
| `/compact` | Summarise the conversation server-side to free context (keeps narrative) |
| `/clear` | Reset the conversation entirely (fresh context) |
| `/init` | Bootstrap a `CLAUDE.md` for the current project |
| `/memory` | View/edit agent memory (`CLAUDE.md` files) |
| `/agents` | Manage subagents |
| `/hooks` | Manage hooks |
| `/mcp` | Manage/inspect MCP servers and auth |
| `/cost` | Show token and cost usage for the session |

`/compact` summarises to preserve narrative; `/clear` throws context away — do not confuse them.

### MCP config scopes

Add servers with `claude mcp add <name> --scope <scope> -- <command>` or by editing `.mcp.json`:

| Scope | Stored in | Shared? |
| --- | --- | --- |
| `local` | Your machine, current project only | No (personal, this project) |
| `project` | `.mcp.json` in the repo | **Yes** — checked in, team-wide vetted catalogue |
| `user` | Your user config | No — spans your projects, personal |

```json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
    }
  }
}
```

Use **project** scope for a shared, vetted catalogue; inspect and authenticate with `/mcp`.

---

## 7.9 The permission model in depth: allow / ask / deny and precedence

Claude Code's tool control is a small but heavily tested decision surface. Rules are **patterns**, they compose across scopes, and **`deny` beats `allow`**; managed policy sits above everything.

| Decision | Meaning | Use for |
| --- | --- | --- |
| `allow` | Run without prompting | Safe, frequently-used tools (Read, Grep, Glob) |
| `ask` | Prompt for confirmation | Medium-risk tools (Bash, WebFetch) |
| `deny` | Block outright (wins over `allow`) | Destructive command families, reading `.env` |

```text
managed policy  →  user settings  →  project settings (.claude/settings.json)  →  settings.local.json
(non-overridable)   (personal)        (checked in, team baseline)                  (git-ignored, personal)

resolution: deny > ask > allow, with more-specific scopes layering over broader ones,
            and managed policy overriding all of them.
```

| Scenario | Correct configuration |
| --- | --- |
| Block `rm -rf` for everyone, non-overridably | `Bash(rm -rf:*)` in `deny`, set via **managed policy** |
| Auto-run read tools, confirm shell | `allow: [Read, Grep, Glob]`, `ask: [Bash]` |
| Never read the secrets file | `deny: [Read(./.env)]` |
| Personal-only experiment | `settings.local.json` (git-ignored) |

:::tip[Exam signal]
'No one can override this block' → **managed policy** `deny`. 'A tool is in both allow and deny' → **denied** (`deny` beats `allow`). 'Enforce a rule' → permissions/hooks, never a `CLAUDE.md` sentence.
:::

---

## 7.10 Composing memory and settings across scopes

`CLAUDE.md` (memory) and `settings.json` (behaviour) both compose broad→narrow, and both are topped by non-overridable managed policy. Knowing *what belongs where* is a frequent item.

| Layer | `CLAUDE.md` (memory) | `settings.json` (behaviour) |
| --- | --- | --- |
| Managed / enterprise | Org security rules, forbidden tools (non-overridable) | Managed permissions/hooks (non-overridable) |
| User (`~/.claude/`) | Personal preferences across all projects | Personal model/permission defaults |
| Project (`./`, `.claude/`) | Team standards, build/test commands (checked in) | Team baseline permissions, hooks, env (checked in) |
| Subdirectory / local | Module rules; `CLAUDE.local.md` (git-ignored) | `settings.local.json` (git-ignored) |

- Secrets never belong in either — use env vars / a secret manager.
- `@path` imports pull shared files into any `CLAUDE.md`.
- A subdirectory file **layers on top of** (does not replace) broader files when working in that subtree.

:::caution[Local files are personal, not team policy]
`CLAUDE.local.md` and `settings.local.json` are git-ignored and personal. Putting a rule you need the whole team to follow in a local file means nobody else gets it — use checked-in project files or managed policy.
:::

---

## 7.11 Common misconceptions

| Misconception | Reality | Why it matters on the exam |
| --- | --- | --- |
| A `CLAUDE.md` sentence enforces a rule | Prose is guidance; enforcement is permissions/hooks | Anti-pattern #3 in Claude Code form |
| Project settings can override managed policy | Managed/enterprise policy is non-overridable | Precedence questions |
| `allow` wins if a tool is also denied | `deny` beats `allow` | Permission-resolution trap |
| `bypassPermissions` is fine for convenience | Only in a trusted, sandboxed CI; it removes safeguards | Safety trap |
| `/compact` and `/clear` are interchangeable | Compact summarises (keeps narrative); clear resets | Session-management trap |
| Secrets can live in `CLAUDE.md` as documentation | It is version-controlled; use env/secret manager | Secrets-hygiene trap |
| A slash command loads automatically | Slash commands are user-invoked; Skills load on demand | Skill vs command vs subagent |
| `CLAUDE.local.md` is a good place for team rules | It is git-ignored and personal | Scope trap |

---

## 7.12 Scenario walkthrough: hardening a shared Claude Code setup for CI

**Scenario.** A team uses Claude Code both interactively and in CI. Security requires that `rm -rf`, `git push --force`, and reading `.env` are blocked for *everyone* and cannot be overridden by any developer. CI must run non-interactively, produce machine-readable output, and only read code (no edits). Developers keep asking to `bypassPermissions` in CI 'to make it faster', and one added `never force-push` to `./CLAUDE.md` expecting it to be enforced. Design the configuration.

**Expert reasoning trace.**

1. **Enforce the destructive-command blocks non-overridably.** Put `deny` patterns (`Bash(rm -rf:*)`, `Bash(git push --force:*)`, `Read(./.env)`) in **managed policy** so no user/project/local file can override them; `deny` beats `allow`. The `./CLAUDE.md` sentence is prose, not enforcement (anti-pattern #3) — it must be removed as a false sense of safety and replaced with the permission rule.
2. **Configure CI correctly.** Headless `claude -p "..." --output-format json` with an explicit `--allowedTools "Read,Grep,Glob"` and `--permission-mode plan` (read-only). This is machine-readable, non-interactive, and edit-free.
3. **Reject `bypassPermissions`.** It removes the very safeguards required and would let a compromised or injected step run destructive commands; allow it only inside a fully trusted, sandboxed automation — not the general CI here.
4. **Put team rules in the right scope.** Coding standards and build/test commands go in checked-in `./CLAUDE.md`; the security blocks go in managed policy; personal experiments go in git-ignored `CLAUDE.local.md`/`settings.local.json`.
5. **Reject the tempting alternatives.** 'Trust the `CLAUDE.md` rule' — prose is not enforcement. 'Use `bypassPermissions` for speed' — removes safeguards. 'Add the block only to project settings' — a developer could override it locally, so it must be managed policy.

**Correct decision.** Managed-policy `deny` patterns for the destructive commands and `.env`; headless CI with `--output-format json`, a read-only `--allowedTools` allowlist, and `--permission-mode plan`; no `bypassPermissions` outside a trusted sandbox; team standards in checked-in `CLAUDE.md`, personal items in git-ignored local files.

---

## Exam traps in this domain

| Trap | Why it is wrong |
| --- | --- |
| Putting secrets in `CLAUDE.md` | It is version-controlled; use env/secret manager |
| Assuming project `CLAUDE.md` overrides managed policy | Managed/enterprise policy wins and is not overridable |
| Using `bypassPermissions` casually | Removes safeguards; only in trusted, sandboxed automation |
| Enforcing rules in `CLAUDE.md` prose instead of permissions/hooks | Prose is guidance, not enforcement (anti-pattern #3) |
| Expecting interactive prompts in CI | Use headless `-p` + `--output-format` + `--allowedTools` |
| Confusing `/compact` with `/clear` | Compact summarises and keeps narrative; clear resets |
| Loading a huge tool set instead of subagents | Overloads selection; use subagents + tool search |
| Forgetting `deny` beats `allow` | A tool in both lists is denied |
| Using a slash command where a Skill is needed | Skills load on demand; commands are user-invoked |
| Giving a subagent broad tools 'just in case' | Violates least privilege; scope the allowlist |
| Putting a rule in `CLAUDE.local.md` for the whole team | It is git-ignored and personal; use checked-in/managed |
| Confusing `local` and `project` MCP scope | Only `project` (`.mcp.json`) is shared/checked in |
| Putting a non-overridable block only in project settings | A developer can override it locally; use managed policy |
| Assuming `allow` wins over `deny` | `deny` beats `allow`; resolution is deny > ask > allow |
| Enforcing a security rule via a `./CLAUDE.md` sentence | Prose is guidance; use a `deny` permission or hook (anti-pattern #3) |
| Using `bypassPermissions` in general CI for speed | Removes safeguards; only inside a fully trusted sandbox |
| Storing team standards in `settings.local.json` | It is git-ignored and personal; use checked-in project settings |

---

## Practice questions

<Accordions>
  <AccordionItem title="Q1 · A team runs Claude Code in a CI pipeline and needs machine-readable results with no interactive prompts. Which invocation fits? (Select one)">
    A. `claude` interactive with plan mode.
    B. `claude -p "..." --output-format json` with an explicit `--allowedTools` allowlist.
    C. `claude` with `bypassPermissions` and no output format.
    D. Open Claude Desktop.

    **Answer: B.** Headless `-p` with `--output-format json` and a tool allowlist is the CI pattern. Interactive plan mode (A) and Desktop (D) are not headless and cannot run unattended; `bypassPermissions` (C) removes safeguards and gives unstructured output CI cannot parse.
  </AccordionItem>

  <AccordionItem title="Q2 · A managed enterprise policy forbids the Bash tool, but a project `CLAUDE.md` says to use it and `settings.local.json` allows it. What happens? (Select one)">
    A. The project setting wins.
    B. The local setting wins.
    C. The managed policy wins and Bash remains denied.
    D. It is undefined.

    **Answer: C.** Managed/enterprise policy sits at the top of precedence and cannot be overridden by user, project, or local config. Prose in `CLAUDE.md` (A) is not enforcement, and a local file (B) cannot override a managed deny; behaviour is well-defined, not undefined (D).
  </AccordionItem>

  <AccordionItem title="Q3 · A subdirectory `./services/api/CLAUDE.md` sets a rule that conflicts with the project-root `./CLAUDE.md` while you work in that subtree. Which applies, and why? (Select one)">
    A. The root file always wins because it is checked in first.
    B. The more specific subdirectory file layers on top for work in that subtree, while the root file still contributes; managed policy still overrides both.
    C. Neither applies; you must merge them manually.
    D. Only `CLAUDE.local.md` applies in subdirectories.

    **Answer: B.** Memory composes broad-to-narrow: the subdirectory file adds module-specific context on top of the root standard, and managed policy remains non-overridable above both. The root does not simply win (A); files compose automatically rather than requiring a manual merge (C); `CLAUDE.local.md` is a personal git-ignored override, not the general mechanism (D).
  </AccordionItem>

  <AccordionItem title="Q4 · A team wants a destructive command family such as `rm -rf` to be blocked deterministically for everyone, and they also want the block enforced even if a developer tries to allow it. Which TWO steps achieve this? (Select two)">
    A. Add `Bash(rm -rf:*)` to `permissions.deny` in the checked-in `.claude/settings.json`.
    B. Write 'never run rm -rf' in `./CLAUDE.md`.
    C. Enforce the deny through managed policy so it cannot be overridden.
    D. Add a `PostToolUse` hook to apologise after the command runs.
    E. Ask developers to be careful.

    **Answer: A and C.** A `deny` pattern blocks the command family deterministically (`deny` beats `allow`), and putting it in managed policy makes it non-overridable. Prose in `CLAUDE.md` (B) is guidance, not enforcement; a `PostToolUse` hook (D) fires after the damage; asking developers (E) is not a control.
  </AccordionItem>

  <AccordionItem title="Q5 · You want Claude to automatically reach for a documented house style whenever it writes API reference docs, without the developer having to invoke anything. Which component fits? (Select one)">
    A. A slash command in `.claude/commands/`.
    B. A Skill (`.claude/skills/api-docs/SKILL.md`) with a name and description, loaded on demand.
    C. A subagent with its own model.
    D. A line in `settings.local.json`.

    **Answer: B.** Skills load progressively and automatically when their description matches the task — exactly 'reach for it when relevant'. A slash command (A) must be typed by the user; a subagent (C) is for isolated delegated work with its own context; a settings file (D) does not carry authored capability content.
  </AccordionItem>

  <AccordionItem title="Q6 · A developer wants `/fix-issue 482` to investigate and fix GitHub issue 482. How is the issue number passed into the command definition? (Select one)">
    A. It is read from an environment variable automatically.
    B. Via `$ARGUMENTS` in the `.claude/commands/fix-issue.md` file.
    C. Through the subagent's tools allowlist.
    D. It cannot take arguments; commands are static.

    **Answer: B.** Custom slash commands substitute the text after the command name into `$ARGUMENTS`. It is not an env var (A); the tools allowlist (C) governs subagent permissions, not command arguments; commands do accept arguments (D).
  </AccordionItem>

  <AccordionItem title="Q7 · A reviewer subagent should read and analyse code but must never modify files, and should use a stronger model for judgement. Which configuration is correct? (Select one)">
    A. `tools: Read, Grep, Glob` and `model: claude-opus-5` in `.claude/agents/reviewer.md`.
    B. Give it all tools and rely on a prompt saying 'do not edit'.
    C. Put it in `.claude/commands/` with `$ARGUMENTS`.
    D. Set `bypassPermissions` so it runs without friction.

    **Answer: A.** A subagent takes an explicit tools allowlist and its own model; restricting to read tools enforces the no-edit rule, and Opus 5 provides stronger judgement. A prompt-only rule (B) is not enforcement; a slash command (C) is not an isolated agent; `bypassPermissions` (D) removes the very safeguards you want.
  </AccordionItem>

  <AccordionItem title="Q8 · During a long session, context is nearly full but the developer wants to keep the working narrative and continue. Which command is appropriate, and how does it differ from the alternative? (Select one)">
    A. `/clear`, because it frees the most space.
    B. `/compact`, which summarises server-side while preserving the narrative; `/clear` would discard the conversation entirely.
    C. `/init`, to rebuild context.
    D. `/memory`, to erase old turns.

    **Answer: B.** `/compact` summarises to free context while keeping continuity; `/clear` resets everything and loses the narrative. `/init` (C) bootstraps a `CLAUDE.md`; `/memory` (D) edits memory files, not the live transcript.
  </AccordionItem>

  <AccordionItem title="Q9 · A team wants a vetted set of MCP servers shared across the repo and checked into version control. Which scope should they use? (Select one)">
    A. `local` scope.
    B. `user` scope.
    C. `project` scope via `.mcp.json`, committed to the repo.
    D. There is no way to share MCP servers.

    **Answer: C.** Project scope stores servers in `.mcp.json` in the repository, making a shared, vetted catalogue available team-wide. `local` (A) is personal to one machine/project; `user` (B) spans only your own projects; sharing is clearly possible (D).
  </AccordionItem>

  <AccordionItem title="Q10 · Before a large automated migration across many files, what is the safest first step in Claude Code? (Select one)">
    A. Apply all edits immediately, then review the diff.
    B. Use plan mode (Shift+Tab or `--permission-mode plan`) to explore read-only and produce a plan, then approve and apply with tests.
    C. Set `bypassPermissions` to move quickly.
    D. Delete the tests to avoid noise.

    **Answer: B.** Plan mode explores without editing and yields a reviewable plan, reducing blast radius on large changes. Applying blindly (A), bypassing permissions (C), and removing tests (D) all increase risk.
  </AccordionItem>

  <AccordionItem title="Q11 · Which TWO practices correctly enforce a critical rule and manage tool access in Claude Code? (Select two)">
    A. A `PreToolUse` hook that exits with code 2 to block a forbidden command.
    B. A `permissions.deny` pattern for the forbidden command.
    C. A paragraph in `CLAUDE.md` describing the rule.
    D. `tool_choice` set in the prompt text.
    E. Trusting the model to remember the instruction.

    **Answer: A and B.** A `PreToolUse` hook returning exit code 2 blocks the action deterministically, and a `deny` pattern refuses the tool outright — both are enforcement. Prose in `CLAUDE.md` (C) and reliance on memory (E) are guidance, not control; `tool_choice` (D) is an API parameter, not a Claude Code permission mechanism.
  </AccordionItem>

  <AccordionItem title="Q12 · A developer wants personal experimental instructions that must never be committed or shared with teammates. Where do they belong? (Select one)">
    A. `./CLAUDE.md`.
    B. Managed policy.
    C. `CLAUDE.local.md` (git-ignored) or `settings.local.json`.
    D. `.mcp.json`.

    **Answer: C.** `CLAUDE.local.md` and `settings.local.json` are git-ignored personal overrides — the right home for un-shared experiments. `./CLAUDE.md` (A) is checked in and shared; managed policy (B) is org-wide and non-overridable; `.mcp.json` (D) configures MCP servers, not instructions.
  </AccordionItem>

  <AccordionItem title="Q13 · A tool matches both an `allow` and a `deny` pattern in the resolved settings. What happens? (Select one)">
    A. `allow` wins because it is listed first.
    B. `deny` wins; resolution is deny > ask > allow.
    C. The tool prompts the user every time.
    D. Behaviour is undefined.

    **Answer: B.** `deny` beats `allow` in permission resolution. Ordering does not decide it (A); it is denied, not an `ask` prompt (C); and the behaviour is well-defined (D).
  </AccordionItem>

  <AccordionItem title="Q14 · Security needs `rm -rf` blocked for everyone with no developer able to override it. Where must the `deny` rule live? (Select one)">
    A. In each developer's `settings.local.json`.
    B. In managed/enterprise policy, which is non-overridable and beats `allow`.
    C. In `./CLAUDE.md` as a sentence.
    D. In a `PostToolUse` hook.

    **Answer: B.** Only managed policy is non-overridable by user/project/local config. Local files (A) can be changed by the developer; a `CLAUDE.md` sentence (C) is prose, not enforcement; a `PostToolUse` hook (D) fires after the command runs.
  </AccordionItem>

  <AccordionItem title="Q15 · A CI job must run non-interactively, output machine-readable results, and never edit files. Which invocation fits BEST? (Select one)">
    A. `claude` interactive with plan mode.
    B. `claude -p "..." --output-format json --allowedTools "Read,Grep,Glob" --permission-mode plan`.
    C. `claude -p "..." --permission-mode bypassPermissions`.
    D. Claude Desktop with MCP.

    **Answer: B.** Headless `-p` with JSON output, a read-only allowlist, and plan mode is non-interactive, machine-readable and edit-free. Interactive plan mode (A) and Desktop (D) are not headless; `bypassPermissions` (C) removes safeguards and does not guarantee read-only.
  </AccordionItem>

  <AccordionItem title="Q16 · A developer adds 'never force-push' to `./CLAUDE.md` and expects it to be enforced. Why is this insufficient, and what should they do? (Select one)">
    A. It is sufficient; `CLAUDE.md` rules are enforced.
    B. `CLAUDE.md` is guidance, not enforcement; add `Bash(git push --force:*)` to `permissions.deny` (ideally via managed policy) or a PreToolUse hook.
    C. Move the sentence to `settings.local.json`.
    D. Raise the model's effort level.

    **Answer: B.** Prose in `CLAUDE.md` is a suggestion (anti-pattern #3 in Claude Code form); a `deny` pattern or PreToolUse hook enforces it deterministically. It is not sufficient (A); a local file (C) is personal and not enforcement; effort (D) is irrelevant.
  </AccordionItem>

  <AccordionItem title="Q17 · During a long session context is nearly full but the developer must keep the working narrative. Which command fits, and how does it differ from the alternative? (Select one)">
    A. `/clear`, because it frees the most space.
    B. `/compact`, which summarises server-side while preserving the narrative; `/clear` would discard the conversation entirely.
    C. `/init`, to rebuild context.
    D. `/memory`, to erase old turns.

    **Answer: B.** `/compact` summarises to free context while keeping continuity; `/clear` resets everything. `/init` (C) bootstraps a `CLAUDE.md`; `/memory` (D) edits memory files, not the live transcript.
  </AccordionItem>

  <AccordionItem title="Q18 · A team wants coding standards shared with everyone, but one developer needs a personal experimental instruction that must never be committed. Where does each belong? (Select one)">
    A. Both in `./CLAUDE.md`.
    B. Standards in checked-in `./CLAUDE.md`; the personal experiment in git-ignored `CLAUDE.local.md`.
    C. Both in `settings.local.json`.
    D. Both in managed policy.

    **Answer: B.** Team standards go in the checked-in project file; personal, un-shared instructions go in the git-ignored local file. Putting the personal item in `./CLAUDE.md` (A) shares it; local files (C) would hide the team standards from others; managed policy (D) is for non-overridable org rules, not personal experiments.
  </AccordionItem>
</Accordions>

## Key takeaways

- Core components: Rules/`CLAUDE.md`, Skills, Commands, Agents/subagents, Agent Memory.
- `CLAUDE.md` precedence composes broad→narrow: managed → user → project → subdirectory; `CLAUDE.local.md` is git-ignored; `@path` imports pull in shared files; secrets never belong here.
- `settings.json` composes across the same scopes; `permissions` (`allow`/`ask`/`deny`) enforce tools deterministically; **`deny` beats `allow`** and managed policy is non-overridable.
- Hooks (PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStop, SessionStart, Notification, PreCompact) are deterministic; **exit code 2 blocks** the action — the way to enforce critical rules instead of prose.
- Skill = auto/progressive capability; slash command = user-invoked prompt with `$ARGUMENTS`; subagent = isolated context with its own prompt, tools allowlist and model.
- Plan mode explores read-only and proposes a plan before edits — the safe first step for large/risky changes.
- Headless `-p` + `--output-format json|stream-json` + `--allowedTools` + `--permission-mode` for CI; `bypassPermissions` only in a trusted sandbox.
- Session commands: `/compact` (summarise, keep narrative) vs `/clear` (reset); `/init`, `/memory`, `/agents`, `/hooks`, `/mcp`, `/cost`. MCP scopes: `local` (personal), `project` (`.mcp.json`, shared/checked-in), `user` (your projects).
- Permission resolution is **deny > ask > allow**, composing broad→narrow, with managed policy non-overridable — a non-overridable block must live in managed policy, not project or local settings.
- Both `CLAUDE.md` and `settings.json` compose across the same scopes; team standards go in checked-in project files, personal items in git-ignored local files, and secrets in neither.
- A rule you need enforced is a `deny` pattern or a hook, never a `CLAUDE.md` sentence (anti-pattern #3 in Claude Code form).
