본문으로 건너뛰기

System Prompts

중급
What you'll learn
  • Set a system prompt correctly on all four surfaces — Anthropic's system parameter, OpenAI's developer role, Gemini's system_instruction, and Claude Code's five flags
  • Know what belongs in the standing brief and what has to stay out of it
  • Stop over-pushing: why "CRITICAL: you MUST" now backfires on current models
  • Put the system prompt where the prompt cache can reuse it, and split the volatile part out
  • Choose between appending to and replacing Claude Code's default prompt — and understand what replacing drops

Every model has one layer that frames the whole conversation. It is the cheapest lever you own — set once, applies to every turn — and it is the one most people fill with the wrong material. Roles covers why it matters. This lesson is the operator's version: exact parameter names, how hard to push, and where it interacts with caching.

One idea, four surfaces​

The concept ports everywhere. The plumbing does not.

SurfaceHow you set itShape
Anthropic Messages APIsystem — a top-level request parameter, not an entry in messagesString, or an array of content blocks
OpenAI Responses APIthe instructions parameter, or a message with the developer roleApplies to the current request; instructions does not carry over when you chain with previous_response_id
Google Gemini APIsystem_instruction on the request (systemInstruction in Java, SystemInstruction in Go)Set per interaction
Claude Codefive CLI flags (below), plus CLAUDE.md and output stylesReplace or append
Chat appscustom instructions on your accountPersistent across chats

The most common porting bug is treating Anthropic's system as a message. It is not: it sits beside messages, not inside it. Going the other way, OpenAI's hierarchy is explicit — developer instructions outrank user instructions, which outrank the assistant's own prior turns. Their own analogy: the developer message is the function definition, the user message is the arguments you pass to it.

Anthropic: system is a top-level parameter

curl https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
  "model": "claude-sonnet-5-5",
  "max_tokens": 1024,
  "system": "You are a precise financial analyst. Show your assumptions. Never invent numbers.",
  "messages": [{"role": "user", "content": "Summarize this filing."}]
}'

What belongs in it​

Sort every line of your prompt by how often it changes. Things that are true for the whole conversation go up into the standing brief. Things that change per turn stay in the user turn.

Guided walkthrough1 of 6
  1. One sentence of role is enough to shift tone and focus. Anthropic's docs are explicit that even a single sentence makes a difference; they also warn against over-constraining the role, because current models do not need heavy persona scaffolding.

How hard to push​

This is where prompts written for older models actively hurt. Anthropic's guidance for the Opus 4.5/4.6 generation and later is blunt: these models are more responsive to the system prompt than their predecessors, so prompts hardened against a model that used to under-trigger tools will now make it over-trigger. The fix is to turn the volume down — Use this tool when… instead of CRITICAL: you MUST use this tool when….

Watch out
  • ALL-CAPS, "CRITICAL", "you MUST", and threat framing are a legacy of models that ignored soft instructions. On current models they cause overtriggering and over-eager tool calls.
  • Over-constrained personas ("you are a world-class 10x expert who never makes mistakes") add tokens and buy nothing. Ask for the perspective you actually want instead.
  • Contradictory layers are worse than a thin brief. If the system prompt says "be concise" and a skill says "always explain your reasoning", the model has to guess.
  • Stacking every technique at once — role, XML, few-shot, chain-of-thought, output schema — is the most common form of over-engineering. Add one, measure, keep it only if it helped.

Eagerness is a dial, not a fixed trait, and the system prompt is where you set it. Wrap the policy in a named tag so you can find and edit it later:

Push toward acting

<default_to_action>
Implement changes rather than only proposing them. If intent is ambiguous, infer the
most useful action and proceed, using tools to find the details you are missing instead
of guessing.
</default_to_action>

Push toward asking first

<do_not_act_before_instructions>
Do not modify files or start an implementation unless you are clearly asked to. When
intent is ambiguous, research and recommend instead of acting. Make changes only on an
explicit request.
</do_not_act_before_instructions>

The system prompt is your cache prefix​

This is the part that shows up on the invoice. Anthropic builds the cacheable prefix in a fixed order — tools, then system, then messages — and caching covers everything up to and including the block you mark. So the system prompt sits in the highest-value cache position in the whole request: stable, reused on every call, and in front of the conversation.

Two consequences:

  • Keep the system prompt byte-stable. A timestamp, a username, or a session ID interpolated into it changes the prefix and misses the cache on every single request.
  • If part of it must vary, put the stable part first and break the cache after it, so the varying tail is the only thing re-read.

Minimum cacheable lengths differ per model — some current models cache from 512 tokens, older ones need up to 4,096 — and a prompt below the threshold is silently processed uncached with no error. Check the current table before you count on it.

