System Prompts & Planning

Now that you have a working agent from Module 1, it’s time to learn how to control how it thinks and plans. Deep Agents gives you powerful tools to shape your agent’s behavior through system prompts and planning strategies.

Exercise 1: Custom System Prompts

Let’s create an agent with a specific persona — a senior Python code reviewer.

  1. Create the review agent script:

    • Run

    • Code Preview

    cat > review_agent.py << 'EOF'
    import os
    from deepagents import create_deep_agent
    from utils import agent_response
    
    MODEL = os.environ.get("DEEPAGENTS_MODEL", "anthropic:claude-sonnet-4-6")
    
    agent = create_deep_agent(
        model=MODEL,
        system_prompt="""You are a senior Python code reviewer.
    When reviewing code, always check for:
    1. Type safety and proper type hints
    2. Error handling
    3. Security vulnerabilities
    4. Performance considerations
    
    Be direct and specific in your feedback.""",
    )
    
    result = agent.invoke({"messages": [("user", """Review this code:
    
    def get_user(id):
        data = eval(open(f"users/{id}.json").read())
        return data
    """)]})
    
    print(agent_response(result))
    EOF
    import os
    from deepagents import create_deep_agent
    from utils import agent_response
    
    MODEL = os.environ.get("DEEPAGENTS_MODEL", "anthropic:claude-sonnet-4-6")
    
    agent = create_deep_agent(
        model=MODEL,
        system_prompt="""You are a senior Python code reviewer.
    When reviewing code, always check for:
    1. Type safety and proper type hints
    2. Error handling
    3. Security vulnerabilities
    4. Performance considerations
    
    Be direct and specific in your feedback.""",
    )
    
    result = agent.invoke({"messages": [("user", """Review this code:
    
    def get_user(id):
        data = eval(open(f"users/{id}.json").read())
        return data
    """)]})
    
    print(agent_response(result))
  2. Run the review agent:

    uv run review_agent.py
    Sample output (your results may vary)
    This code has several serious issues:
    
    1. Type safety and proper type hints: Missing type hints for the function parameter and return value.
    
    2. Error handling: No try/except blocks to handle potential file read errors or JSON parsing failures.
    
    3. Security vulnerabilities: CRITICAL - Using eval() on file contents is extremely dangerous. It will execute arbitrary Python code, creating a severe security vulnerability. Use json.load() instead.
    
    4. Performance considerations: The f-string file path construction is vulnerable to path traversal attacks.
    
    Recommended fix:
    def get_user(user_id: str) -> dict:
        import json
        from pathlib import Path
    
        file_path = Path("users") / f"{user_id}.json"
        with open(file_path) as f:
            return json.load(f)

The system_prompt parameter is prepended to BASE_AGENT_PROMPT — the agent still has all its built-in capabilities (tool use, planning, etc.), but now also has your custom instructions. This lets you add domain expertise without losing the core agent behavior.

Exercise 2: The Base Prompt

Let’s explore what BASE_AGENT_PROMPT actually contains.

  1. Create a script to inspect the base prompt:

    • Run

    • Code Preview

    cat > inspect_prompt.py << 'EOF'
    from deepagents.graph import BASE_AGENT_PROMPT
    
    print(BASE_AGENT_PROMPT[:2000])
    print(f"\n... ({len(BASE_AGENT_PROMPT)} total characters)")
    EOF
    from deepagents.graph import BASE_AGENT_PROMPT
    
    print(BASE_AGENT_PROMPT[:2000])
    print(f"\n... ({len(BASE_AGENT_PROMPT)} total characters)")
  2. Run the inspection script:

    uv run inspect_prompt.py
    Sample output (your results may vary)
    You are a helpful AI assistant with access to tools. When given a task:
    
    1. Analyze the request carefully
    2. Determine which tools you need to use
    3. Execute the tools in the correct order
    4. Synthesize the results into a helpful response
    
    TOOL USAGE GUIDELINES:
    
    When using tools, always:
    - Check that required parameters are present
    - Validate inputs before making tool calls
    - Handle errors gracefully
    - Provide clear feedback about what you're doing
    
    BEHAVIORAL GUIDELINES:
    
    For complex tasks:
    - Break down the problem into manageable steps
    - Use the write_todos tool to plan your approach
    - Execute systematically and track progress
    ...
    
    ... (8547 total characters)

You’ll see this is no simple "you are a helpful assistant" prompt. It’s a comprehensive instruction manual covering:

  • Detailed tool usage instructions

  • Behavioral guidelines for complex tasks

  • Output formatting expectations

  • Error handling strategies

This is the "detailed system prompt" pillar in action — giving the LLM clear, specific guidance on how to operate as an agent.

You might wonder about the cost of such a large system prompt. Claude Code’s system prompt is reportedly around 16,000 words — a third of a novel! This is viable because Deep Agents includes AnthropicPromptCachingMiddleware in its middleware stack, which caches the system prompt across invocations. You pay the full token cost once, then subsequent calls reuse the cached prompt at a fraction of the cost. Verbose, detailed system prompts are an investment that pays off through caching.

Exercise 3: Planning with Todos

