← Back to all guides

CLAUDE.md and Settings

─────────────────────────────────────────

Introduction

Claude Code has two configuration mechanisms: CLAUDE.md files that give Claude persistent context about your project, and settings.json files that control permissions and behaviour. Together they let you tailor Claude to your codebase without repeating yourself every session.

If you haven’t set up Claude Code yet, start from Installing Claude Code. If you want a walkthrough of the TUI itself, see Using the Claude Code TUI.

The CLAUDE.md Hierarchy

CLAUDE.md files can exist at five different levels. Claude loads and merges them all, with more specific files adding to (not replacing) broader ones:

LevelPathScope
Enterprise/etc/claude-code/CLAUDE.mdOrganisation-wide policies
User~/.claude/CLAUDE.mdYour personal defaults across all projects
Project./CLAUDE.mdProject root — the main one
Subdirectory./subdir/CLAUDE.mdScoped context for a specific directory
Local./CLAUDE.local.mdPersonal overrides, gitignored
How they combine
All levels are merged together, not overridden. Enterprise and user files provide baseline context, the project file adds project-specific information, subdirectory files layer on scoped details, and local files add your personal preferences. Claude sees all of them.
CLAUDE.local.md
Use CLAUDE.local.md for personal preferences that shouldn’t be committed — things like “I prefer verbose explanations” or “always use bun instead of npm.” Add it to your .gitignore.

What to Put in CLAUDE.md

A good CLAUDE.md gives Claude the same context a new team member would need on their first day. Here’s the kind of information that works well:

  • Project overview — What the project is, what tech stack it uses
  • Build and run commands — How to build, test, lint, and run the project
  • Key paths — Where the important files and directories are
  • Conventions — Coding style, naming conventions, patterns to follow
  • Rules — Things Claude should always or never do

Here’s an example:

CLAUDE.md
12345678910111213141516171819202122232425
# CLAUDE.md

## Project Overview
A REST API built with Go and Chi router, backed by PostgreSQL.

## Commands
- `make run` — Start the dev server
- `make test` — Run all tests
- `make lint` — Run golangci-lint

## Key Paths
- `cmd/api/` — Entry point and server setup
- `internal/handlers/` — HTTP handlers
- `internal/store/` — Database layer (sqlc generated)
- `migrations/` — SQL migration files

## Conventions
- Use structured logging via slog
- Errors wrap with fmt.Errorf("context: %w", err)
- All handlers return (response, error) — the middleware handles error responses
- Tests use testcontainers for database integration tests

## Rules
- Never modify generated files in internal/store/db/
- Always run make lint before suggesting a commit
Keep it concise
CLAUDE.md is loaded into Claude’s context window every session. Aim for under 200 lines. If it’s getting longer, you probably need to split context into subdirectory CLAUDE.md files instead.

You may also see references to AGENTS.md — this is an emerging cross-tool convention that serves the same purpose as CLAUDE.md but is recognised by multiple AI coding tools. Claude Code only reads CLAUDE.md natively, but you can pull in an AGENTS.md by adding @AGENTS.md to your CLAUDE.md or by symlinking it with ln -s AGENTS.md CLAUDE.md.

Nesting CLAUDE.md Files

For larger projects, you can place CLAUDE.md files in subdirectories to provide scoped context. Claude only loads a subdirectory’s CLAUDE.md when it’s working with files in that directory.

Consider a project structure like this:

12345678910111213
my-project/
  CLAUDE.md              # Project-wide context
  src/
    api/
      CLAUDE.md          # API-specific conventions
      handlers/
      middleware/
    frontend/
      CLAUDE.md          # Frontend-specific conventions
      components/
      pages/
  migrations/
    CLAUDE.md            # Migration-specific rules

The root CLAUDE.md covers the whole project. The subdirectory files add specifics:

src/api/CLAUDE.md
123456
# API Conventions

- All handlers follow the func(w, r) signature pattern
- Use chi.URLParam(r, "id") for path parameters
- Validate request bodies with the validator package
- Return JSON errors with the errorResponse helper
src/frontend/CLAUDE.md
123456
# Frontend Conventions

- Components use PascalCase filenames
- State management through Zustand stores in stores/
- All API calls go through the client in lib/api.ts
- Use the cn() utility for conditional classnames

When Claude is editing a file in src/api/handlers/, it sees the root CLAUDE.md and the src/api/CLAUDE.md. When it’s working on the frontend, it picks up the frontend-specific context instead. This keeps each CLAUDE.md focused and avoids bloating the context with irrelevant information.

Anti-Patterns

A few things to avoid:

