DEV Community

Cover image for What Actually Belongs in CLAUDE.md?
Tony
Tony

Posted on

What Actually Belongs in CLAUDE.md?

I’m Tony. I build and run web products, and I use Claude Code as my main development tool every day. A common problem with coding agents starts when an instruction file grows every time the agent makes a mistake. You add an architecture rule, then a testing reminder, then a preference about formatting, and eventually CLAUDE.md contains permanent policies mixed with notes from tasks nobody remembers.

The problem isn't simply that the file is long. It's that different instructions have different lifetimes, scopes, and purposes, yet we ask the agent to treat them as one document. In this article, I'll show you how I separate project rules, reusable procedures, and temporary task instructions. You'll leave with a minimal Claude Code configuration, a reusable Skill, a task brief template, and a way to test whether the arrangement actually works.

This is the second article in Making Coding Agents Reliable, a series about building, verifying, and maintaining software with coding agents. The article on trusting code you didn't write in this series focuses on verification. Here, we'll focus on the configuration that guides the agent before it starts making changes.

More instructions do not automatically produce better behavior

Consider a TypeScript monorepo with an administrative web application, a multi-tenant API, and two shared packages. The team uses pnpm, enforces tenant isolation in the API, and maintains reusable components separately from application code. These constraints matter, but they don't all need to appear in every instruction the agent reads.

A developer might start with three useful lines in CLAUDE.md and keep adding more whenever an output looks wrong. An unsuccessful component change produces a rule about UI reuse. An incomplete API test produces another testing reminder. Eventually, the file contains instructions that overlap or contradict each other.

For example:

- Always create a separate component for new features.
- Reuse existing components whenever possible.
- Never modify shared components without approval.
- Keep component implementations as small as possible.
- Follow the approach used in the previous reporting task.
Enter fullscreen mode Exit fullscreen mode

These statements don't establish a consistent decision process. The first two can conflict, while the final instruction refers to a task that may no longer be relevant. Adding more language doesn't resolve which instruction should control the next change.

Claude Code's official guidance recommends specific, verifiable instructions and removing outdated or conflicting rules. Conflicting instructions can produce unpredictable choices. I treat this as a maintenance problem rather than something to solve by writing increasingly forceful prompts.

Instruction ownership map

The useful distinction is between information Claude needs for the project, procedures it needs for certain kinds of work, and requirements that apply only to the current task.

Give CLAUDE.md a clear responsibility

I use CLAUDE.md for durable information about the repository and its development expectations. It should help Claude understand where code belongs, which boundaries matter, and what evidence the team expects before calling a change complete. It doesn't need to reproduce the architecture documentation or describe every possible workflow.

Here's the fictional repository we'll use:

.
├── CLAUDE.md
├── apps/
│   ├── admin/
│   └── api/
├── packages/
│   ├── ui/
│   └── shared/
├── .claude/
│   ├── rules/
│   └── skills/
└── docs/
    └── architecture.md
Enter fullscreen mode Exit fullscreen mode

A minimal root CLAUDE.md could look like this:

# Project Instructions

## Repository

TypeScript monorepo managed with pnpm.

- apps/admin: administrative web application
- apps/api: multi-tenant backend API
- packages/ui: reusable UI components
- packages/shared: shared types and utilities

## Boundaries

- Keep application logic inside its application.
- Shared packages must not import application code.
- Check affected consumers before changing public contracts.
- Preserve existing behavior outside the requested scope.

## Workflow

Before editing:
- Identify affected packages.
- Read the relevant implementation and tests.
- Identify assumptions that affect the change.

Before reporting completion:
- Run relevant available checks.
- Report executed commands and their results.
- State which checks were not run.
- Summarize changed behavior and remaining risks.

## Verification

API tests: pnpm -F api test

## References

Architecture: docs/architecture.md
Enter fullscreen mode Exit fullscreen mode

The template establishes useful boundaries without prescribing every implementation step. It also gives the agent a concrete verification command and a reporting contract. The example assumes the API package is named api in its package.json and defines a test script.

Claude Code supports several instruction locations:

Location Responsibility
~/.claude/CLAUDE.md Personal instructions across projects
./CLAUDE.md Shared project instructions
./.claude/CLAUDE.md Alternative shared project location
./CLAUDE.local.md Personal instructions for one project
Managed policy file Organization-managed instructions

