claude_code preset for CLI or IDE-like coding tools where a human watches and steers the work. Write your own prompt for agents with a different surface, identity, or permission model.
How system prompts work
A system prompt is the initial instruction set that shapes how Claude behaves throughout a conversation. The Agent SDK has three starting points for it:- Minimal default: when you don’t set
systemPromptin TypeScript orsystem_promptin Python, the SDK uses a minimal prompt that covers tool calling but omits the rest of theclaude_codepreset’s content, including its security and safety instructions and its context about the working directory and environment. This differs fromclaude -p, which uses the Claude Code system prompt by default. If you’re migrating from the CLI and want matching behavior, set theclaude_codepreset. claude_codepreset: the system prompt that the Claude Code CLI uses, with tool usage instructions, security and safety instructions, and context about the working directory and environment. SetsystemPrompt: { type: "preset", preset: "claude_code" }in TypeScript orsystem_prompt={"type": "preset", "preset": "claude_code"}in Python, optionally withappendto add your own instructions on the end.- Custom string: a prompt you write yourself. The SDK sends only what you provide.
Decide on a starting point
The deciding factor is how closely your agent resembles Claude Code: a coding agent operating in a repository, with a human watching streaming output and steering the work. The further your product is from that, the more you’ll want to write your own prompt.
“Different from Claude Code” usually means one of the following:
- Different surface: the output isn’t read in a terminal by the person who triggered it. Chat UIs, structured-output consumers, and non-coding automation each need a prompt that matches how their output is rendered and reviewed. Unattended coding automation, like a CI job that fixes lint errors or reviews diffs, still fits the preset because the work itself is what the preset is written for.
- Different identity: the agent shouldn’t present itself as Claude Code. A support bot, a data-analysis assistant, or any domain-specific agent needs its own name, scope, and persona.
- Different permission model: the agent runs autonomously without a human approving each step, or operates on a narrow set of resources. Claude Code’s prompt assumes a human is in the loop with access to a full toolset.
- Non-coding tasks: most of Claude Code’s prompt is coding guidance. For research, content, or operations agents, that guidance competes with the instructions you actually need.
Customize agent behavior
append and a custom prompt string each change the system prompt directly, and an output style changes the instructions Claude Code gives Claude for every response. CLAUDE.md takes a different path: the SDK reads it and injects its content into the conversation as project context, so it shapes behavior alongside whichever system prompt you choose. Skills, hooks, and permissions also shape behavior outside the system prompt and are covered on their own pages.
CLAUDE.md files for project-level instructions
CLAUDE.md files give Claude persistent project context and instructions. The SDK injects their content into the conversation and leaves the system prompt untouched, so they work with any system prompt configuration. For what to put in CLAUDE.md, where to place it, and how to write effective instructions, see When to add to CLAUDE.md and the rest of How Claude remembers your project. This section covers what’s specific to the SDK: how CLAUDE.md loads. The SDK reads CLAUDE.md when the matching setting source is enabled:'project' loads CLAUDE.md or .claude/CLAUDE.md from the working directory, and 'user' loads ~/.claude/CLAUDE.md. Default query() options enable both sources, so CLAUDE.md loads automatically. If you set settingSources in TypeScript or setting_sources in Python explicitly, include the sources you need. CLAUDE.md loading is controlled by setting sources, not by the claude_code preset.
Load CLAUDE.md with the SDK
To load CLAUDE.md, setsettingSources 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:
settingSources array.
Output styles for persistent configurations
Output styles are saved sets of instructions that change Claude’s role, tone, and output format. They’re stored as markdown files and can be reused across sessions and projects.Create an output style
An output style is a markdown file with frontmatter for metadata, followed by the prompt content. Save it to~/.claude/output-styles/ for a user-level style available in every project, or .claude/output-styles/ in your repository for a project-level style you can commit and share with your team.
A custom output style leaves the claude_code preset’s software engineering instructions out and uses your own. To keep them and layer your instructions on top, set keep-coding-instructions: true in the frontmatter. Those instructions are only in Claude Code’s full system prompt, so the setting has no effect in a session on the shorter system prompt, which you pin on or off with CLAUDE_CODE_SIMPLE_SYSTEM_PROMPT. Keep them when your agent is still doing software engineering work. Leave them out when you’re replacing the role entirely.
The example below defines a code-review persona that keeps the coding instructions, since reviewing code still benefits from Claude Code’s security and code-quality guidance. Save it as ~/.claude/output-styles/code-reviewer.md to make it available across projects:
~/.claude/output-styles/code-reviewer.md
Activate an output style
Once created, activate output styles via:-
CLI: run
/configand select an output style -
Settings: set
outputStylein.claude/settings.local.json -
TypeScript SDK: set
outputStyleinside the inlinesettingsobject passed toquery(), or pointsettingsat a settings file that sets it.outputStyleis not a top-levelOptionsfield:
.claude/settings.local.json, use append or a custom prompt string instead.
Note for SDK users: Output styles are loaded when you include settingSources: ['user'] or settingSources: ['project'] (TypeScript) / setting_sources=["user"] or setting_sources=["project"] (Python) in your options.
Append to the claude_code preset
You can use the Claude Code preset with an append property to add your custom instructions while preserving all built-in functionality.
Improve prompt caching across users and machines
By default, two sessions that use the sameclaude_code preset and append text still cannot share a prompt cache entry if they run from different working directories. This is because the preset embeds per-session context in the system prompt ahead of your append text: the working directory, whether it’s a git repository, the platform, the active shell, the OS version, and auto memory paths. Any difference in that context produces a different system prompt and a cache miss. CLAUDE.md content doesn’t affect the system prompt cache because the SDK injects it into the conversation, not the system prompt.
To make the system prompt identical across sessions, set excludeDynamicSections: true in TypeScript or "exclude_dynamic_sections": True in Python. The per-session 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.
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.append block with excludeDynamicSections so a fleet of agents running from different directories can reuse the same cached system prompt:
--exclude-dynamic-system-prompt-sections.
Custom system prompts
You can provide a custom string assystemPrompt to replace the default entirely with your own instructions.
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 for the platform thresholds and the Windows behavior.
Cache the static part of a custom prompt
In the TypeScript SDK, you can pass a custom prompt as an array of strings instead of one string, with theSYSTEM_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. This form isn’t available in the Python SDK, whose system_prompt option accepts a string, a preset, or a file.
The SDK splits the prompt only when it calls the Claude API directly or runs on Claude Platform on AWS. In every other configuration, such as Amazon Bedrock, Google Cloud’s Agent Platform, Microsoft Foundry, or an LLM gateway, and whenever you set
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1, the SDK sends the whole prompt as one block, the same as passing one string.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:
TypeScript
cache_creation_input_tokens and cache_read_input_tokens fields on each result message.
The SDK assembles the blocks from the array as follows:
- The SDK joins the strings on each side of the marker with a blank line between them and removes the marker itself, so the marker text doesn’t reach Claude.
- If you include the marker more than once, the first one is the split and the SDK removes the others.
- If you leave the marker out, the SDK joins all the strings into one block, the same as passing one string.
Change the prompt of an existing session
By default, Claude Code builds the system prompt once, on a session’s first request, with yourappend text or custom prompt included, and records it in the session. Until the session is compacted, every later request uses that recorded prompt, including after you return to the session with resume or continue. If you pass a different append or custom prompt on that later call, it takes effect once the session is compacted or in a new session.
Recording applies in sessions that fetch feature flags, as sessions using a claude.ai or Console account do by default. On Amazon Bedrock, Google Cloud’s Agent Platform, Microsoft Foundry, and in other sessions that don’t fetch them, Claude Code rebuilds the prompt on every request. If you start Claude Code in bare mode by passing --bare through extraArgs or setting CLAUDE_CODE_SIMPLE=1, recording stays off unless you set snapshot: true on the object form of systemPrompt. Recording an append or custom prompt by default requires Claude Code v2.1.265 or later, which the TypeScript Agent SDK bundles from v0.3.265.
To rebuild the prompt on every request instead, set snapshot: false on the object form of systemPrompt in the TypeScript SDK: { type: "preset", preset: "claude_code", append, snapshot: false } or { type: "custom", prompt, snapshot: false }. Use this form while you iterate on prompt wording, or when your application changes append between calls that resume the same session. The snapshot field requires @anthropic-ai/claude-agent-sdk v0.3.257 or later and has no effect in sessions that don’t fetch feature flags.
Compare the four approaches
The four customization methods differ in where they live, how they’re shared, and what they preserve from theclaude_code preset.
“With append” means using
systemPrompt: { type: "preset", preset: "claude_code", append: "..." } in TypeScript or system_prompt={"type": "preset", "preset": "claude_code", "append": "..."} in Python. CLAUDE.md doesn’t change the system prompt itself: the SDK injects its content into the conversation as project context.
Combine approaches
The approaches compose. A persistent output style or CLAUDE.md sets the long-lived behavior, andappend layers session-specific instructions on top without touching the saved configuration.
Combine an output style with session-specific additions
The example below assumes a Code Reviewer output style is already active. Theappend 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:
See also
- Output styles: create, manage, and share output styles for the CLI, including the file format and storage locations
- How Claude remembers your project: what to put in CLAUDE.md, where to place it, and how to write effective project instructions
- TypeScript SDK reference: the full
Optionstype, includingsystemPrompt,settingSources, andsettings - Python SDK reference: the full
ClaudeAgentOptionstype, includingsystem_promptandsetting_sources - Settings: the
settings.jsonreference, including where output styles and other configuration are stored