Prelude

Many developers spend months writing system prompts before ever opening a CLAUDE.md file. When first building with the Anthropic API, the system prompt feels like everything. It is where you define Claude's personality, set constraints, structure output formats, and establish the rules of engagement. Every API call starts with a carefully crafted system parameter.

Then Claude Code enters the picture. People talk about CLAUDE.md files, and the natural assumption is that they are just another name for system prompts. A file where you put your instructions, Claude reads them, and it follows them. Same thing, different packaging. Right?

Wrong. It takes many developers an embarrassingly long time to realise that system prompts and CLAUDE.md files are fundamentally different mechanisms that serve completely different purposes. They operate at different layers of the stack, load into different parts of the context window, and solve different problems. Once this distinction clicks, it changes how you structure every AI workflow you build.

This guide is the explanation we wish had existed from the start. If you are building applications with the Anthropic API, using Claude Code for development, or trying to figure out where your instructions should live, this is for you.

The Problem

The confusion is understandable. Both system prompts and CLAUDE.md files contain instructions that shape Claude's behaviour. Both are written in natural language. Both influence how Claude responds to you. From the outside, they look like the same concept wearing different clothes.

But they are not. A system prompt is an API parameter you send with every request. A CLAUDE.md file is a persistent document that Claude Code reads from your filesystem. They load at different times, occupy different positions in the context window, and have different scopes.

Mixing them up leads to real problems. We have seen developers try to put API-level behaviour rules in CLAUDE.md, and others try to encode project architecture decisions in system prompts. Neither approach works well.

The distinction matters because choosing the wrong mechanism means your instructions either get ignored, waste tokens, or create conflicts with the tool's built-in behaviour. Understanding when to use each one, and how they can work together, is one of those foundational skills that makes everything else easier.

The Journey

What System Prompts Actually Are

A system prompt is a parameter you pass to the Anthropic Messages API. It is the system field in your API call, and it gets processed before any user messages. Here is what it looks like in practice:

client.messages.create(
    model="claude-opus-4-6",
    max_tokens=1024,
    system="You are a helpful coding assistant specialising in Python. Always provide code examples with type hints. When you don't know something, say so directly rather than guessing.",
    messages=[
        {"role": "user", "content": "How do I sort a list of dictionaries by a specific key?"}
    ],
)

The system prompt sits at the very beginning of the context window, before any conversation history. Claude processes it first, which gives it a privileged position in shaping the model's behaviour. This is where you define the role Claude should play, the constraints it should follow, and the format of its responses.

Here is the critical thing about system prompts. Every API request is stateless. The API does not remember your previous calls. If you send a system prompt with one request, it has zero effect on the next request unless you include it again.

This means your application code is responsible for attaching the system prompt to every single API call. There is no persistence, no memory, no carry-over.

This statelessness is actually a feature, not a limitation. It means you can dynamically adjust the system prompt based on context. You can swap out persona definitions depending on who the user is. You can add or remove constraints based on the conversation stage. You have complete programmatic control over what Claude sees at the system level for every individual request.

System prompts are also invisible to the end user in most applications. The person chatting with your Claude-powered app never sees the system prompt, they only see the conversation. This makes system prompts ideal for defining behind-the-scenes behaviour that users should not be aware of or able to modify.

For real-world system prompt patterns, check out our system prompt library with templates for common use cases.

What CLAUDE.md Actually Does

CLAUDE.md is a completely different beast. It is a markdown file that lives on your filesystem, either in your project root, your home directory, or a managed system path. Claude Code reads it automatically at the start of every session, and its contents become part of the context that Claude Code uses to understand your project.

Here is a simple example of what a CLAUDE.md file might contain:

# My Project

## Build Commands
- `npm run build` to compile TypeScript
- `npm test` to run the test suite
- `npm run lint` to check code style

## Architecture
- This is a monorepo with packages in /packages
- Shared types live in /packages/common
- API routes are in /packages/api/src/routes

## Coding Standards
- Use arrow functions, not function declarations
- All new code must have tests
- British English in user-facing strings

Notice the difference? This is not about defining Claude's personality or constraining its output format. It is about giving Claude Code the context it needs to work effectively in your specific project. Build commands, architecture decisions, coding standards, file locations. The kind of information a new team member would need on their first day.