Don't blow the context budget
  • Don’t paste your entire README — CLAUDE.md should be curated context, not a documentation dump. Claude doesn’t need your project’s marketing copy or contribution guidelines.
  • Don’t duplicate other config — Don’t restate things Claude can read from package.json, tsconfig.json, or other config files. Just tell it where to look.
  • Don’t make it huge — If your CLAUDE.md is over 200 lines, it’s eating into the context window that Claude needs for actual work. Split it into subdirectory files or trim it down.
  • Don’t include volatile information — Don’t put things that change frequently (current sprint goals, ticket numbers). CLAUDE.md should be relatively stable.

Writing Effective Rules

Rules in CLAUDE.md work best when they have clear boundaries. I use these levels:

  • IMPORTANT — Things you want Claude to always keep in mind and consider. “IMPORTANT: This project uses a monorepo — changes in shared/ affect all services.”
  • ALWAYS — Things Claude must do every time, no exceptions. “ALWAYS run make lint before suggesting a commit.”
  • ASK — Things Claude should check with you before doing. “ASK before modifying any migration files.”
  • NEVER — Hard lines Claude must not cross. “NEVER modify generated files in internal/store/db/.”

Being explicit with these keywords helps Claude understand the weight of each instruction. A vague “try not to modify generated files” is much weaker than “NEVER modify generated files.”

CLAUDE.md
12345678
## Rules

- ALWAYS run tests before suggesting changes are complete
- ALWAYS use structured logging via slog, never fmt.Println
- ASK before adding new dependencies
- ASK before modifying the CI pipeline
- NEVER modify generated files in internal/store/db/
- NEVER commit directly to main
Don't rely on rules for security
If you need to prevent Claude from accessing certain files, use deny rules in settings.json rather than CLAUDE.md rules. A settings-level deny is enforced by the permission system and cannot be bypassed. A CLAUDE.md rule is just an instruction — Claude follows it most of the time, but it’s not a hard guarantee.
Never give Claude details of things it shouldn't access
If there are environments, databases, or services you don’t want Claude touching, don’t include their connection details in your project at all. Telling Claude “never connect to the production database” will work most of the time, but occasionally it will go off the rails and do it anyway. If Claude doesn’t know the hostname, credentials, or connection string in the first place, it can’t connect even if it tries. The best security boundary is the absence of information.

Importing Files with @

You can reference files directly in your CLAUDE.md using the @ import syntax:

CLAUDE.md
1234567891011
# Project Overview

A REST API built with Go and Chi router.

## Architecture

For a detailed overview of the system architecture, see @docs/architecture.md

## API Conventions

See @docs/api-conventions.md for request/response patterns and error handling.

When Claude reads the CLAUDE.md it will pull in the contents of the referenced files. This is powerful because it means your CLAUDE.md stays short and readable while still giving Claude access to detailed documentation when it needs it.

You can use this to reference any file in your project — markdown docs, config files, even source files that contain important patterns you want Claude to follow.

Progressive Disclosure

Progressive disclosure is the idea that Claude shouldn’t load everything into context at once, but instead only load what it needs for the current task.

The key insight is that your CLAUDE.md should be an index, not an encyclopedia. Instead of including all of your documentation inline, describe what each document covers and where to find it. Claude is smart enough to go read the relevant files when it’s working on a task that needs that context.

Here’s what this looks like in practice:

CLAUDE.md
123456789101112131415
# Project Overview

A microservices platform with three services: auth, billing, and notifications.

## Documentation

Topic-specific documentation is in the docs/ directory:

- docs/architecture.md — System architecture, service boundaries, data flow
- docs/database.md — Schema conventions, migration process, query patterns
- docs/testing.md — Test strategy, fixtures, integration test setup
- docs/deployment.md — CI/CD pipeline, environment config, rollback process
- docs/api-design.md — Endpoint naming, versioning, error response format

Read the relevant doc before making changes in that area.

Claude sees this on every session — it’s only a few lines in the context window. But when it needs to work on the database layer, it knows to read docs/database.md first. When it’s working on deployment config, it pulls in docs/deployment.md. The information is available on demand without eating into the context budget permanently.

Write docs for Claude, not just humans
Create documentation specifically for Claude’s consumption. These don’t need to be polished or pretty — they need to be information-dense and focused on the things Claude needs to know to work effectively. Conventions, patterns, gotchas, and examples are more valuable than high-level overviews.

This approach scales well. You can have extensive documentation for a large project without any of it impacting Claude’s context window until it’s actually needed. The CLAUDE.md acts as a table of contents, and Claude reads the chapters it needs.

Skills take this further
Claude Code’s skills system builds on progressive disclosure by packaging knowledge and workflows into reusable units that Claude loads on demand. We’ll cover skills in the next guide in this series.

Settings Files

While CLAUDE.md handles context, settings.json handles permissions and behaviour. There are four levels:

LevelPathCommitted?
Enterprise/etc/claude-code/settings.jsonN/A (system)
User~/.claude/settings.jsonNo
Project.claude/settings.jsonYes
Local.claude/settings.local.jsonNo (gitignored)

