Modifying system prompts changedagent-sdk/modifying-system-prompts
Nearest release: v2.1.300, published 7 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 14 Oct 2026 21:42 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 20 Oct 2026 18:37 UTC.
Upstream edited
Recorded here
Lines+306added
Lines−318removed
From line
46
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits17to this page, all time
The whole hunk
from line 46, old and new numbered
/
The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.
from line 46
4646
4747To load CLAUDE.md, set `settingSources` to include the level where you keep your CLAUDE.md. The example below loads a project-level CLAUDE.md alongside the `claude_code` preset, so Claude has both the coding-agent prompt and your project's conventions:
4848
49<CodeGroup>
50 ```typescript TypeScript theme={null}
51 import { query } from "@anthropic-ai/claude-agent-sdk";
52
53 const messages = [];
54
55 for await (const message of query({
56 prompt: "Add a new React component for user profiles",
57 options: {
58 systemPrompt: {
59 type: "preset",
60 preset: "claude_code" // Use Claude Code's system prompt
61 },
62 settingSources: ["project"] // Loads CLAUDE.md from project
63 }
64 })) {
65 messages.push(message);
66 }
67
68 // Now Claude has access to your project guidelines from CLAUDE.md
69 ```
70
71 ```python Python theme={null}
72 import asyncio
73
74 from claude_agent_sdk import query, ClaudeAgentOptions
75
76 messages = []
77
78
79 async def main():
80 async for message in query(
81 prompt="Add a new React component for user profiles",
82 options=ClaudeAgentOptions(
83 system_prompt={
84 "type": "preset",
85 "preset": "claude_code", # Use Claude Code's system prompt
86 },
87 setting_sources=["project"], # Loads CLAUDE.md from project
88 ),
89 ):
90 messages.append(message)
91
92
93 asyncio.run(main())
94
95 # Now Claude has access to your project guidelines from CLAUDE.md
96 ```
97</CodeGroup>
49```typescript TypeScript theme={null}
50import { query } from "@anthropic-ai/claude-agent-sdk";
51
52const messages = [];
53
54for await (const message of query({
55 prompt: "Add a new React component for user profiles",
56 options: {
57 systemPrompt: {
58 type: "preset",
59 preset: "claude_code" // Use Claude Code's system prompt
60 },
61 settingSources: ["project"] // Loads CLAUDE.md from project
62 }
63})) {
64 messages.push(message);
65}
66
67// Now Claude has access to your project guidelines from CLAUDE.md
68```
69
70```python Python theme={null}
71import asyncio
72
73from claude_agent_sdk import query, ClaudeAgentOptions
74
75messages = []
76
77
78async def main():
79 async for message in query(
80 prompt="Add a new React component for user profiles",
81 options=ClaudeAgentOptions(
82 system_prompt={
83 "type": "preset",
84 "preset": "claude_code", # Use Claude Code's system prompt
85 },
86 setting_sources=["project"], # Loads CLAUDE.md from project
87 ),
88 ):
89 messages.append(message)
90
91
92asyncio.run(main())
93
94# Now Claude has access to your project guidelines from CLAUDE.md
95```
9896
9997When you run either example, the SDK streams messages as Claude works: a system init message, assistant messages, user messages carrying tool results, and a final result message with the session outcome.
10098
from line 146
148146
149147You can use the Claude Code preset with an `append` property to add your custom instructions while preserving all built-in functionality.
150148
151<CodeGroup>
152 ```typescript TypeScript theme={null}
153 import { query } from "@anthropic-ai/claude-agent-sdk";
154
155 const messages = [];
156
157 for await (const message of query({
158 prompt: "Help me write a Python function to calculate fibonacci numbers",
159 options: {
160 systemPrompt: {
161 type: "preset",
162 preset: "claude_code",
163 append: "Always include detailed docstrings and type hints in Python code."
164 }
149```typescript TypeScript theme={null}
150import { query } from "@anthropic-ai/claude-agent-sdk";
151
152const messages = [];
153
154for await (const message of query({
155 prompt: "Help me write a Python function to calculate fibonacci numbers",
156 options: {
157 systemPrompt: {
158 type: "preset",
159 preset: "claude_code",
160 append: "Always include detailed docstrings and type hints in Python code."
165161 }
166 })) {
167 messages.push(message);
168 if (message.type === "assistant") {
169 console.log(message.message.content);
162 }
163})) {
164 messages.push(message);
165 if (message.type === "assistant") {
166 console.log(message.message.content);
167 }
168}
169```
170
171```python Python theme={null}
172import asyncio
173
174from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage
175
176messages = []
177
178
179async def main():
180 async for message in query(
181 prompt="Help me write a Python function to calculate fibonacci numbers",
182 options=ClaudeAgentOptions(
183 system_prompt={
184 "type": "preset",
185 "preset": "claude_code",
186 "append": "Always include detailed docstrings and type hints in Python code.",
187 }
188 ),
189 ):
190 messages.append(message)
191 if isinstance(message, AssistantMessage):
192 print(message.content)
193
194
195asyncio.run(main())
196```
197
198#### Improve prompt caching across users and machines
199
200By default, two sessions that use the same `claude_code` preset and `append` text still can't share a prompt cache entry when their auto memory locations differ. The preset embeds that location in the system prompt ahead of your `append` text. The location defaults to an absolute path under `~/.claude/projects/` named for the repository's path on disk, so it differs across users, machines, and checkouts.
201
202CLAUDE.md content and environment details such as the working directory, platform, shell, and OS version don't affect the system prompt cache, because Claude Code delivers them in the conversation, not the system prompt.
203
204To make the system prompt identical across sessions, set `excludeDynamicSections: true` in TypeScript or `"exclude_dynamic_sections": True` in Python. The per-user context moves into the first user message, leaving only the static preset and your `append` text in the system prompt so identical configurations share a cache entry across users and machines.
205
206> [!NOTE]
207>
208> `excludeDynamicSections` requires `@anthropic-ai/claude-agent-sdk` v0.2.98 or later, or `claude-agent-sdk` v0.1.58 or later for Python. Set it on the preset object form only. The SDK ignores it when you pass a custom prompt instead of the preset; to keep a custom prompt's instructions cached in the TypeScript SDK, see [Cache the static part of a custom prompt](#cache-the-static-part-of-a-custom-prompt).
209
210The following example pairs a shared `append` block with `excludeDynamicSections` so a fleet of agents can reuse the same cached system prompt:
211
212```typescript TypeScript theme={null}
213import { query } from "@anthropic-ai/claude-agent-sdk";
214
215for await (const message of query({
216 prompt: "Triage the open issues in this repo",
217 options: {
218 systemPrompt: {
219 type: "preset",
220 preset: "claude_code",
221 append: "You operate Acme's internal triage workflow. Label issues by component and severity.",
222 excludeDynamicSections: true
170223 }
171224 }
172 ```
173
174 ```python Python theme={null}
175 import asyncio
176
177 from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage
178
179 messages = []
180
181
182 async def main():
183 async for message in query(
184 prompt="Help me write a Python function to calculate fibonacci numbers",
185 options=ClaudeAgentOptions(
186 system_prompt={
187 "type": "preset",
188 "preset": "claude_code",
189 "append": "Always include detailed docstrings and type hints in Python code.",
190 }
191 ),
192 ):
193 messages.append(message)
194 if isinstance(message, AssistantMessage):
195 print(message.content)
196
197
198 asyncio.run(main())
199 ```
200</CodeGroup>
201
202#### Improve prompt caching across users and machines
203
204By default, two sessions that use the same `claude_code` preset and `append` text still can't share a prompt cache entry when their auto memory locations differ. The preset embeds that location in the system prompt ahead of your `append` text. The location defaults to an absolute path under `~/.claude/projects/` named for the repository's path on disk, so it differs across users, machines, and checkouts.
205
206CLAUDE.md content and environment details such as the working directory, platform, shell, and OS version don't affect the system prompt cache, because Claude Code delivers them in the conversation, not the system prompt.
207
208To make the system prompt identical across sessions, set `excludeDynamicSections: true` in TypeScript or `"exclude_dynamic_sections": True` in Python. The per-user context moves into the first user message, leaving only the static preset and your `append` text in the system prompt so identical configurations share a cache entry across users and machines.
209
210<Note>
211 `excludeDynamicSections` requires `@anthropic-ai/claude-agent-sdk` v0.2.98 or later, or `claude-agent-sdk` v0.1.58 or later for Python. Set it on the preset object form only. The SDK ignores it when you pass a custom prompt instead of the preset; to keep a custom prompt's instructions cached in the TypeScript SDK, see [Cache the static part of a custom prompt](#cache-the-static-part-of-a-custom-prompt).
212</Note>
213
214The following example pairs a shared `append` block with `excludeDynamicSections` so a fleet of agents can reuse the same cached system prompt:
215
216<CodeGroup>
217 ```typescript TypeScript theme={null}
218 import { query } from "@anthropic-ai/claude-agent-sdk";
219
220 for await (const message of query({
221 prompt: "Triage the open issues in this repo",
222 options: {
223 systemPrompt: {
224 type: "preset",
225 preset: "claude_code",
226 append: "You operate Acme's internal triage workflow. Label issues by component and severity.",
227 excludeDynamicSections: true
228 }
229 }
230 })) {
231 // ...
232 }
233 ```
234
235 ```python Python theme={null}
236 import asyncio
237
238 from claude_agent_sdk import query, ClaudeAgentOptions
239
240
241 async def main():
242 async for message in query(
243 prompt="Triage the open issues in this repo",
244 options=ClaudeAgentOptions(
245 system_prompt={
246 "type": "preset",
247 "preset": "claude_code",
248 "append": "You operate Acme's internal triage workflow. Label issues by component and severity.",
249 "exclude_dynamic_sections": True,
250 },
251 ),
252 ):
253 ...
254
255
256 asyncio.run(main())
257 ```
258</CodeGroup>
225})) {
226 // ...
227}
228```
229
230```python Python theme={null}
231import asyncio
232
233from claude_agent_sdk import query, ClaudeAgentOptions
234
235
236async def main():
237 async for message in query(
238 prompt="Triage the open issues in this repo",
239 options=ClaudeAgentOptions(
240 system_prompt={
241 "type": "preset",
242 "preset": "claude_code",
243 "append": "You operate Acme's internal triage workflow. Label issues by component and severity.",
244 "exclude_dynamic_sections": True,
245 },
246 ),
247 ):
248 ...
249
250
251asyncio.run(main())
252```
259253
260254**Tradeoffs:** the text that moves out of the system prompt still reaches Claude, but in a user message. That text is at least the auto memory directory's location, and often the whole auto memory section. Instructions in a user message carry marginally less weight than the same text in the system prompt, so Claude may follow its auto memory guidance less consistently. Enable this option when cross-session cache reuse matters more than that.
261255
from line 259
265259
266260You can provide a custom string as `systemPrompt` to replace the default entirely with your own instructions.
267261
268<CodeGroup>
269 ```typescript TypeScript theme={null}
270 import { query } from "@anthropic-ai/claude-agent-sdk";
271
272 const customPrompt = `You are a Python coding specialist.
273 Follow these guidelines:
274 - Write clean, well-documented code
275 - Use type hints for all functions
276 - Include comprehensive docstrings
277 - Prefer functional programming patterns when appropriate
278 - Always explain your code choices`;
279
280 const messages = [];
281
282 for await (const message of query({
283 prompt: "Create a data processing pipeline",
284 options: {
285 systemPrompt: customPrompt
286 }
287 })) {
288 messages.push(message);
289 if (message.type === "assistant") {
290 console.log(message.message.content);
291 }
292 }
293 ```
294
295 ```python Python theme={null}
296 import asyncio
297
298 from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage
299
300 custom_prompt = """You are a Python coding specialist.
301 Follow these guidelines:
302 - Write clean, well-documented code
303 - Use type hints for all functions
304 - Include comprehensive docstrings
305 - Prefer functional programming patterns when appropriate
306 - Always explain your code choices"""
307
308 messages = []
309
310
311 async def main():
312 async for message in query(
313 prompt="Create a data processing pipeline",
314 options=ClaudeAgentOptions(system_prompt=custom_prompt),
315 ):
316 messages.append(message)
317 if isinstance(message, AssistantMessage):
318 print(message.content)
319
320
321 asyncio.run(main())
322 ```
323</CodeGroup>
262```typescript TypeScript theme={null}
263import { query } from "@anthropic-ai/claude-agent-sdk";
264
265const customPrompt = `You are a Python coding specialist.
266Follow these guidelines:
267- Write clean, well-documented code
268- Use type hints for all functions
269- Include comprehensive docstrings
270- Prefer functional programming patterns when appropriate
271- Always explain your code choices`;
272
273const messages = [];
274
275for await (const message of query({
276 prompt: "Create a data processing pipeline",
277 options: {
278 systemPrompt: customPrompt
279 }
280})) {
281 messages.push(message);
282 if (message.type === "assistant") {
283 console.log(message.message.content);
284 }
285}
286```
287
288```python Python theme={null}
289import asyncio
290
291from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage
292
293custom_prompt = """You are a Python coding specialist.
294Follow these guidelines:
295- Write clean, well-documented code
296- Use type hints for all functions
297- Include comprehensive docstrings
298- Prefer functional programming patterns when appropriate
299- Always explain your code choices"""
300
301messages = []
302
303
304async def main():
305 async for message in query(
306 prompt="Create a data processing pipeline",
307 options=ClaudeAgentOptions(system_prompt=custom_prompt),
308 ):
309 messages.append(message)
310 if isinstance(message, AssistantMessage):
311 print(message.content)
312
313
314asyncio.run(main())
315```
324316
325317In Python, load a large custom prompt from a file with `system_prompt={"type": "file", "path": "..."}` instead of passing it as a string. The Python SDK passes a string prompt as one command-line argument to the CLI subprocess, so a prompt that exceeds the OS argument-length limit fails at process spawn before any API request is sent. On Linux the error is `Argument list too long`. See [`SystemPromptFile`](/docs/en/agent-sdk/python#systempromptfile) for the platform thresholds and the Windows behavior.
326318
from line 320
328320
329321In the TypeScript SDK, you can pass a custom prompt as an array of strings instead of one string, with the `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` marker between the static part and the rest. Use this when your prompt combines instructions that are the same on every request with context that changes per request, such as the customer or ticket the agent is handling. When you pass both parts as one string, a change to the per-request part changes the whole system prompt, so the static instructions miss the cache too. The array form isn't available in the Python SDK; [`ClaudeAgentOptions`](/docs/en/agent-sdk/python#claudeagentoptions) lists the forms `system_prompt` accepts.
330322
331<Note>
332 Claude Code splits the prompt only when it calls the Claude API directly or runs on [Claude Platform on AWS](/docs/en/claude-platform-on-aws). In every other configuration, such as Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, or an [LLM gateway](/docs/en/llm-gateway-connect), it sends the whole prompt as one block, the same as passing one string. The same happens whenever you set [`CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`](/docs/en/llm-gateway-protocol#disable-pre-release-capabilities).
333</Note>
323> [!NOTE]
324>
325> Claude Code splits the prompt only when it calls the Claude API directly or runs on [Claude Platform on AWS](/docs/en/claude-platform-on-aws). In every other configuration, such as Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, or an [LLM gateway](/docs/en/llm-gateway-connect), it sends the whole prompt as one block, the same as passing one string. The same happens whenever you set [`CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`](/docs/en/llm-gateway-protocol#disable-pre-release-capabilities).
334326
335327To split the prompt, import `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` from `@anthropic-ai/claude-agent-sdk` and pass it as its own array element between the two parts. The SDK sends the strings before the marker as one text block and the strings after it as a second block, each with its own cache breakpoint. In the example below, a support agent loads its triage instructions from a file and receives details about one ticket on each request, so the instructions stay cached while the ticket details change:
336328
from line 425
433425
434426The following example is for an agent that carries its own commit rules in `append`. It sets both `attribution` keys to empty strings to remove the trailer and footer, and turns off `includeGitInstructions` so Claude Code's own commit workflow instructions don't compete with yours:
435427
436<CodeGroup>
437 ```typescript TypeScript theme={null}
438 import { query } from "@anthropic-ai/claude-agent-sdk";
439
440 for await (const message of query({
441 prompt: "Commit the staged changes for ticket PROJ-142",
442 options: {
443 systemPrompt: {
444 type: "preset",
445 preset: "claude_code",
446 append: "Write commit messages as: <ticket id>: <summary>. Add no trailers."
447 },
448 settings: {
449 includeGitInstructions: false,
450 attribution: { commit: "", pr: "" }
451 },
452 allowedTools: ["Bash(git *)"]
453 }
454 })) {
455 if (message.type === "result") console.log(message.subtype);
456 }
457 ```
458
459 ```python Python theme={null}
460 import asyncio
461 from claude_agent_sdk import query, ClaudeAgentOptions
462
463
464 async def main():
465 async for message in query(
466 prompt="Commit the staged changes for ticket PROJ-142",
467 options=ClaudeAgentOptions(
468 system_prompt={
469 "type": "preset",
470 "preset": "claude_code",
471 "append": "Write commit messages as: <ticket id>: <summary>. Add no trailers.",
472 },
473 settings='{"includeGitInstructions": false, "attribution": {"commit": "", "pr": ""}}',
474 allowed_tools=["Bash(git *)"],
475 ),
476 ):
477 print(message)
478
479
480 asyncio.run(main())
481 ```
482</CodeGroup>
428```typescript TypeScript theme={null}
429import { query } from "@anthropic-ai/claude-agent-sdk";
430
431for await (const message of query({
432 prompt: "Commit the staged changes for ticket PROJ-142",
433 options: {
434 systemPrompt: {
435 type: "preset",
436 preset: "claude_code",
437 append: "Write commit messages as: <ticket id>: <summary>. Add no trailers."
438 },
439 settings: {
440 includeGitInstructions: false,
441 attribution: { commit: "", pr: "" }
442 },
443 allowedTools: ["Bash(git *)"]
444 }
445})) {
446 if (message.type === "result") console.log(message.subtype);
447}
448```
449
450```python Python theme={null}
451import asyncio
452from claude_agent_sdk import query, ClaudeAgentOptions
453
454
455async def main():
456 async for message in query(
457 prompt="Commit the staged changes for ticket PROJ-142",
458 options=ClaudeAgentOptions(
459 system_prompt={
460 "type": "preset",
461 "preset": "claude_code",
462 "append": "Write commit messages as: <ticket id>: <summary>. Add no trailers.",
463 },
464 settings='{"includeGitInstructions": false, "attribution": {"commit": "", "pr": ""}}',
465 allowed_tools=["Bash(git *)"],
466 ),
467 ):
468 print(message)
469
470
471asyncio.run(main())
472```
483473
484474To confirm the change, run the example in a repository with staged changes and check the new commit with `git log -1`. The message ends without a `Co-Authored-By` trailer.
485475
from line 507
517507
518508The example below assumes a Code Reviewer output style is already active. The `append` block layers session-specific focus areas on top of the persona, so a single review session can prioritize OAuth and token storage without changing the saved output style:
519509
520<CodeGroup>
521 ```typescript TypeScript theme={null}
522 import { query } from "@anthropic-ai/claude-agent-sdk";
523
524 // Assuming "Code Reviewer" output style is active (via /config or settings)
525 // Add session-specific focus areas
526 const messages = [];
527
528 for await (const message of query({
529 prompt: "Review this authentication module",
530 options: {
531 systemPrompt: {
532 type: "preset",
533 preset: "claude_code",
534 append: `
535 For this review, prioritize:
536 - OAuth 2.0 compliance
537 - Token storage security
538 - Session management
539 `
540 }
510```typescript TypeScript theme={null}
511import { query } from "@anthropic-ai/claude-agent-sdk";
512
513// Assuming "Code Reviewer" output style is active (via /config or settings)
514// Add session-specific focus areas
515const messages = [];
516
517for await (const message of query({
518 prompt: "Review this authentication module",
519 options: {
520 systemPrompt: {
521 type: "preset",
522 preset: "claude_code",
523 append: `
524 For this review, prioritize:
525 - OAuth 2.0 compliance
526 - Token storage security
527 - Session management
528 `
541529 }
542 })) {
543 messages.push(message);
544 }
545 ```
546
547 ```python Python theme={null}
548 import asyncio
549
550 from claude_agent_sdk import query, ClaudeAgentOptions
551
552 # Assuming "Code Reviewer" output style is active (via /config or settings)
553 # Add session-specific focus areas
554 messages = []
555
556
557 async def main():
558 async for message in query(
559 prompt="Review this authentication module",
560 options=ClaudeAgentOptions(
561 system_prompt={
562 "type": "preset",
563 "preset": "claude_code",
564 "append": """
565 For this review, prioritize:
566 - OAuth 2.0 compliance
567 - Token storage security
568 - Session management
569 """,
570 }
571 ),
572 ):
573 messages.append(message)
574
575
576 asyncio.run(main())
577 ```
578</CodeGroup>
530 }
531})) {
532 messages.push(message);
533}
534```
535
536```python Python theme={null}
537import asyncio
538
539from claude_agent_sdk import query, ClaudeAgentOptions
540
541# Assuming "Code Reviewer" output style is active (via /config or settings)
542# Add session-specific focus areas
543messages = []
544
545
546async def main():
547 async for message in query(
548 prompt="Review this authentication module",
549 options=ClaudeAgentOptions(
550 system_prompt={
551 "type": "preset",
552 "preset": "claude_code",
553 "append": """
554 For this review, prioritize:
555 - OAuth 2.0 compliance
556 - Token storage security
557 - Session management
558 """,
559 }
560 ),
561 ):
562 messages.append(message)
563
564
565asyncio.run(main())
566```
579567
580568## See also
581569
582570
No line in this hunk matches that.