# Where each Claude Code instruction belongs

> CLAUDE.md can't enforce never. Hooks, skills, rules and subagents can, and here is when to use each.

Source: https://fullbytedeveloper.com/blog/claude-md-where-instructions-belong
Keyword: WHEREPUT
Published: 2026-10-29

Your `CLAUDE.md` says "never do X", and Claude can still do X. `CLAUDE.md` is guidance; hooks are enforced. Here's where each kind of instruction belongs, per the Claude Code docs.

## Keep CLAUDE.md to facts

Put the facts Claude needs in every session in `CLAUDE.md`: build commands, conventions, project layout. The docs say to target under 200 lines, because longer files use more context and reduce how well Claude follows them [1]. Everything below moves out of it.

```md title="CLAUDE.md"
# my-app

- Build: npm run build
- Test: npm test
- API code lives in src/api, UI in src/ui
```

## Block a never with a PreToolUse hook

A hook runs your script before a tool call. If the script exits with code 2, the call is blocked and whatever it wrote to stderr goes back to Claude as the reason [2]. Add this to `.claude/settings.json`:

```json title=".claude/settings.json"
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
```

Then the script, at `.claude/hooks/protect-files.sh`. Change the pattern to whatever must never be edited:

```bash title=".claude/hooks/protect-files.sh"
#!/bin/bash
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
  *.env|*.env.*|*package-lock.json)
    echo "Blocked: $file is protected" >&2
    exit 2
    ;;
esac
exit 0
```

```bash
chmod +x .claude/hooks/protect-files.sh
```

The script needs `jq` (`brew install jq` on macOS). You should see Claude report "Blocked" when it tries to edit a protected file.

## Run an always with a PostToolUse hook

For "always do Y after edits", run it after the tool instead of asking for it. This formats every file Claude edits, from the docs' own example [2]:

```json title=".claude/settings.json"
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
```

You should see edited files come back formatted without asking.

## Turn a procedure into a skill

A 30 line procedure doesn't belong in every session's context. Put it in a skill, which Claude loads only when it's needed [3]. The folder name becomes the command:

```md title=".claude/skills/release/SKILL.md"
---
description: Release checklist. Use when the user asks to cut or publish a release.
---

1. Run npm test and stop if anything fails.
2. Bump the version in package.json.
3. Update CHANGELOG.md with the merged pull requests.
4. Tag the commit and push the tag.
```

Save it as `.claude/skills/release/SKILL.md`. The `---` must be the file's first line, or Claude Code won't read the frontmatter [3]. You should see `/release` when you type `/`.

## Scope a rule to one folder

A rule that only matters in one part of the repo goes in `.claude/rules/` with a `paths` list, so it only loads when Claude works on matching files [1]:

```md title=".claude/rules/api.md"
---
paths:
  - "src/api/**/*.ts"
---

# API rules

- Every endpoint validates its input.
- Use the standard error response format.
```

Save it as `.claude/rules/api.md`. Rules without `paths` load at the start of every session [1].

## Hand deep work to a subagent

Long searches and log analysis fill the main context with noise. A subagent does the work in its own context window and returns only the result [4]. Save this as `.claude/agents/log-reader.md`:

```md title=".claude/agents/log-reader.md"
---
name: log-reader
description: Reads long logs and test output and reports only the errors and their likely cause.
tools: Read, Grep, Glob
---

Read the logs you are pointed at. Report each distinct error once, with the file and line,
and one sentence on the likely cause. Do not paste whole logs back.
```

Only `name` and `description` are required [4]. You should see Claude hand log questions to `log-reader` and get a short summary back.

Your `CLAUDE.md` is now short, the nevers are enforced by a hook, and everything else loads only when it's needed.

## Sources

1. [Claude Code docs: memory and CLAUDE.md](https://code.claude.com/docs/en/memory)
2. [Claude Code docs: hooks guide](https://code.claude.com/docs/en/hooks-guide)
3. [Claude Code docs: skills](https://code.claude.com/docs/en/skills)
4. [Claude Code docs: subagents](https://code.claude.com/docs/en/sub-agents)

## Original posts

- [TikTok photos](https://www.tiktok.com/@fullbytedeveloper/photo/7702019674044714248)
- [Instagram post](https://www.instagram.com/fullbytedeveloper/p/DfEsGMQG8IR/)