Claude Code ships a purpose-built version of that split. When your replacement prompt mixes fixed instructions with per-run context, put a line containing only __SYSTEM_PROMPT_DYNAMIC_BOUNDARY__ between them: Claude Code splits at the first such line and drops it, keeping everything above it cached while the part below changes (v2.1.275+). For scripted multi-user runs, --exclude-dynamic-system-prompt-sections moves per-user context out of the prompt and into the first user message so several machines share one cached prefix.

Claude Code: append or replace​

Five flags set the prompt. Four of them set text; the fifth controls whether a conversation keeps the text it started with.

FlagWhat it does
--system-promptReplaces the entire default prompt with your text
--system-prompt-fileReplaces it with a file's contents
--append-system-promptAppends your text to the default prompt
--append-system-prompt-fileAppends a file's contents to the default prompt
--system-prompt-snapshotoff rebuilds the prompt on every request instead of reusing the one recorded on the first request

--system-prompt and --system-prompt-file are mutually exclusive; either append flag can be combined with either replacement flag.

The decision rule is about what you are willing to own:

Guided walkthrough1 of 3
  1. Appending preserves the default tool guidance, safety instructions, and coding conventions, so you only supply what differs — per-invocation rules, output format, domain context for a -p script.

Append a rule for one headless run

claude -p --append-system-prompt "Cite file:line for every claim." "audit the auth flow"

One gotcha that costs real debugging time: by default Claude Code builds the system prompt once, on a conversation's first request, and records it. Every later request in that conversation reuses the recorded prompt — including after --resume or --continue. Change the flag text on a later launch and nothing happens until the conversation is compacted or you start a new one. While you are iterating on wording, pass --system-prompt-snapshot off (v2.1.257+) to rebuild it every request.

A worked before/after​

Before — everything at maximum volume, volatile facts baked in, no output contract:

Over-pushed and cache-hostile

You are THE BEST code reviewer in the world. You are a 10x engineer.
CRITICAL: You MUST ALWAYS use the search tool before answering. NEVER skip this.
IT IS EXTREMELY IMPORTANT that you are thorough.
The current date is 2026-09-30 and the user is reviewing PR #4412 on branch fix/auth-race.

Four separate problems: the superlatives buy nothing, the shouting will make the model over-call its tools, there is no definition of a valid answer, and the last line changes every run so the prefix never caches.

After — one sentence of role, a real output contract, an uncertainty escape hatch, volatile facts moved to the user turn:

Calm, contract-first, cacheable

You are a code reviewer for a TypeScript monorepo.

Rules:
- Search the codebase before claiming a symbol is unused.
- If you cannot verify a claim from the diff or the code, say so instead of guessing.

Output: a Summary section, then Risks, then Suggested changes. No preamble.

The date, the PR number, and the branch go into the user turn, where they belong. Same behavior, a stable cache prefix, and about a third of the tokens.

What not to reach for any more​

Prefilling — starting the assistant's turn yourself so the model continues in your format — used to be the go-to way to force JSON or skip a preamble. On Claude 4.6 and later, a prefilled final assistant turn returns a 400 error. The replacements all live in or next to the system prompt: a direct "respond without preamble" instruction, structured outputs, or a tool with an enum field for classification. Assistant messages elsewhere in the conversation are unaffected, so few-shot examples still work exactly as before.

System prompt quick reference
Enter 또는 스페이스 키를 눌러 카드를 뒤집습니다. 좌우 화살표 키로 카드를 이동할 수 있습니다.용어가 표시되었습니다.
1 / 8
Key takeaways
  • Same concept, different plumbing: Anthropic's `system` parameter, OpenAI's `developer` role / `instructions`, Gemini's `system_instruction`, Claude Code's five flags.
  • Sort by rate of change — durable rules go in the standing brief, volatile facts go in the user turn.
  • Turn the volume down. Current models over-trigger on prompts hardened for models that used to under-trigger.
  • The system prompt sits in the cache prefix (tools → system → messages): keep it byte-stable, and split the varying tail off.
  • In Claude Code, appending preserves the default safety and tool guidance; replacing hands you the whole responsibility.
  • Prefilled final assistant turns are a 400 on Claude 4.6+ — use an output contract, structured outputs, or tools.

Check yourself

0/4
  1. In the Anthropic Messages API, where does the system prompt live?
  2. Your prompt says "CRITICAL: You MUST ALWAYS call the search tool." On a current Claude model, what is the likely effect?
  3. Why does interpolating the current timestamp into your system prompt cost money?
  4. You pass `--system-prompt` in Claude Code instead of `--append-system-prompt`. What did you just give up?

Next​