Commit shared project instructions so changes can be reviewed. Keep CLAUDE.local.md out of Git by adding it to .gitignore. When Claude Code launches, it loads applicable instruction files in the working directory and its parents, while instructions in subdirectories load when Claude accesses files there.

These files accumulate in context rather than overriding one another. That means a personal preference and a project rule can both appear, even when they disagree. Avoid using multiple files to express competing versions of the same requirement.

Keep area-specific rules out of the root

Tenant isolation is essential for our API, but it doesn't need to accompany every frontend task. Claude Code supports path-scoped instruction files in .claude/rules/. A file with paths frontmatter loads when Claude reads or edits a matching file.

Create .claude/rules/api.md:

---
paths:
  - "apps/api/**/*.ts"
---

# API Rules

- Resolve the authenticated tenant before
  accessing tenant-owned data.
- Scope tenant-owned queries to that tenant.
- Validate authorization before accepting
  a tenant identifier from request input.
- Add tests for authorized and denied access.
- Test cross-tenant access boundaries.
Enter fullscreen mode Exit fullscreen mode

For UI conventions, create a separate file with paths such as packages/ui/**/*.ts and packages/ui/**/*.tsx. Rules without paths frontmatter load at launch, so adding a file to .claude/rules/ doesn't automatically make it conditional. The distinction matters when you want a rule to apply only within a particular part of a monorepo.

Another option is placing CLAUDE.md directly under apps/api/. That keeps instructions near the code they govern. I would choose either approach based on how the team maintains instructions, rather than duplicating the same policies in both.

References are not the same as imports

Claude Code supports @path/to/file imports inside instruction files. Relative paths resolve from the importing file, and imports support up to four nested levels. This helps split documents into manageable files, but importing content doesn't reduce how much context gets loaded.

For a lengthy architecture document, I prefer a reference:

Architecture: docs/architecture.md

Read the relevant sections before changing
module boundaries or public API contracts.
Enter fullscreen mode Exit fullscreen mode

That gives Claude a location to consult without importing the complete document into the initial instruction context. Official guidance also recommends keeping individual instruction files under roughly 200 lines. I treat that as a useful review threshold, not a reason to split one overloaded file into several files that all load together.

Move procedures into Skills

Project rules tell the agent what must remain true. A Skill tells it how to perform a particular kind of work. I use Skills for repeatable activities with recognizable inputs, defined steps, and an output that someone else can inspect.

Suppose the team regularly asks Claude to review API changes before merging. A useful review covers backward compatibility, authentication, tenant isolation, database changes, tests, and API documentation. Putting that entire procedure in the root CLAUDE.md would make Claude carry review instructions even when implementing a button.

A project Skill belongs at:

.claude/
└── skills/
    └── api-review/
        └── SKILL.md
Enter fullscreen mode Exit fullscreen mode

A Skill is centered on SKILL.md, with optional metadata in YAML frontmatter. Claude can use it when relevant or when you invoke it with /api-review. Its description remains available for selection, while its full instructions load when invoked.

Here's a focused example:

---
name: api-review
description: Review API changes before merge, including compatibility, authorization, tenant isolation, migrations, tests, and documentation.
---

# API Review

Review the requested API changes.
Do not modify code, approve, merge, or deploy.

## Input

- Identify the Git base ref for comparison.
- If the base ref is missing, request it.
- Do not select a base ref without confirmation.

## Procedure

1. Identify changed API files and related packages.
2. Read relevant implementation and tests.
3. Check request and response compatibility.
4. Check authentication and authorization.
5. Trace tenant context through data access.
6. Review affected database schema changes.
7. Check relevant tests and documentation.
8. Report evidence and verification gaps.

## Output

For each finding, provide:
- Location
- Issue
- Evidence
- Potential impact
- Recommended action

Also report:
- Areas checked
- Tests executed and their results
- Checks not performed
- Unresolved assumptions

## Boundaries

- Do not change source files.
- Do not approve or merge changes.
- Do not claim a finding without evidence.
Enter fullscreen mode Exit fullscreen mode

This Skill describes a review process rather than encoding the tenant isolation policy itself. The permanent requirement to isolate tenants belongs in the API rules. The Skill defines how to inspect a change against that requirement and report the evidence.

The description deserves particular attention because Claude uses it to decide whether the Skill is relevant. A description such as "Helps with code quality" says very little about when to activate it. "Review API changes before merge" establishes a clearer task boundary.