Here’s what a typical project settings file looks like:

.claude/settings.json
123456789101112131415161718
{
  "permissions": {
    "allow": [
      "Bash(git status)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(just *)",
      "Bash(go test:*)",
      "Bash(go build:*)",
      "Read(*)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push *)",
      "Bash(git reset --hard*)"
    ]
  }
}

The project settings file (.claude/settings.json) should be committed to your repo so the whole team shares the same permission baseline. Use .claude/settings.local.json for personal overrides.

Permission Rules in Detail

The allow and deny arrays accept patterns for specific tools:

  • Bash(pattern) — Match shell commands. Bash(git status) matches exactly, Bash(git diff:*) matches git diff with any arguments.
  • Read(pattern) — Control file read access. Read(*) allows reading everything.
  • Write(pattern) — Control file write access. Write(src/*) allows writes only within src/.
  • Glob patterns — Use * for wildcards. Bash(just *) matches any just command.
Deny always wins
If a command matches both an allow and a deny rule, the deny takes precedence. This is by design — deny rules are your safety net. Put destructive commands in deny and you can be more generous with allow patterns.

Some practical examples:

1234567891011121314151617
{
  "permissions": {
    "allow": [
      "Bash(npm test:*)",
      "Bash(npm run lint:*)",
      "Bash(docker compose *)",
      "Write(src/*)",
      "Write(tests/*)"
    ],
    "deny": [
      "Bash(npm publish*)",
      "Bash(docker compose down*)",
      "Write(*.env*)",
      "Write(.claude/settings.json)"
    ]
  }
}

This setup lets Claude run tests, lint, and manage Docker containers, but blocks it from publishing packages, tearing down containers, touching env files, or modifying its own permission settings.

Enterprise Configuration

For organisations, the /etc/claude-code/ directory provides system-level configuration that applies to all users on the machine:

  • /etc/claude-code/CLAUDE.md — Organisation-wide instructions (coding standards, security policies)
  • /etc/claude-code/settings.json — Organisation-wide permission rules

Enterprise settings cascade the same way — they combine with user and project settings, with deny rules always taking precedence regardless of level. This means a security team can set organisation-wide deny rules (like blocking access to production credentials or preventing certain destructive commands) that individual users and projects cannot override.

Typical enterprise use cases include enforcing code review policies, restricting access to sensitive directories, mandating specific linting or testing commands before any commit suggestions, and ensuring compliance with internal security standards.

Practical Setup Walkthrough

Setting up Claude Code configuration for a new project takes about two minutes:

1. Create your CLAUDE.md at the project root with your project overview, commands, key paths, and conventions.

2. Create the settings directory and file:

bash
×
mkdir -p .claude

3. Add a .claude/settings.json with your permission rules — start permissive with reads and common commands, add deny rules for anything destructive.

4. Add local files to .gitignore:

.gitignore
12
CLAUDE.local.md
.claude/settings.local.json

5. Commit .claude/settings.json and CLAUDE.md so your team shares the same baseline.

Quick start
You don’t need to get everything perfect up front. Start with a minimal CLAUDE.md (project overview + build commands) and a basic settings.json (allow your test runner, deny destructive git commands). You can iterate on both as you discover what Claude needs.

Real-World Example

Here’s the CLAUDE.md from this blog — it’s a Hugo static site with a custom cyberpunk theme. This gives you an idea of what a real, working CLAUDE.md looks like in practice:

CLAUDE.md
123456789101112131415161718192021222324252627
# CLAUDE.md

## Project Overview

This is a Hugo static site blog with a custom cyberpunk theme.
The Hugo project lives in `src/wildev/` (not the repo root).

## Commands

just dev        # Start dev server with drafts and live reload
just build      # Production build with minification
just clean      # Remove public/ and resources/
just new-post TITLE        # Create new post

## Key Paths

- src/wildev/hugo.toml — Hugo config
- src/wildev/assets/css/main.css — Complete theme CSS
- src/wildev/assets/js/main.js — Interactive JS
- src/wildev/layouts/shortcodes/ — Custom shortcodes
- src/wildev/content/ — All markdown content

## Architecture Notes

- No external Hugo theme — everything is custom
- CSS uses custom properties sourced from hugo.toml params
- All assets are minified and fingerprinted through Hugo Pipes

Notice how it’s focused on what Claude needs to know to work effectively in the codebase — not a comprehensive README, just the practical essentials.

Wrapping Up

Start simple: a short CLAUDE.md with your project overview and build commands, a basic settings.json with sensible permission rules. Iterate from there as you notice patterns — if you keep telling Claude the same thing, put it in CLAUDE.md. If you keep approving the same command, add it to your allow list.

The next guide in this series covers the extensibility layer — skills, agents, and MCP servers.

Skills, Agents, and MCP Servers →