CLAUDE.md does not replace Claude Code's built-in system prompt. Claude Code already has its own system prompt that defines how it behaves as a coding assistant, how it uses tools, and how it interacts with your filesystem. Your CLAUDE.md file adds to this. It provides the project-specific layer that Claude Code cannot know about on its own.

This is worth repeating because it is the single biggest misconception we encounter. CLAUDE.md does not replace the system prompt in Claude Code. It supplements it. The two operate at different layers.

The Key Differences

Here is a side-by-side comparison that captures the essential distinctions:

Dimension System Prompt CLAUDE.md
Where it lives Application code, the system parameter File on disk (./CLAUDE.md, ~/.claude/CLAUDE.md)
Who writes it Application developer Developer or team
Scope Single API request (stateless) Persistent across all sessions in a project
How it loads Sent explicitly per API call Auto-read by Claude Code at session start
Position in context Processed first, before all messages Loaded as early context after the system prompt
Hierarchy Flat (one per request) Hierarchical with managed, project, user, and local levels
Typical content Role definition, behavioural rules, output format Build commands, coding standards, architecture rules
Token cost Counted on every request Counted on every Claude Code session

Here are the most important rows unpacked.

Scope is perhaps the biggest practical difference. A system prompt lives and dies with a single API call. When that request completes, the system prompt is gone. Your next API call starts from scratch. CLAUDE.md, on the other hand, persists on your filesystem. Every time you start a Claude Code session in that project, the file is there, ready to be read. You write it once and it works for months.

Position in context matters more than people realise. The system prompt occupies the privileged first position in the context window. It is processed before any user messages, which gives it strong influence over Claude's behaviour. CLAUDE.md content is injected as early user-turn context, after the system prompt. It still has significant influence, but it is working within the framework that Claude Code's own system prompt has already established.

Hierarchy is unique to CLAUDE.md. System prompts are flat. You get one per request, and that is it. CLAUDE.md supports multiple levels that layer on top of each other, as explained in detail below.

Where CLAUDE.md Sits in the Context Window

Understanding exactly where CLAUDE.md content appears in the context window clears up a lot of confusion.