For complex multi-step tasks, Deep Agents can plan out the work before executing. Let’s see this in action.

  1. Create the planning agent script:

    • Run

    • Code Preview

    cat > planning_agent.py << 'EOF'
    import os
    from deepagents import create_deep_agent
    from utils import agent_response
    
    MODEL = os.environ.get("DEEPAGENTS_MODEL", "anthropic:claude-sonnet-4-6")
    
    agent = create_deep_agent(model=MODEL)
    
    result = agent.invoke({"messages": [("user",
        "Create a Python project structure for a REST API with "
        "user authentication, database models, and tests. "
        "Plan out the work first, then create the files."
    )]})
    
    # Show planning tool calls
    for msg in result["messages"]:
        if hasattr(msg, 'tool_calls'):
            for tc in msg.tool_calls:
                if tc['name'] == 'write_todos':
                    print("Planning step detected!")
                    print(f"Todos: {tc['args']}")
    
    # Show the final response
    print("\n=== Agent Response ===")
    print(agent_response(result))
    EOF
    import os
    from deepagents import create_deep_agent
    from utils import agent_response
    
    MODEL = os.environ.get("DEEPAGENTS_MODEL", "anthropic:claude-sonnet-4-6")
    
    agent = create_deep_agent(model=MODEL)
    
    result = agent.invoke({"messages": [("user",
        "Create a Python project structure for a REST API with "
        "user authentication, database models, and tests. "
        "Plan out the work first, then create the files."
    )]})
    
    # Show planning tool calls
    for msg in result["messages"]:
        if hasattr(msg, 'tool_calls'):
            for tc in msg.tool_calls:
                if tc['name'] == 'write_todos':
                    print("Planning step detected!")
                    print(f"Todos: {tc['args']}")
    
    # Show the final response
    print("\n=== Agent Response ===")
    print(agent_response(result))
  2. Run the planning agent:

    uv run planning_agent.py
    Sample output (your results may vary)
    Planning step detected!
    Todos: {'todos': [
      '[ ] Create project directory structure with src/, tests/, and config folders',
      '[ ] Create database models (User, Session) in src/models/',
      '[ ] Create authentication handlers in src/auth/',
      '[ ] Create REST API endpoints in src/api/',
      '[ ] Create test files for models and API endpoints',
      '[ ] Create requirements.txt and basic configuration'
    ]}

The write_todos tool is provided by TodoListMiddleware — a context engineering strategy. By giving the agent a way to write down a plan, it can break complex tasks into manageable steps and track progress.

Exercise 4: Guiding Planning Behavior

You can use system prompts to influence how the agent plans.

  1. Create the guided planning script:

    • Run

    • Code Preview

    cat > guided_planning.py << 'EOF'
    import os
    from deepagents import create_deep_agent
    from utils import agent_response
    
    MODEL = os.environ.get("DEEPAGENTS_MODEL", "anthropic:claude-sonnet-4-6")
    
    agent = create_deep_agent(
        model=MODEL,
        system_prompt="""Before starting any task:
    1. Always create a todo list with write_todos
    2. Break work into steps of no more than 3 files each
    3. Complete and check off each step before moving to the next
    4. Never skip the planning phase""",
    )
    
    result = agent.invoke({"messages": [("user",
        "Create a Python project structure for a REST API with "
        "user authentication, database models, and tests."
    )]})
    
    # Show planning tool calls
    for msg in result["messages"]:
        if hasattr(msg, 'tool_calls'):
            for tc in msg.tool_calls:
                if tc['name'] == 'write_todos':
                    print("Planning step detected!")
                    print(f"Todos: {tc['args']}")
    
    # Show the final response
    print("\n=== Agent Response ===")
    print(agent_response(result))
    EOF
    import os
    from deepagents import create_deep_agent
    from utils import agent_response
    
    MODEL = os.environ.get("DEEPAGENTS_MODEL", "anthropic:claude-sonnet-4-6")
    
    agent = create_deep_agent(
        model=MODEL,
        system_prompt="""Before starting any task:
    1. Always create a todo list with write_todos
    2. Break work into steps of no more than 3 files each
    3. Complete and check off each step before moving to the next
    4. Never skip the planning phase""",
    )
    
    result = agent.invoke({"messages": [("user",
        "Create a Python project structure for a REST API with "
        "user authentication, database models, and tests."
    )]})
    
    # Show planning tool calls
    for msg in result["messages"]:
        if hasattr(msg, 'tool_calls'):
            for tc in msg.tool_calls:
                if tc['name'] == 'write_todos':
                    print("Planning step detected!")
                    print(f"Todos: {tc['args']}")
    
    # Show the final response
    print("\n=== Agent Response ===")
    print(agent_response(result))
  2. Run the guided planning agent:

    uv run guided_planning.py
    Sample output (your results may vary)
    Planning step detected!
    Todos: {'todos': [
      '[ ] Step 1: Create base project structure (pyproject.toml, README.md, .gitignore)',
      '[ ] Step 2: Create user and session models (src/models/user.py, src/models/session.py)',
      '[ ] Step 3: Create authentication module (src/auth/handlers.py, src/auth/middleware.py)',
      '[ ] Step 4: Create API endpoints (src/api/routes.py, src/api/dependencies.py)',
      '[ ] Step 5: Create test files (tests/test_models.py, tests/test_auth.py, tests/test_api.py)'
    ]}

Compare the planning behavior with and without the custom instructions. The system prompt gives you fine-grained control over the agent’s approach.

CLI Note: The deepagents CLI uses its own built-in system prompt and doesn’t support custom system prompts via command-line flags. Custom system prompts are a programmatic feature — use them in your Python scripts with create_deep_agent(system_prompt=…​). The CLI is best for quick interactive sessions with the default harness behavior.

Module Summary

In this module, you accomplished:

  • Created agents with custom personas using system_prompt

  • Explored the comprehensive BASE_AGENT_PROMPT

  • Observed planning behavior with write_todos

  • Guided planning through system prompt instructions

Key takeaways:

  • System prompts are prepended to the base prompt, adding domain expertise

  • The base prompt is a detailed instruction manual, not a simple directive

  • Todo lists are a context engineering strategy for complex tasks

  • System prompts can shape both what the agent does and how it plans

Next up: you’ll explore the filesystem tools and storage backends that make agents truly useful for code and file manipulation.