Most Claude system prompts are written the same way: a paragraph of instructions, some "always do X" rules, a persona definition. Most of them underperform — not because the instructions are wrong, but because they're structured in a way that makes them easy to ignore. Here's what structure, iron laws, and permission modes actually mean in practice.
A system prompt is passed at the start of an API conversation — it sets context before the user says anything. In Claude Code and agentic contexts, CLAUDE.md files serve the same function but are loaded automatically from the filesystem. They're semantically identical: both are instructions Claude reads before taking action.
The practical difference is persistence. A system prompt lives in your code. A CLAUDE.md file lives in the project directory, travels with the codebase, and can be read and updated by the agent itself. This makes CLAUDE.md the better choice for long-running agents and shared projects where instructions need to evolve without code deploys.
Everything in this guide applies to both. Where there's a meaningful difference, it's noted.
The single most impactful structural change is putting the most important instructions at the top. Claude reads system prompts from the beginning, and attention is highest on the early content. Instructions buried at paragraph 7 of a 15-paragraph prompt are reliably followed less consistently than instructions in paragraph 1.
A structure that works:
# [Agent Name]
[One sentence: who this is and what they do]
## CRITICAL: [Most important rule]
[The rule, stated plainly]
## Identity
[Name, persona, communication style]
## Capabilities
[What this agent can do — tools, APIs, permissions]
## Behavior
[How it should behave — tone, format preferences, when to ask vs proceed]
## Memory
[Where to store and retrieve information]
## Iron Laws
[The rules that are never overridden]
The CRITICAL: prefix on section headers that must not be missed is not decoration. It's a reliable attention signal. Reserve it for instructions that, if ignored, cause the most damage — not for everything you care about.
Each section should be as short as it can be while remaining unambiguous. If a section needs more than 5 bullet points, consider whether it's doing too much. Long sections get summarized internally by the model, and the summaries lose specificity. Short, specific instructions survive the full context better than long, vague ones.
Iron laws are instructions that must never be overridden — not by user requests, not by seeming edge cases, not by the model's own judgment about what would be helpful. They're the safety rails for situations where flexibility would cause real harm.
The pattern that works:
NEVER [specific behavior] — instead [what to do instead]
The second half is what separates a functional iron law from a dead end. "NEVER commit secrets to git" leaves the agent stuck. "NEVER commit secrets to git — instead warn the user and suggest using environment variables" gives it a path forward. Iron laws without recovery behavior create confusing refusals.
How to find your real iron laws: run the agent on the hardest version of each task it handles. Note the worst output. Each genuine failure becomes an iron law. If you haven't stress-tested the agent, you don't yet know what the iron laws should be.
3–7 is the working range. Fewer than 3 usually means important cases aren't covered. More than 10 creates a list so long it reads as background noise rather than hard constraints. If you have 15 iron laws, most of them aren't actually iron — they're preferences. Move preferences to the Behavior section.
Claude's default behavior is conservative — it asks for confirmation, hedges on uncertainty, and declines ambiguous requests. For agent contexts where the goal is autonomous operation, the default behavior needs to be explicitly relaxed.
Permission modes are statements that expand what Claude will do without being asked:
## Permissions
- You MAY read any file in /workspace without asking
- You MAY run bash commands that are clearly safe (read-only, no network writes)
- You MAY write to /workspace/output/ without confirming each file
- You MUST ask before: deleting files, making network requests, running commands
that modify system state outside /workspace
The pattern is: explicit permission for the common safe case, explicit requirement to ask for the uncommon dangerous case. Without the permission grants, Claude will ask before every file read, which defeats the purpose of an autonomous agent. Without the explicit "must ask" cases, the agent may proceed on destructive operations you expected it to confirm.
If your agent runs without a human watching (scheduled tasks, automated pipelines), the permission mode needs to account for the absence of a reviewer. Agents in headless contexts should have stricter default restrictions, with explicit permission granted for the exact set of operations they're expected to perform. Broad permissions in headless environments amplify failures — the agent will proceed confidently on things it would have caught in interactive mode.
Claude doesn't retain memory between conversations by default. If your agent needs to remember things — user preferences, past decisions, accumulated knowledge — you need to tell it explicitly how to persist that information and how to retrieve it.
A simple memory instruction that works:
## Memory
- Store important facts in /workspace/memory/MEMORY.md
- Check MEMORY.md at the start of each session for relevant context
- Update MEMORY.md when you learn something that should persist
- Keep MEMORY.md under 500 lines — if it grows larger, split into topic files
and maintain an index
The size limit is not cosmetic. Memory files that grow without bound become less useful as they exceed the context window. The instruction to split and maintain an index prevents the file from becoming unmanageable without requiring external tools.
Facts that change slowly and matter repeatedly: user preferences, recurring contacts, project conventions, lessons learned. Not: conversation history (too verbose), temporary state (gets stale), or facts the agent can look up quickly (wastes memory space). The test: would knowing this at the start of a fresh session meaningfully change what the agent does? If yes, it belongs in memory.
This is a minimal template that covers the essential structure. Fill in the specifics for your agent:
# [Agent Name]
[Agent] is a [role] for [context]. [One sentence on primary function.]
## CRITICAL: [Most important constraint]
[State the constraint. NEVER [X] — instead [Y].]
## Identity
- Name: [Agent Name]
- Handle: [agent-handle]
- Tone: [e.g., direct and professional / casual and friendly]
- Sign messages as: "[Name]"
## Capabilities
- [Tool or permission 1]
- [Tool or permission 2]
- [Tool or permission 3]
## Permissions
- You MAY [safe common action] without asking
- You MAY [safe common action] without asking
- You MUST ask before: [dangerous action], [destructive action]
## Memory
- Store persistent facts in [path]
- Check [path] at session start for context
- Update when you learn [type of information]
## Behavior
- [Format preference]
- [Response length guideline]
- [How to handle uncertainty]
- [When to ask vs proceed]
## Iron Laws
1. NEVER [specific failure mode] — instead [recovery path]
2. NEVER [specific failure mode] — instead [recovery path]
3. NEVER [specific failure mode] — instead [recovery path]