You can keep additional reference documents or scripts beside SKILL.md when the workflow grows. ${CLAUDE_SKILL_DIR} identifies the Skill directory for referencing those resources. Claude Code recommends keeping the main SKILL.md under 500 lines and moving larger reference material into separate files.

Skills also support disable-model-invocation: true when only the user should invoke them. That is useful for workflows with side effects, such as deployment. The API review example doesn't need that setting, but it still needs appropriate permissions if the workflow uses tools.

Before and after splitting CLAUDE.md

There is an important boundary here: neither CLAUDE.md nor a Skill is an enforcement mechanism. They provide instructions, not guarantees. If a team must prevent an action, Claude Code provides hooks and permissions.deny for enforcement. The article on permissions and MCP tool control in this series covers that distinction in more detail.

Keep temporary instructions close to the task

A temporary requirement shouldn't become permanent project policy merely because the agent needs to follow it carefully. Consider a task to add transaction export for administrators. It may require a date filter, pagination, CSV output, and a specific response contract.

Those requirements belong in the task brief, not in the root instructions. They describe one deliverable rather than how the repository should operate for every feature.

I use a small task-brief.md template:

# Task

## Objective

Describe the behavior to implement.

## Scope

- Allowed applications and packages:
- Files or interfaces to inspect:
- Explicit exclusions:

## Requirements

- Required behavior:
- Input and output contracts:
- Authorization requirements:
- Edge cases:

## Verification

- Tests to add or update:
- Commands to run:
- Expected observable results:

## Delivery

- Summarize implementation.
- Report executed checks.
- Identify unverified behavior.
- Do not expand scope without approval.
Enter fullscreen mode Exit fullscreen mode

You can give Claude this brief directly as part of the task. If requirements change, update that task's instructions rather than continually editing CLAUDE.md. This keeps the shared configuration independent of a particular feature's progress.

The distinction becomes especially useful across multiple development sessions. Claude Code re-reads the project-root CLAUDE.md from disk during compaction, while instructions provided only in conversation can be lost. Durable repository conventions therefore need an appropriate file, while temporary work needs a task artifact that can be supplied again.

Design instructions around observable behavior

A useful instruction changes something you can inspect. "Be careful about security" doesn't establish what the agent should check. "Test cross-tenant requests using data owned by two organizations" describes a concrete verification action.

Here are examples of replacing broad preferences with testable expectations:

Vague instruction Observable instruction
Write clean code Follow existing module boundaries
Be careful with API security Check authentication, authorization, and tenant scoping
Test thoroughly Run pnpm -F api test and report the result
Avoid breaking changes Identify affected API consumers before modifying response contracts
Give a good summary List changed files, executed checks, and unverified behavior

I also avoid instructions that require the agent to claim certainty it cannot establish. Running an API test suite is useful evidence, but it doesn't prove every endpoint is secure. A review report should separate confirmed findings, unverified assumptions, and checks that weren't executed.

For our fictional API, imagine a new endpoint:

GET /reports/export
Enter fullscreen mode Exit fullscreen mode

A successful response isn't enough to demonstrate correct authorization. The implementation must resolve the authenticated organization and keep its data isolated from other organizations. Tests should include an authorized request, an unauthorized request, and an attempted cross-tenant access.

This is where instruction placement and verification meet. The API rule names the invariant, the task brief defines the endpoint's behavior, and the review Skill guides the assessment. Production authorization must still be implemented and enforced by the application.

Test the setup using representative tasks

I wouldn't judge an instruction setup by asking Claude to explain the contents of CLAUDE.md. The useful evidence is what it does when working on a representative change. That includes the files it inspects, the decisions it makes, the code it changes, and the checks it runs.

For a fair comparison, prepare two documented configurations and use the same repository state and task briefs. Configuration A can use an overloaded root instruction file. Configuration B can use the minimal root file, scoped API rules, and the review Skill.

Behavior comparison of two configurations

Define the evaluation criteria before running either setup:

Task Expected evidence
Update a UI component No API-specific review procedure for a UI-only change
Add an API export endpoint Tenant-scoped data access and cross-tenant tests
Change an API response field Identification of affected consumers
Review an API diff Findings supported by file and code evidence
Complete an API change Actual test results and explicit verification gaps

Run the tasks in separate sessions with equivalent starting conditions. Record whether the expected behaviors occurred and whether unrelated changes appeared. Don't treat a polished final explanation as evidence of correct implementation.

