Modifying system prompts

Tags

official-docs claude-code-cli

Content

Documentation Index

Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt Use this file to discover all available pages before exploring further.

Modifying system prompts

Learn how to customize Claude's behavior by modifying system prompts using three approaches - output styles, systemPrompt with append, and custom system prompts.

System prompts define Claude's behavior, capabilities, and response style. The Claude Agent SDK provides three ways to customize system prompts: using output styles (persistent, file-based configurations), appending to Claude Code's prompt, or using a fully custom prompt.

Understanding system prompts

A system prompt is the initial instruction set that shapes how Claude behaves throughout a conversation.

Default behavior: The Agent SDK uses a minimal system prompt by default. It contains only essential tool instructions but omits Claude Code's coding guidelines, response style, and project context. To include the full Claude Code system prompt, specify systemPrompt: { type: "preset", preset: "claude_code" } in TypeScript or system_prompt={"type": "preset", "preset": "claude_code"} in Python.

Claude Code's system prompt includes:

Methods of modification

Method 1: CLAUDE.md files (project-level instructions)

CLAUDE.md files provide project-specific context and instructions that are automatically read by the Agent SDK when it runs in a directory. They serve as persistent "memory" for your project.

How CLAUDE.md works with the SDK

Location and discovery:

CLAUDE.md files are read when the corresponding setting source is enabled: 'project' for project-level CLAUDE.md and 'user' for ~/.claude/CLAUDE.md. With default query() options both sources are enabled, so CLAUDE.md loads automatically. If you set settingSources (TypeScript) or setting_sources (Python) explicitly, include the sources you need. CLAUDE.md loading is controlled by setting sources, not by the claude_code preset.

Content format: CLAUDE.md files use plain markdown and can contain:

Example CLAUDE.md

```markdown theme={null}

Project Guidelines

Code Style

Testing

Commands

Using CLAUDE.md with the SDK

```typescript TypeScript theme={null} import { query } from "@anthropic-ai/claude-agent-sdk";

const messages = [];

