Overview

The system prompt is the instruction block that persists across every turn; the user message is the per-turn ask. Identity, scope, constraints, and the output contract go in system, which is what keeps an agent consistent across a session. Write it as four labeled blocks with checkable constraints, and version it like code with evals. The term is defined in system-prompt.

Put durable rules in the system prompt

Test each rule: would you have to repeat it every turn? If yes, it belongs in system.

  • System: identity, capabilities, constraints, output schema, tool list, voice rules, refusal behavior.
  • User: the specific task, the input, the per-turn variables.

A system prompt that restates the current task wastes budget. A user message that restates the role each turn breaks the day a caller forgets.

Use four labeled blocks

1. Identity      You are <role> for <domain>, writing for <audience>.
2. Capabilities  You can <list>. Tools: <list>.
3. Constraints   Do not <non-goals>. Refuse or ask when <triggers>.
4. Format        Return <schema or shape>. Limit: <bounds>.

Labeled sections are easier to version and diff, and harder for the model to conflate. Wrap them in consistent tags as in prompt-templates. Keep the role line short and concrete; see role-framing.

Write constraints as checkable rules with a reason

“Never run a statement that writes; refuse and explain” beats “be careful”. Pair each prohibition with the action to take instead, and add the reason when it is not obvious, because the model generalizes from reasons. Drop capitals and “you MUST”: current models follow the system prompt closely, and emphasis written for older models causes overtriggering. Remove contradictions between sections; OpenAI reports that conflicting instructions make reasoning models spend tokens reconciling them.

Define behavior for ambiguity and refusal

Say what happens when a request is unclear, out of scope, or unsafe: ask one clarifying question, refuse with a one-line reason, or fall back to a named default. Without a rule the model improvises, and the improvisation varies run to run.

Pin the output contract

Format, field order, and length bounds are durable, so they belong in system. For machine-read output, enforce a schema with structured outputs rather than prose; see structured-output. “Max 5 bullets, 12 words each, order: cause, evidence, fix” is enforceable; “be concise” is not.

Keep it as short as the evals allow

Do not try to anticipate every edge case in one prompt. Move examples to a few-shot block (few-shot), schemas to a tool definition, and long procedures to a referenced runbook. To find dead weight, delete a paragraph, re-run the eval set, and keep the deletion if scores hold.

Change instructions mid-session with system-role messages

Editing the top-level system field mid-conversation restarts the prompt cache. On Claude Fable 5.1, Fable 5, Opus 5.5, Opus 5, Opus 4.8, and Sonnet 5.5, append a {"role": "system"} message at the point the new rule applies; the cached prefix stays valid and the instruction keeps system-level authority over user text. Use it for operator-level constraints and state changes (permissions, remaining budget), not for tool output or retrieved documents, which belong in tool_result blocks. Sonnet 5 does not support it.

Version prompts like code

Store prompts in the repo (prompts/<agent>.v3.md), review diffs in pull requests, tag versions, and run the eval set on every edit (prompt-evals). A bad prompt is a bad deploy; roll it back the same way.

Keep secrets out

Assume the prompt can be extracted. Put no keys, passwords, internal URLs, or PII in it; tools hold credentials server-side. See prompt-injection-defense.