When you start a Claude Code session, here is roughly what the context looks like:

  1. Claude Code's built-in system prompt (defines tool usage, safety rules, coding assistant behaviour)
  2. CLAUDE.md content (injected as early context, after the system prompt)
  3. Your conversation (the commands you type and Claude's responses)

So CLAUDE.md does not replace the system prompt. It does not even appear in the system prompt position. It appears after it, as additional context that informs Claude Code about your specific project. Think of it as a briefing document that Claude reads after it already knows how to be a coding assistant, but before it starts working on your tasks.

This positioning has practical implications. If your CLAUDE.md says something that conflicts with Claude Code's built-in system prompt, the system prompt generally wins. You cannot use CLAUDE.md to override safety rules or fundamentally change how Claude Code operates. What you can do is provide project-specific information, preferences, and conventions that Claude Code would not otherwise know about.

The CLAUDE.md Hierarchy

One of the most powerful features of CLAUDE.md is its hierarchical loading system. Multiple CLAUDE.md files can exist at different levels, and they all get loaded and combined. Here is the hierarchy from highest to lowest priority:

  1. Managed policy lives at /etc/claude-code/CLAUDE.md on Linux or /Library/Application Support/ClaudeCode/CLAUDE.md on macOS. This is for organisation-wide policies that administrators set. Individual developers cannot override these.

  2. Project-level is ./CLAUDE.md or ./.claude/CLAUDE.md in your project root. This is the most common location. It contains project-specific instructions and gets committed to git so the whole team shares it.

  3. User-level is ~/.claude/CLAUDE.md in your home directory. This contains your personal preferences that apply across all projects. Things like your preferred code style, your editor shortcuts, or how verbose you want explanations to be.

  4. Local is ./CLAUDE.local.md in your project root. This is for personal overrides that you do not want to commit to git. Maybe you prefer different formatting than your team, or you have local paths that are specific to your machine.

All four levels get loaded and combined. If there is a conflict, higher-priority levels generally take precedence. This hierarchy means a team can share project-level instructions via git while individual developers maintain their own preferences without conflicts.

Beyond the hierarchy, Claude Code also supports .claude/rules/ directories. These contain modular rule files that can be scoped to specific file paths using glob patterns. For example, you might have a rule that only applies when working on test files, or a rule specific to your API routes directory. This granular scoping keeps your main CLAUDE.md file focused and avoids loading irrelevant instructions.

When to Use System Prompts

System prompts are the right choice when you are building an application that calls the Anthropic Messages API directly. Here are the scenarios where system prompts shine:

Custom chatbots and assistants. If you are building a customer support bot, a writing assistant, or any conversational application, the system prompt is where you define the persona, tone, and behavioural rules. "You are a friendly customer support agent for Acme Corp. Never discuss competitor products. Always offer to escalate to a human if the customer seems frustrated."

API-powered agents. When building autonomous agents that use Claude for reasoning, the system prompt frames each reasoning step. You might change the system prompt depending on which phase of the agent loop you are in, giving Claude different instructions for planning versus execution versus evaluation.

Dynamic per-request customisation. Because system prompts are stateless and sent with every request, you can change them dynamically. A multi-tenant application might include tenant-specific rules in the system prompt. A content platform might adjust the system prompt based on the content type being generated.

Output format control. System prompts are excellent for specifying exact output formats, whether that is JSON schemas, XML structures, or specific markdown conventions. The privileged position at the start of the context window makes format instructions particularly effective.

Guardrails and safety rules. Any behaviour constraints that must be enforced on every interaction belong in the system prompt. Content policies, topic restrictions, disclosure requirements. These need to be present on every request without exception.

The common thread is that system prompts are for programmatic control of Claude's behaviour in applications you build. You are the developer, and the system prompt is your control surface.

For practical examples of how system prompts fit into daily development, see the daily workflows guide which covers patterns for both system prompts and Claude Code.

When to Use CLAUDE.md

CLAUDE.md is the right choice when you are using Claude Code as your development tool. Here are the scenarios where CLAUDE.md files excel:

Project onboarding. The most valuable content in a CLAUDE.md file is the information a new developer would need to start working in your codebase. Build commands, test commands, the project structure, key architectural decisions. Claude Code reads this and immediately understands how to work in your project without you having to explain it every session.

Team coding standards. If your team has agreed on specific patterns, conventions, or rules, put them in the project-level CLAUDE.md and commit it to git. "Use arrow functions, not function declarations." "All database queries go through the repository layer." "British English in user-facing strings." Every developer on the team gets the same instructions, and Claude Code follows them consistently.

Architecture documentation. Not a full architecture document, but the key decisions that affect day-to-day development. "This is a monorepo. Shared types live in /packages/common. The API uses the repository pattern." Claude Code uses this to make better decisions about where to put new code and how to structure changes.

Build and deployment workflows. Commands for building, testing, linting, deploying. Claude Code can run these commands, and having them documented in CLAUDE.md means it knows the right commands for your specific project without guessing.

Critical rules. Every project has a few rules that must never be broken. "Never modify the core/ directory, it is a git submodule." "CSS files go in storage/files/css/, never in extensions/." These go at the top of your CLAUDE.md where they have maximum visibility.

The common thread is that CLAUDE.md is for project context that helps Claude Code work effectively in your specific codebase. You are giving it the knowledge it needs, not programming its personality.

Using Both Together

Here is where things get interesting. If you are building an application that uses the Anthropic API, and you are using Claude Code to develop that application, you are using both mechanisms simultaneously.

Your CLAUDE.md file tells Claude Code how to work in your codebase. "The system prompt templates live in /src/prompts. We use Jinja2 for template rendering. Run pytest to test prompt changes."

Your system prompts, the ones your application sends to the API, define how Claude behaves for your end users. "You are a helpful writing assistant. Respond in the user's language. Keep responses under 200 words."

These two mechanisms operate at completely different layers and never interact directly. CLAUDE.md shapes your development experience. System prompts shape your users' experience. They coexist naturally because they solve different problems.

This layered approach is extremely powerful. When building a new feature for an API-powered application, Claude Code understands your project structure and coding conventions through CLAUDE.md, while you are simultaneously crafting and testing system prompts that will control Claude's behaviour in the deployed application. The two concerns stay cleanly separated.

There is one subtle interaction worth noting. If you store your system prompt templates as files in your project (which we recommend), Claude Code can see and edit them. You might ask Claude Code to "update the system prompt for the customer support agent to be more concise," and it will modify the template file in your project. Claude Code is helping you write system prompts, guided by the project context in your CLAUDE.md. It is meta in the best way.

Best Practices for System Prompts

After writing hundreds of system prompts across different applications, here are the practices that prove most effective. These align closely with Anthropic's official guidance.

Be clear and direct. Claude responds best to straightforward instructions. Instead of "It would be nice if you could try to keep your responses somewhat brief," write "Keep responses under 150 words." Specificity beats vagueness every time.

Give Claude a role. Starting your system prompt with a role definition sets the frame for everything that follows. "You are an expert Python developer who specialises in data pipelines" gives Claude a clear identity to inhabit. This is more effective than listing disconnected rules.

Use XML tags for structure. When your system prompt contains multiple sections, XML tags help Claude parse the structure reliably.

<role>You are a technical documentation writer for a developer tools company.</role>

<rules>
- Write in active voice
- Use British English
- Include code examples for every concept
- Target an intermediate developer audience
</rules>

<output_format>
Return documentation in markdown format with H2 headers for each section.
</output_format>

The tags create clear boundaries between different types of instructions, which helps Claude follow them more reliably.

Add context and motivation. Do not just tell Claude what to do. Tell it why. "Keep responses under 100 words because these appear in a mobile notification where space is limited." The motivation helps Claude make better judgement calls in edge cases where the literal rule might not apply perfectly.

Put longform reference data at the top. If your system prompt includes reference material like product catalogues, API documentation, or example data, put it at the beginning. Put your instructions and queries at the end. This structure, sometimes called "long context prompt design," helps Claude process the reference material as context before encountering the task.

Use examples for complex tasks. If you need Claude to produce a specific output format or follow a particular reasoning pattern, include a worked example. One good example is worth a paragraph of description.

<example>
User: What's your return policy?
Assistant: We offer free returns within 30 days of purchase. Just bring your receipt to any store location, or start a return online at acme.com/returns. Would you like me to help you start a return?
</example>

Dial back aggressive language for newer models. Claude Opus 4.6 is more responsive to instructions than earlier models. You do not need to use emphatic phrases like "YOU MUST ALWAYS" or "NEVER EVER." Clear, direct statements work just as well and waste fewer tokens.

Test systematically. Do not just try your system prompt once and call it done. Test it with a variety of inputs, including edge cases and adversarial inputs. Keeping a test suite for system prompts, just like tests for application code, pays dividends over time.

Best Practices for CLAUDE.md

Writing a good CLAUDE.md file is a different skill from writing good system prompts. Here is what we have learned from optimising CLAUDE.md files across multiple projects.

Target under 200 lines per file. CLAUDE.md content gets loaded into the context window on every session. Longer files eat into the context you need for actual work. Be concise and focused. If you find your CLAUDE.md growing past 200 lines, it is time to move content into .claude/rules/ files or Skills.

How many lines should your CLAUDE.md be? Anthropic recommends keeping it under 200 lines. In practice, 50 to 100 lines covers most projects well. The key is to include only information that Claude Code needs on every session. Anything that is only relevant to specific files or tasks should go in scoped rules instead.

Put critical rules first. Claude Code reads the whole file, but emphasis matters. Your most important rules, the ones that must never be violated, go at the top. A recommended pattern is to title the first section "Critical Rules" containing the non-negotiable constraints.

Write specific, verifiable instructions. "Write clean code" is useless. "Use arrow functions, not function declarations" is specific and verifiable. Claude Code can follow concrete rules. It cannot follow vague aspirations.

Use markdown structure. Headers, bullet points, and code blocks make your CLAUDE.md easier for both Claude and humans to parse. H2 headers work well for major sections and bullet points for individual rules.

Use /init to get started. If you are creating a CLAUDE.md for an existing project, Claude Code's /init command analyses your project and generates a starting file. It is not perfect, but it gives you a solid foundation to edit rather than starting from a blank page.

Commit your project CLAUDE.md to git. Your project-level CLAUDE.md belongs in version control so the whole team benefits from it. Use CLAUDE.local.md for personal preferences that should not be shared.

Use .claude/rules/ for modular instructions. Instead of cramming everything into one file, create focused rule files in the .claude/rules/ directory. You can scope rules to specific file paths using glob patterns in the frontmatter. A rule file for test patterns might only apply when Claude Code is working on files matching **/*.test.ts. This keeps instructions relevant and reduces noise.

What goes in CLAUDE.md vs .claude/rules/ vs Skills? The answer comes down to scope and frequency. CLAUDE.md holds instructions that apply to every session and every file in the project. Rules in .claude/rules/ hold instructions scoped to specific file types or directories.

Skills hold domain knowledge and complex procedures that are loaded on demand, not on every session. If Claude Code only needs the information sometimes, it should not be in CLAUDE.md.

Iterate based on real usage. Your CLAUDE.md is a living document. When you notice Claude Code doing something wrong or asking for information it should already have, update the file. When you find yourself repeating the same instruction across multiple sessions, add it. The best CLAUDE.md files are refined over weeks and months of actual usage.

Keep personal preferences in the user-level file. Your ~/.claude/CLAUDE.md is the right place for instructions that apply across all your projects. Things like "I prefer concise explanations" or "Always show the file path when suggesting edits." These follow you everywhere without cluttering project-level files.

The Lesson

The deeper lesson here is about matching tools to contexts. System prompts and CLAUDE.md are not competing approaches. They are complementary tools designed for different layers of the AI development stack.

System prompts give you programmatic, per-request control over Claude's behaviour in applications you build for others. They are dynamic, stateless, and invisible to users. They define what Claude is for each interaction.

CLAUDE.md gives you persistent, project-level context for Claude Code as your development tool. It is static, shared with your team, and visible to anyone who reads the file. It defines what your project is so Claude Code can work effectively within it.

Do system prompts persist across API calls? No, and that is by design. Every API call to the Messages API is completely independent. Your application must include the system prompt with every request. This statelessness gives you full control, you can change the system prompt dynamically based on any condition your application logic can evaluate.

Does CLAUDE.md replace the system prompt in Claude Code? No. Claude Code has its own built-in system prompt that defines its core behaviour as a coding assistant. Your CLAUDE.md content is loaded as additional context after the system prompt. It adds to Claude Code's knowledge about your project, but it does not override the foundational instructions that make Claude Code work.

Can you use both? Absolutely, and if you are building API-powered applications with Claude Code, you should. CLAUDE.md tells Claude Code how to work in your codebase. System prompts tell your deployed application's Claude how to interact with users. The two mechanisms complement each other perfectly.

The confusion between system prompts and CLAUDE.md is really a symptom of a broader shift in how we work with AI. We are moving from a world where there was one way to instruct an AI model (the prompt) to a world with multiple instruction layers, each serving a different purpose. Understanding these layers, and knowing which one to use when, is becoming a core competency for developers building with AI.

Conclusion

We started this guide by acknowledging that the confusion between system prompts and CLAUDE.md is extremely common. The distinction seems academic at first. Both are just instructions for Claude, right? But once the technical reality becomes clear, that they operate at different layers, load at different times, and serve fundamentally different purposes, everything clicks into place.

If you are building applications with the Anthropic API, invest time in your system prompts. Make them clear, structured, and tested. Use XML tags, provide examples, and include context about why each rule exists. Your system prompts are part of your application code and deserve the same care.

If you are using Claude Code for development, invest time in your CLAUDE.md. Start with /init, keep it under 200 lines, put critical rules first, and commit it to git. Use .claude/rules/ for file-scoped instructions and CLAUDE.local.md for personal preferences. Your CLAUDE.md is the bridge between Claude Code's general capabilities and your specific project's needs.

If you are doing both, and increasingly that is all of us, keep them cleanly separated. CLAUDE.md for your development workflow. System prompts for your users' experience. Two layers, two purposes, one coherent approach to working with Claude.

The tools are different, but the underlying principle is the same. Give Claude the right context, in the right place, at the right time. That is what effective AI development looks like.