for await (const message of query({ prompt: "Add a new React component for user profiles", options: { systemPrompt: { type: "preset", preset: "claude_code" // Use Claude Code's system prompt }, settingSources: ["project"] // Loads CLAUDE.md from project } })) { messages.push(message); }

// Now Claude has access to your project guidelines from CLAUDE.md ```

```python Python theme={null} from claude_agent_sdk import query, ClaudeAgentOptions

messages = []

async for message in query( prompt="Add a new React component for user profiles", options=ClaudeAgentOptions( system_prompt={ "type": "preset", "preset": "claude_code", # Use Claude Code's system prompt }, setting_sources=["project"], # Loads CLAUDE.md from project ), ): messages.append(message)

# Now Claude has access to your project guidelines from CLAUDE.md ```

When to use CLAUDE.md

Best for:

Key characteristics:

Method 2: Output styles (persistent configurations)

Output styles are saved configurations that modify Claude's system prompt. They're stored as markdown files and can be reused across sessions and projects.

Creating an output style

```typescript TypeScript theme={null} import { writeFile, mkdir } from "fs/promises"; import { join } from "path"; import { homedir } from "os";

async function createOutputStyle(name: string, description: string, prompt: string) { // User-level: ~/.claude/output-styles // Project-level: .claude/output-styles const outputStylesDir = join(homedir(), ".claude", "output-styles");

await mkdir(outputStylesDir, { recursive: true });

const content = `---

name: ${name} description: ${description}


${prompt}`;

const filePath = join(outputStylesDir, `${name.toLowerCase().replace(/\s+/g, "-")}.md`);
await writeFile(filePath, content, "utf-8");

}

// Example: Create a code review specialist await createOutputStyle( "Code Reviewer", "Thorough code review assistant", `You are an expert code reviewer.

For every code submission: 1. Check for bugs and security issues 2. Evaluate performance 3. Suggest improvements 4. Rate code quality (1-10)` ); ```

```python Python theme={null} from pathlib import Path

async def create_output_style(name: str, description: str, prompt: str): # User-level: ~/.claude/output-styles # Project-level: .claude/output-styles output_styles_dir = Path.home() / ".claude" / "output-styles"

  output_styles_dir.mkdir(parents=True, exist_ok=True)

  content = f"""---

name: {name} description: {description}


{prompt}"""

  file_name = name.lower().replace(" ", "-") + ".md"
  file_path = output_styles_dir / file_name
  file_path.write_text(content, encoding="utf-8")

# Example: Create a code review specialist await create_output_style( "Code Reviewer", "Thorough code review assistant", """You are an expert code reviewer.

For every code submission: 1. Check for bugs and security issues 2. Evaluate performance 3. Suggest improvements 4. Rate code quality (1-10)""", ) ```

Using output styles

Once created, activate output styles via:

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.

Method 3: Using systemPrompt with append

You can use the Claude Code preset with an append property to add your custom instructions while preserving all built-in functionality.

```typescript TypeScript theme={null} import { query } from "@anthropic-ai/claude-agent-sdk";

const messages = [];

for await (const message of query({ prompt: "Help me write a Python function to calculate fibonacci numbers", options: { systemPrompt: { type: "preset", preset: "claude_code", append: "Always include detailed docstrings and type hints in Python code." } } })) { messages.push(message); if (message.type === "assistant") { console.log(message.message.content); } } ```

```python Python theme={null} from claude_agent_sdk import query, ClaudeAgentOptions

messages = []

async for message in query( prompt="Help me write a Python function to calculate fibonacci numbers", options=ClaudeAgentOptions( system_prompt={ "type": "preset", "preset": "claude_code", "append": "Always include detailed docstrings and type hints in Python code.", } ), ): messages.append(message) if message.type == "assistant": print(message.message.content) ```

Improve prompt caching across users and machines

By default, two sessions that use the same claude_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, platform and OS version, current date, git status, and auto-memory paths. Any difference in that context produces a different system prompt and a cache miss.

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. It applies only to the preset object form and has no effect when systemPrompt is a string.

The following example pairs a shared append block with excludeDynamicSections so a fleet of agents running from different directories can reuse the same cached system prompt:

```typescript TypeScript theme={null} import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({ prompt: "Triage the open issues in this repo", options: { systemPrompt: { type: "preset", preset: "claude_code", append: "You operate Acme's internal triage workflow. Label issues by component and severity.", excludeDynamicSections: true } } })) { // ... } ```

```python Python theme={null} from claude_agent_sdk import query, ClaudeAgentOptions

async for message in query( prompt="Triage the open issues in this repo", options=ClaudeAgentOptions( system_prompt={ "type": "preset", "preset": "claude_code", "append": "You operate Acme's internal triage workflow. Label issues by component and severity.", "exclude_dynamic_sections": True, }, ), ): ... ```

Tradeoffs: the working directory, git status, and memory location still reach Claude, but as part of the first user message rather than the system prompt. Instructions in the user message carry marginally less weight than the same text in the system prompt, so Claude may rely on them less strongly when reasoning about the current directory or auto-memory paths. Enable this option when cross-session cache reuse matters more than maximally authoritative environment context.

For the equivalent flag in non-interactive CLI mode, see --exclude-dynamic-system-prompt-sections.

Method 4: Custom system prompts

You can provide a custom string as systemPrompt to replace the default entirely with your own instructions.

```typescript TypeScript theme={null} import { query } from "@anthropic-ai/claude-agent-sdk";

const customPrompt = You are a Python coding specialist. Follow these guidelines: - Write clean, well-documented code - Use type hints for all functions - Include comprehensive docstrings - Prefer functional programming patterns when appropriate - Always explain your code choices;

const messages = [];

for await (const message of query({ prompt: "Create a data processing pipeline", options: { systemPrompt: customPrompt } })) { messages.push(message); if (message.type === "assistant") { console.log(message.message.content); } } ```

```python Python theme={null} from claude_agent_sdk import query, ClaudeAgentOptions

custom_prompt = """You are a Python coding specialist. Follow these guidelines: - Write clean, well-documented code - Use type hints for all functions - Include comprehensive docstrings - Prefer functional programming patterns when appropriate - Always explain your code choices"""

messages = []

async for message in query( prompt="Create a data processing pipeline", options=ClaudeAgentOptions(system_prompt=custom_prompt), ): messages.append(message) if message.type == "assistant": print(message.message.content) ```

Comparison of all four approaches

Feature CLAUDE.md Output Styles systemPrompt with append Custom systemPrompt
Persistence Per-project file Saved as files Session only Session only
Reusability Per-project Across projects Code duplication Code duplication
Management On filesystem CLI + files In code In code
Default tools Preserved Preserved Preserved Lost (unless included)
Built-in safety Maintained Maintained Maintained Must be added
Environment context Automatic Automatic Automatic Must be provided
Customization level Additions only Replace default Additions only Complete control
Version control With project Yes With code With code
Scope Project-specific User or project Code session Code session

Note: "With append" means using systemPrompt: { type: "preset", preset: "claude_code", append: "..." } in TypeScript or system_prompt={"type": "preset", "preset": "claude_code", "append": "..."} in Python.

Use cases and best practices

When to use CLAUDE.md

Best for:

Examples:

CLAUDE.md files load when the project setting source is enabled, which it is for default query() options. If you set settingSources (TypeScript) or setting_sources (Python) explicitly, include 'project' to keep loading project-level CLAUDE.md.

When to use output styles

Best for:

Examples:

When to use systemPrompt with append

Best for:

When to use custom systemPrompt

Best for:

Combining approaches

You can combine these methods for maximum flexibility:

Example: Output style with session-specific additions

```typescript TypeScript theme={null} import { query } from "@anthropic-ai/claude-agent-sdk";

// Assuming "Code Reviewer" output style is active (via /output-style) // Add session-specific focus areas const messages = [];

for await (const message of query({ prompt: "Review this authentication module", options: { systemPrompt: { type: "preset", preset: "claude_code", append: For this review, prioritize: - OAuth 2.0 compliance - Token storage security - Session management } } })) { messages.push(message); } ```

```python Python theme={null} from claude_agent_sdk import query, ClaudeAgentOptions

# Assuming "Code Reviewer" output style is active (via /output-style) # Add session-specific focus areas messages = []

async for message in query( prompt="Review this authentication module", options=ClaudeAgentOptions( system_prompt={ "type": "preset", "preset": "claude_code", "append": """ For this review, prioritize: - OAuth 2.0 compliance - Token storage security - Session management """, } ), ): messages.append(message) ```

See also