A conversation with Claude has two parts. Above it sits one standing block of instructions, present on every turn, which is called the system prompt. Below that runs the transcript: your messages, Claude’s replies, tool results, in the order they happened.
Everything you have written so far reaches the model as text, and what changes between the surfaces is which of those two parts the text lands in. Text in the system prompt frames every turn. Text in a user message is one more thing in the transcript, competing with the diff you just pasted and the eighty tool results after it.
Four CLI flags write directly into the system prompt.
| Flag | What it does | Example |
|---|---|---|
—system-prompt | Replaces the entire default prompt | claude —system-prompt “You are a Python expert” |
—system-prompt-file | Replaces it with the contents of a file | claude —system-prompt-file ./prompts/review.txt |
—append-system-prompt | Appends to the default prompt | claude —append-system-prompt “Always use TypeScript” |
—append-system-prompt-file | Appends the contents of a file | claude —append-system-prompt-file ./style-rules.txt |
All four work whether you are chatting in the terminal or handing Claude one prompt from a script, the interactive and non-interactive modes. The two replacement flags are mutually exclusive with each other; either one can be combined with an append flag. And all four apply only to the invocation you typed them on, so nothing you do here persists into your next session.
Replacing drops all of the default prompt, tool guidance and safety instructions included, so you take responsibility for whatever your task still needs. That includes how tools are called, when to ask before doing something destructive, and every behaviour you have been treating as ambient. --system-prompt "You are a Python expert" produces a model that knows Python and very little about being an agent in your terminal. Reach for append unless you have a specific reason not to.
There is a fifth flag for the layer below. --append-subagent-system-prompt appends text to every subagent’s system prompt, works in -p mode only, and requires v2.1.205 or later. It does not apply to a forked subagent, which inherits the parent’s prompt instead. Forked means started from the session you are already in rather than started fresh, and inherits means it receives that session’s prompt automatically instead of being given one of its own.
Output styles
An output style is a markdown file that changes how Claude works and talks, and the mechanism is the same one the flags use: Claude Code adds each output style’s custom instructions to the end of the system prompt.
One consequence catches everyone. A custom output style leaves out Claude Code’s built-in software engineering instructions unless keep-coding-instructions is set to true. So a custom style is a partial replacement rather than an addition: it drops the coding block and keeps the rest of the harness prompt. That default is false.
The command surface moved recently, and older writing about this is wrong. The standalone /output-style command was deprecated in v2.1.73 and removed in v2.1.91. You select a style through /config under Output style, which writes the choice to .claude/settings.local.json, or you set outputStyle directly in any settings file. Either way, changes take effect after /clear or in a new session, because outputStyle is one of the keys read once at session start.
Built-in styles: Default, Proactive, Concise (v2.1.237+), Explanatory, Learning.
Custom styles load from ~/.claude/output-styles, .claude/output-styles, the managed settings directory, and a plugin’s output-styles/ folder. Project styles load from every .claude/output-styles/ between your working directory and the repository root, and on a name clash the one nearest your working directory wins.
| Frontmatter | Purpose | Default |
|---|---|---|
name | Name, if not the file name | file name |
description | Shown in the /config picker | none |
keep-coding-instructions | Keep the built-in software engineering instructions | false |
force-for-plugin | Plugin styles only: auto-apply when the plugin is enabled, overriding the user’s outputStyle | false |
Styles apply to the main conversation only. A subagent runs its own system prompt and never sees your style, which you will use deliberately in the next module. A fork is the exception, because it inherits the parent’s full system prompt.
The shape on disk
.claude/output-styles/reviewer.md ships to your plugin Appended to the end of the system prompt. Applies every turn until you change it.
---
name: Reviewer
description: Report findings before making changes
keep-coding-instructions: true
---
Lead with what you found, not what you plan to do.
State each finding as: the file and line, what is wrong,
and what breaks if it stays. Order by what breaks worst.
Do not edit a file until the findings are on screen and
the user has picked one. Read more
keep-coding-instructions: true is here because this style shapes how findings are reported and has no opinion about how code is written. Drop the line and you also drop the built-in software engineering instructions, which is almost never what a style like this intends.
.claude/settings.local.json Where /config writes your style choice. Read once at session start.
{
"outputStyle": "Reviewer"
} Read more
Edit this by hand and the running session keeps the old style. Run /clear or start a new session for it to take.
style-rules.txt Plain text for --append-system-prompt-file. No frontmatter, no name.
Cite an absolute file path with every claim about
the codebase.
When a command fails, quote its exact stderr before
you interpret it. Read more
The file form exists because a long prompt on the command line runs into the operating system argument-length limit. On Linux that failure reads "Argument list too long".
CLAUDE.md Not in the system prompt. Arrives as a user message after it.
# Conventions
Migrations are forward-only.
API handlers return typed errors, never raw strings. Read more
Which is why --system-prompt does not remove it: the replacement flags rewrite the system prompt and CLAUDE.md was never there. To actually drop it, use CLAUDE_CODE_DISABLE_CLAUDE_MDS=1, --bare, or --safe-mode.
Where each thing lands
CLAUDE.md is not in the system prompt. The docs put it plainly: CLAUDE.md “adds a user message after the system prompt”. The SDK documentation says the same thing from the other side, that CLAUDE.md is read and injected into the conversation as project context, not into the system prompt.
Two things follow. First, --system-prompt replaces the whole default prompt and your CLAUDE.md still arrives, because it was never in the thing being replaced. If you want it gone, that is CLAUDE_CODE_DISABLE_CLAUDE_MDS=1, --bare, or --safe-mode. Second, when a CLAUDE.md rule and an output style disagree, they are not two instructions of the same kind arguing. One is framing and one is a message in the transcript.
The documented layering order for the main conversation:
- The base, which is either the built-in Claude Code prompt or your
--system-prompt/--system-prompt-filereplacement. - Output style instructions, appended to the end of the system prompt.
--append-system-promptand--append-system-prompt-filetext.CLAUDE.md, injected as a user message after the system prompt.
One further flag interacts with this. --exclude-dynamic-system-prompt-sections moves the working directory, environment info, memory paths, and git-repo flag out of the system prompt and into the first user message, which helps prompt caching. It works only with the default system prompt and is ignored with a custom one.
Picking the mechanism
The docs publish their own comparison:
| Feature | How it works | Use it when |
|---|---|---|
| Output styles | Modifies the system prompt | Different role, tone, or format every turn |
CLAUDE.md | Adds a user message after the system prompt | Project conventions and codebase context |
—append-system-prompt | Appends to the system prompt without removing anything | One-off addition for a single invocation |
| Agents | Subagent with its own system prompt, model, tools | Separately scoped helper |
| Skills | Task-specific instructions loaded when invoked or relevant | Reusable workflow |
Read the rows against modules 3 and 5 and the boundary sharpens. Your CLAUDE.md from module 3 was never framing; it was context. Your skill from module 5 was neither, because its body was absent until something invoked it. An output style is the only one of the three that is in front of the model on turn one and every turn after, with no invocation and no competing transcript around it. That reach is what you pay for it: it is loaded whether the current turn needs it or not.
The SDK, the software development kit you use to drive Claude Code from your own TypeScript or Python program, starts from a different default. When you do not set systemPrompt in TypeScript or system_prompt in Python, the SDK uses a minimal prompt covering tool calling but omitting Claude Code’s coding guidelines. That is not what claude -p does; the CLI uses the full prompt by default. Ask for it explicitly with { type: "preset", preset: "claude_code" }, and add append to that object to extend it.
Write .claude/output-styles/<name>.md with description and a body that describes how you want work reported rather than what to build. Set keep-coding-instructions: true. Select it with /config, then /clear, and confirm the choice landed in .claude/settings.local.json.
Now watch the boundary. Ask a question that a rule in your CLAUDE.md covers and one that only your style covers, and see which shapes the answer more reliably across several turns. Then run one invocation with --append-system-prompt "Cite an absolute file path with every claim" and confirm it applies for that session only.
This directory ships to output-styles/ in your plugin. A plugin style can set force-for-plugin: true to apply itself when the plugin is enabled, which overrides the user’s own outputStyle. Leave it off for now, and remember it exists when you package in module 12.
You write your first custom output style, one paragraph about tone, select it, and start work. Within an hour something is off. Claude stops running the tests it always ran. It edits three files where it used to read first. It writes a plausible answer about a function it never opened. Nothing in your style file says anything about any of that, so you go looking for a bug in your CLAUDE.md.
The style is the bug, and by the mechanism rather than the content. A custom output style leaves out Claude Code’s built-in software engineering instructions unless keep-coding-instructions: true. The default is false, and there is no warning when you select the style, because dropping that block is the documented purpose of the feature for styles that turn Claude into something other than a coding agent.
Add keep-coding-instructions: true to the frontmatter and /clear. Then take the general rule with you: a style that changes how work is reported wants the flag on, and a style that changes what Claude is is the case the default was written for.
The output style file does not. The portability research found no equivalent surface in any of the ten harnesses surveyed, no path to copy it to, and no wrapper that converts it. The --append-system-prompt flags are equally specific to this CLI.
What travels is the distinction, and it is worth more than the file. Every harness in that survey has instruction files, all of them read as context, and none of them documents a user-authorable path into the system prompt itself. So when you move a Claude Code setup outward, an output style’s content has one destination, an instruction file, and that is a demotion: it lands in the transcript instead of the frame.
Which suggests a sorting rule you can apply now. If an instruction has to hold on turn ninety of a long session, an output style is where it belongs and it will not port. If it is a project convention, CLAUDE.md is where it belongs and it ports everywhere, because eight of the ten harnesses read a file with the same content under a different name.
Check yourself
- You run
claude --system-prompt "You are a database expert". Does yourCLAUDE.mdstill reach the model? - You edit
outputStylein.claude/settings.local.jsonin the middle of a session. When does it take effect? - Your output style says “always answer in bullet points”. A subagent you dispatch answers in prose. Is that a bug?
- You want one rule applied to a single
claude -prun and never again. Which mechanism?