Modifying System Prompts
View SourceLearn how to customize Claude's behavior by modifying system prompts using output styles, appended instructions, and custom system prompts.
Official Documentation: This guide is based on the official Claude Agent SDK documentation. Examples are adapted for Elixir.
System prompts define Claude's behavior, capabilities, and response style. The Elixir SDK provides three primary ways to customize system prompts: using output styles (persistent, file-based configurations), appending to Claude Code's prompt, or using a fully custom prompt. You can also use CLAUDE.md files for project-level instructions and pass settings directly via the :settings option.
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, use
:system_promptwith a preset value. To customize behavior, use:system_promptto replace the default entirely, or:append_system_promptto add instructions while keeping the defaults.
Claude Code's system prompt includes:
- Tool usage instructions and available tools
- Code style and formatting guidelines
- Response tone and verbosity settings
- Security and safety instructions
- Context about the current working directory and environment
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:
- Project-level:
CLAUDE.mdor.claude/CLAUDE.mdin your working directory - User-level:
~/.claude/CLAUDE.mdfor global instructions across all projects
Important: The SDK only reads CLAUDE.md files when you explicitly configure :setting_sources:
- Include
"project"to load project-level CLAUDE.md - Include
"user"to load user-level CLAUDE.md (~/.claude/CLAUDE.md)
Using :system_prompt alone does not automatically load CLAUDE.md -- you must also specify setting sources.
Content format: CLAUDE.md files use plain markdown and can contain:
- Coding guidelines and standards
- Project-specific context
- Common commands or workflows
- API conventions
- Testing requirements
Example CLAUDE.md
# Project Guidelines
## Code Style
- Use Elixir 1.18+ features
- Prefer pattern matching over conditionals
- Always include @moduledoc and @doc attributes
## Testing
- Run `mix test` before committing
- Maintain >80% code coverage
- Use ExUnit with Mox for mocking
## Commands
- Quality checks: `mix quality`
- Dev server: `iex -S mix phx.server`
- Type check: `mix dialyzer`Using CLAUDE.md with the SDK
# You must specify setting_sources to load CLAUDE.md
{:ok, result} = ClaudeCode.query("Add a new GenServer module for user sessions",
setting_sources: ["project"]
)When to use CLAUDE.md
Best for:
- Team-shared context -- Guidelines everyone should follow
- Project conventions -- Coding standards, file structure, naming patterns
- Common commands -- Build, test, deploy commands specific to your project
- Long-term memory -- Context that should persist across all sessions
- Version-controlled instructions -- Commit to git so the team stays in sync
Key characteristics:
- Persistent across all sessions in a project
- Shared with team via git
- Automatic discovery (no code changes needed)
- Requires loading settings via
:setting_sources
Method 2: Output styles (persistent configurations)
Output styles are saved configurations that modify Claude's system prompt. They are stored as markdown files and can be reused across sessions and projects.
Creating an output style
Output style files are markdown files with YAML frontmatter, stored in ~/.claude/output-styles/ (user-level) or .claude/output-styles/ (project-level):
---
name: Code Reviewer
description: Thorough code review assistant
keep-coding-instructions: true
---
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)Supported frontmatter fields:
| Field | Purpose | Default |
|---|---|---|
name | Name of the output style, if not the file name | Inherits from file name |
description | Description shown in the UI of /output-style | None |
keep-coding-instructions | Whether to keep the parts of Claude Code's system prompt related to coding | false |
Using output styles
Once created, activate output styles via:
- CLI:
/output-style [style-name] - Settings:
.claude/settings.local.json - Create new:
/output-style:new [description]
Note for SDK users: Output styles are loaded when you include "user" or "project" in your :setting_sources option:
{:ok, result} = ClaudeCode.query("Review this module for issues",
setting_sources: ["user"]
)When to use output styles
Best for:
- Persistent behavior changes across sessions
- Team-shared configurations
- Specialized assistants (code reviewer, data scientist, DevOps)
- Complex prompt modifications that need versioning
Examples:
- Creating a dedicated SQL optimization assistant
- Building a security-focused code reviewer
- Developing a teaching assistant with specific pedagogy
Method 3: Appending to the system prompt
Use :append_system_prompt to add your custom instructions while preserving all built-in functionality. This is the recommended approach for most use cases.
{:ok, result} = ClaudeCode.query("Help me process this large CSV file",
append_system_prompt: "Focus on performance optimization. Prefer Stream over Enum for large datasets."
)This keeps Claude's tool-usage instructions, safety guidelines, and environment context intact while adding your custom behavior.
Method 4: Custom system prompts
Use :system_prompt to replace the default system prompt entirely with your own instructions:
{:ok, result} = ClaudeCode.query("Create a data processing pipeline",
system_prompt: """
You are an Elixir coding specialist.
Follow these guidelines:
- Write clean, well-documented code
- Use typespecs for all public functions
- Include comprehensive @moduledoc and @doc attributes
- Prefer functional programming patterns
- Always explain your code choices
"""
)Warning: Overriding the system prompt replaces Claude Code's default instructions, which include tool usage guidance, safety instructions, and environment context. Only use this when you need complete control over Claude's behavior.
Method 5: Settings configuration
Pass settings directly as a map or file path using the :settings option:
# As a map (auto-encoded to JSON for the CLI)
{:ok, session} = ClaudeCode.start_link(
settings: %{
"preferredLanguage" => "elixir",
"codeStyle" => "functional"
}
)
# Or as a path to a JSON file
{:ok, session} = ClaudeCode.start_link(
settings: "/path/to/settings.json"
)Per-query overrides
Both :system_prompt and :append_system_prompt can be overridden at the query level. Query-level options take precedence over session defaults for that single query only:
{:ok, session} = ClaudeCode.start_link(
append_system_prompt: "You are a general coding assistant."
)
# This query uses a different system prompt override
session
|> ClaudeCode.stream("Review this module",
system_prompt: "You are a security auditor. Focus on OWASP vulnerabilities.")
|> ClaudeCode.Stream.text_content()
|> Enum.each(&IO.write/1)
# Next query goes back to the session default
session
|> ClaudeCode.stream("Help me write tests")
|> ClaudeCode.Stream.text_content()
|> Enum.each(&IO.write/1)Comparison of approaches
| Feature | CLAUDE.md | Output Styles | :append_system_prompt | Custom :system_prompt | :settings |
|---|---|---|---|---|---|
| Persistence | Per-project file | Saved as files | Session only | Session only | Session only |
| Reusability | Per-project | Across projects | Code duplication | Code duplication | File or code |
| Management | On filesystem | CLI + files | In code | In code | In code |
| Default tools | Preserved | Preserved | Preserved | Lost (unless included) | Preserved |
| Built-in safety | Maintained | Maintained | Maintained | Must be added | Maintained |
| Environment context | Automatic | Automatic | Automatic | Must be provided | Automatic |
| Customization level | Additions only | Replace default | Additions only | Complete control | Key-value config |
| Version control | With project | Yes | With code | With code | File or code |
| Scope | Project-specific | User or project | Code session | Code session | Code session |
Use cases and best practices
When to use CLAUDE.md
Best for:
- Project-specific coding standards and conventions
- Documenting project structure and architecture
- Listing common commands (build, test, deploy)
- Team-shared context that should be version controlled
- Instructions that apply to all SDK usage in a project
Examples:
- "All API endpoints should use plug pipelines and proper error tuples"
- "Run
mix qualitybefore committing" - "Database migrations are in the
priv/repo/migrations/directory"
Important: To load CLAUDE.md files, you must explicitly set :setting_sources to ["project"]. Using :system_prompt alone does not automatically load CLAUDE.md without this setting.
When to use output styles
Best for:
- Persistent behavior changes across sessions
- Team-shared configurations
- Specialized assistants (code reviewer, data scientist, DevOps)
- Complex prompt modifications that need versioning
Examples:
- Creating a dedicated SQL optimization assistant
- Building a security-focused code reviewer
- Developing a teaching assistant with specific pedagogy
When to use :append_system_prompt
Best for:
- Adding specific coding standards or preferences
- Customizing output formatting
- Adding domain-specific knowledge
- Modifying response verbosity
- Enhancing Claude Code's default behavior without losing tool instructions
When to use custom :system_prompt
Best for:
- Complete control over Claude's behavior
- Specialized single-session tasks
- Testing new prompt strategies
- Situations where default tools are not needed
- Building specialized agents with unique behavior
Combining approaches
You can combine these methods for maximum flexibility:
# Assuming an output style is active (via /output-style),
# add session-specific focus areas
{:ok, result} = ClaudeCode.query("Review this authentication module",
append_system_prompt: """
For this review, prioritize:
- OAuth 2.0 compliance
- Token storage security
- Session management
""",
setting_sources: ["project"]
)See also
- Output styles -- Complete output styles documentation
- Configuration guide -- General configuration options
- Permissions -- Control tool access
- Subagents -- Custom agent definitions with specialized prompts
- Sessions -- Session management and multi-turn conversations