For the tenant isolation case, create test fixtures for organizations A and B. Authenticate as an account belonging to A and attempt to retrieve B's data through the relevant endpoint. The expected result is that the account cannot access B's records, regardless of how request parameters are constructed.

Claude Code provides /context to inspect loaded context and /memory to open memory files. Use /context while testing the scoped rules to check which instructions are available. You can use /init to generate an initial CLAUDE.md, but review its contents against your actual repository before adopting it.

For the Skill, test both positive and negative activation cases. Ask Claude to review an API diff and check whether it uses the workflow. Then ask it to explain a TypeScript type or modify an unrelated UI component and check that it doesn't invoke API review unnecessarily.

Separate activation from execution when investigating failures. If Claude doesn't select the review Skill automatically, invoke /api-review directly and evaluate the resulting procedure. If the procedure still misses required checks, the problem is no longer just Skill selection.

A comparison only becomes useful when you preserve the task, the expected results, and the actual artifacts. I wouldn't claim that a shorter configuration improves reliability by a particular percentage without controlled evidence. The immediate objective is to discover whether the instructions produce the behavior your project needs.

Maintain the configuration like code

Agent instructions deserve the same review discipline as application configuration. When the team moves a package, changes a test command, or modifies an architecture boundary, the corresponding instructions may become incorrect. A perfectly followed outdated rule can still produce the wrong implementation.

Consider moving tenant-owned data access into a different package. The original apps/api/**/*.ts glob may no longer cover the code that needs isolation rules. Someone reviewing that architectural change should also review the scoped instruction files and their tests.

I would assign clear ownership and include these checks in configuration reviews:

  • Does the instruction still describe the repository?
  • Does it belong at this scope?
  • Does another file express a conflicting requirement?
  • Can the expected behavior be observed?
  • Does a representative test cover the requirement?
  • Can the instruction be removed without losing necessary guidance?

I would also avoid adding sensitive credentials or tokens to committed instruction files. Shared configuration should describe where approved credentials come from, not contain their values. Review Skills and supporting scripts before sharing them with the team.

When an instruction repeatedly fails, investigate whether Claude received it, whether it is specific enough, and whether competing instructions exist. Fix the relevant cause rather than adding a second version of the rule. If the requirement demands a hard restriction, move that control into the appropriate enforcement mechanism.

A small starter you can adapt

The complete starter for this example has four essential artifacts:

claude-project-starter/
├── CLAUDE.md
├── skills/
│   └── api-review/
│       └── SKILL.md
├── task-brief.md
└── instruction-placement-checklist.md
Enter fullscreen mode Exit fullscreen mode

Copy CLAUDE.md to your project root and skills/api-review/ into .claude/skills/. Keep task-brief.md as a template for individual tasks. Add .claude/rules/ with scoped files when your repository needs area-specific policies.

The final checklist is the decision process I use when deciding where to place a new instruction:

# Instruction Placement Checklist

1. Is this a durable repository-wide rule?
   -> Project CLAUDE.md

2. Does it apply only to specific code paths?
   -> .claude/rules/ with paths

3. Is it a repeatable, multi-step procedure?
   -> .claude/skills/<name>/SKILL.md

4. Is it specific to one deliverable?
   -> Task brief

5. Is it lengthy reference material?
   -> Documentation, read when needed

6. Is it a personal working preference?
   -> Personal CLAUDE.md or CLAUDE.local.md

7. Must the action be technically blocked?
   -> Hooks or permissions.deny

Before adding the instruction:
- Check for an existing equivalent rule.
- Remove conflicting or obsolete wording.
- Define an observable verification criterion.
- Identify who maintains it.
Enter fullscreen mode Exit fullscreen mode

The goal is not to create the smallest possible collection of instruction files. It's to give every instruction a clear responsibility, scope, and way to verify its effect. A useful CLAUDE.md remains understandable because it contains project knowledge, not every procedure and reminder the team has ever written.

The next article, on context and memory in this series, examines another part of the same problem: what the agent needs to retain, what it can retrieve, and what should remain in the repository. For now, take one instruction from your existing CLAUDE.md and apply the checklist. Decide whether it describes the project, a procedure, or a temporary task, then test the behavior it is supposed to produce.

What's one instruction you added to CLAUDE.md that probably doesn't belong there anymore?

Top comments (0)