6.0 What This Teaches
The system parameter gives you a way to set ground rules that persist
across an entire conversation. This tutorial covers:
- What a system prompt is and where it sits in the API call
- How to set a persona that changes tone and detail level
- Enforcing output format constraints across multiple turns
- The difference between system-level and user-level instructions
- A full working example using a code reviewer persona
6.1 What a System Prompt Is
The system parameter in messages.create() sets persistent
instructions that apply to every turn of the conversation. Unlike the
messages list, the system prompt is not part of the alternating
user/assistant role structure - it is separate, and the model treats it as a
higher-level directive.
Think of the system prompt as a contract you establish before the conversation
starts: "you are this kind of assistant, you always output this format, you
never do these things." The messages list then carries the actual
conversation within that contract.
6.2 Setting a System Prompt
# system_basic.py - compare output with and without a system prompt.
import anthropic
client = anthropic.Anthropic()
user_message = "Write a function that reads a JSON file."
# Without system prompt - model chooses its own style.
r1 = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=256,
messages=[{"role": "user", "content": user_message}]
)
print("--- No system prompt ---")
print(r1.content[0].text)
# With system prompt - model follows the constraints.
r2 = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=256,
system=(
"You are a senior Python developer. "
"Always include type hints. "
"Return only code with no prose."
),
messages=[{"role": "user", "content": user_message}]
)
print("--- With system prompt ---")
print(r2.content[0].text)
The second response should be shorter, contain type hints, and have no surrounding
explanation. The exact same user message produces different output because the
system prompt changed the model's defaults.
6.3 Persona Setting
The system prompt can establish a persona that changes how the model communicates:
technical depth, level of assumed knowledge, tone, and vocabulary all shift.
# persona.py - two personas, same question, different outputs.
import anthropic
client = anthropic.Anthropic()
question = "What is a pointer?"
expert_system = (
"You are a C++ expert focused on performance and undefined behavior. "
"Assume the reader is an experienced systems programmer."
)
beginner_system = (
"You are a patient teacher explaining programming concepts to beginners "
"who have no prior experience with low-level languages. "
"Use analogies and avoid jargon."
)
for label, system in [("Expert", expert_system), ("Beginner", beginner_system)]:
r = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=256,
system=system,
messages=[{"role": "user", "content": question}]
)
print(f"--- {label} persona ---")
print(r.content[0].text)
print()
The expert persona will discuss memory addresses, alignment, and undefined behavior.
The beginner persona will use an analogy like "a pointer is like a street address
for your data." Same model, same question, fundamentally different output because
the audience expectation is different.
6.4 Output Format Constraints
When you need structured output consistently across multiple turns, put the
format requirement in the system prompt rather than repeating it in every user
message.
# json_system.py - enforce JSON output via system prompt.
import anthropic
import json
client = anthropic.Anthropic()
system = (
"Always respond with valid JSON. No other text before or after the JSON. "
"Every response must have exactly two keys: "
"'answer' (a string) and 'confidence' ('high', 'medium', or 'low')."
)
questions = [
"What does the `with` statement do in Python?",
"Is Python dynamically typed?",
]
for q in questions:
r = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=256,
system=system,
messages=[{"role": "user", "content": q}]
)
data = json.loads(r.content[0].text)
print(f"Q: {q}")
print(f"A: {data['answer']}")
print(f"Confidence: {data['confidence']}")
print()
Without the system prompt, the model might return JSON for the first question and
plain prose for the second. The system prompt makes the format consistent across
every turn.
6.5 Scope: System vs User
The system prompt sets ground rules; user messages make individual requests within
those rules. The model treats system instructions as higher-priority than user
requests in most cases.
| Layer | Purpose | Persists across turns? |
| system |
Persona, output format, behavioral guardrails |
Yes - set once, applies to the whole conversation |
| user message |
The specific task for this turn |
No - each message is a new request |
| assistant message |
The model's previous reply (for context in multi-turn) |
Only if you include it in the messages list |
If a user message contradicts the system prompt - for example, the system prompt
says "return only code" but the user says "explain what the code does" - the model
usually follows the user message. Guardrails work best for format and persona, not
for preventing the user from overriding them.
6.6 Example: Code Reviewer Persona
# code_reviewer.py - system prompt makes Claude act as a strict code reviewer.
import anthropic
client = anthropic.Anthropic()
system = """\
You are a strict Python code reviewer. When shown code, you always check for:
1. Security issues (e.g., shell injection, hardcoded secrets)
2. Missing type hints on function parameters and return values
3. Missing error handling for I/O operations
For each issue found, state the line number (if visible), the problem, and a fix.
If no issues are found in a category, say "None found."
"""
code_to_review = """\
def load_config(path):
import json
f = open(path)
return json.load(f)
"""
r = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
system=system,
messages=[{"role": "user", "content": f"Review this code:\n\n{code_to_review}"}]
)
print(r.content[0].text)
The reviewer will flag: missing type hints on path and the return
type, the file handle that is never closed (no with statement), and
the absence of a FileNotFoundError handler. All of these come from
the system prompt's checklist, not from a user request.
6.7 Exercise
Exercise
Write a script that sends the same user message - "Write a function to read
a JSON file" - twice: once with no system prompt, and once with:
system="You are a security-conscious Python developer. Always validate
inputs and handle FileNotFoundError."
Print both responses and compare them. Note whether the second response
includes input validation, a with statement for the file, and
a try/except block that catches FileNotFoundError.
6.8 Common Mistakes
Putting format instructions in the user message instead of system
If you write "return only JSON" in the user message on turn 1, the model
follows it. On turn 2, you send a new user message without that instruction
and the model may revert to prose. Format constraints belong in the system
prompt so they apply to every turn automatically.
Contradicting the system prompt in user messages
If the system prompt says "return only code" and the user message says
"explain this code line by line", the model faces a conflict. Behavior
varies: sometimes the system prompt wins, sometimes the user message does.
Keep user messages consistent with the system prompt to get predictable results.
Making the system prompt so long it eats into the context window
The system prompt counts as input tokens on every single call. A 2,000-token
system prompt in a 10-turn conversation adds 20,000 tokens to your total
input cost. Keep system prompts concise - three to five clear sentences is
usually enough to establish persona and format.
6.9 Key Terms
| Term | Meaning |
| system prompt | The text passed in the system parameter; sets persistent instructions for the whole conversation |
| system parameter | The system= argument in messages.create() |
| persona | A role description in the system prompt that changes how the model communicates |
| output constraint | A format rule in the system prompt, such as "always return valid JSON" |
| behavioral guardrail | An instruction that restricts what the model will or will not do |
| context window budget | The portion of the context window consumed by the system prompt on every call |