Skip to content

Self-Improving AI Agents: The System Prompt Evolution Pattern 🧬

Published: January 10, 2025

What if your AI agent could learn and evolve across sessions? This post explores the system prompt evolution pattern used by both DevDuck and Strands-Coder to enable continuous self-improvement.

The Core Concept

flowchart TB
    subgraph "Session N"
        Q1[User Query] --> E1[Execute]
        E1 --> L1[Learn Something]
        L1 --> U1[Update System Prompt]
        U1 --> S1[Store in KB]
    end

    subgraph "Session N+1"
        Q2[User Query] --> R2[Retrieve from KB]
        R2 --> P2[Load Updated Prompt]
        P2 --> E2[Execute with New Knowledge]
    end

    S1 -->|Persisted| R2
    U1 -->|GitHub Variable| P2

    style L1 fill:#f9f,stroke:#333,stroke-width:4px
    style U1 fill:#bbf,stroke:#333,stroke-width:4px

Key Insight

Every agent execution is an opportunity to learn. The system prompt isn't static—it's a living document that grows with the agent's experience.

The Evolution Tools

1. System Prompt Management

@tool
def system_prompt(
    action: str,        # view, update, add_context, reset
    prompt: str = None,
    context: str = None,
    repository: str = None,
    variable_name: str = "SYSTEM_PROMPT"
) -> dict:

Actions: - view: See current prompt - update: Replace entire prompt - add_context: Append new learning - reset: Clear and start fresh

2. Knowledge Base Storage

@tool
def store_in_kb(
    content: str,
    title: str = None,
    knowledge_base_id: str = None
) -> dict:

Stores execution summaries for future retrieval.

The Self-Improvement Loop

sequenceDiagram
    participant Agent
    participant KB as Knowledge Base
    participant SP as System Prompt
    participant GH as GitHub Variable

    Note over Agent: Start Execution

    Agent->>KB: retrieve(current_task)
    KB->>Agent: Related past learnings

    Agent->>Agent: Execute with context

    Note over Agent: Discover something new!

    Agent->>SP: system_prompt(action="add_context")
    SP->>GH: Update SYSTEM_PROMPT variable

    Agent->>KB: store_in_kb(execution_summary)

    Note over Agent: Next session starts with<br/>updated knowledge

Implementation Pattern

Step 1: Retrieve Before Acting

# Always check what you've learned before
kb_id = os.getenv("STRANDS_KNOWLEDGE_BASE_ID")
if kb_id:
    agent.tool.retrieve(
        text=user_query,
        knowledgeBaseId=kb_id
    )

Step 2: Execute with Context

# System prompt already includes:
# - Base instructions
# - GitHub event context
# - Project state
# - Self-awareness (own code)
# - Past learnings (from KB retrieve)

result = agent(enhanced_prompt)

Step 3: Learn and Store

# After execution, store what happened
agent.tool.store_in_kb(
    content=f"Input: {query}\nResult: {result}",
    title=f"Execution: {datetime.now()}"
)

# If learned something significant
if significant_learning:
    agent.tool.system_prompt(
        action="add_context",
        context=f"Learning: {what_was_learned}",
        repository="owner/repo"  # Persist to GitHub
    )

Real-World Example: Strands-Coder

From the actual SYSTEM_PROMPT.md:

## 🧠 CORE DIRECTIVE: Self-Update Every Turn

**MANDATORY**: At the END of every execution, I MUST:
1. **Reflect** on what I learned or did
2. **Store** execution summary in KB via `store_in_kb()`
3. **Update** system prompt if I learned something important
   via `system_prompt(action="add_context")`

This makes me continuously improve.

Evolution Log Example

## 📝 Evolution Log

| Date | Change |
|------|--------|
| 2026-02-01 | Rewrote from scratch - quality over quantity |
| 2026-01-15 | Memory & learning protocol added |
| 2026-01-13 | Shell timeout best practices (by @cagataycali) |
| 2026-01-13 | Comment quality guidelines (by @zastrowm) |
| 2026-01-12 | AI disclosure footer mandatory |

The Learning Categories

mindmap
  root((Agent Learnings))
    Anti-Patterns
      Comment Noise
      Untested Code
      Duplicate PRs
    Quality Patterns
      Test First
      One PR Per Issue
      Inline Reviews
    Tool Usage
      Token Selection
      Timeout Settings
      Project Board
    Community Feedback
      User Preferences
      Review Guidelines
      Disclosure Rules

Types of Learnings

  1. Anti-Patterns: Things to NEVER do

    system_prompt(
        action="add_context",
        context="NEVER: Create multiple PRs for same issue. Iterate on one branch."
    )
    

  2. Quality Patterns: Best practices discovered

    system_prompt(
        action="add_context",
        context="ALWAYS: Run `hatch fmt && hatch test` before commit"
    )
    

  3. User Feedback: Corrections and preferences

    system_prompt(
        action="add_context",
        context="USER FEEDBACK: @username prefers detailed explanations"
    )
    

Two-Tier Memory System

flowchart TB
    subgraph "Short-Term Memory"
        KB[(Knowledge Base)]
        Conv[Conversation Context]
        Events[Recent Events]
    end

    subgraph "Long-Term Memory"
        SP[System Prompt]
        GH[GitHub Variable]
        Code[Embedded in Code]
    end

    KB -->|retrieve| Agent
    Conv -->|session| Agent
    Events -->|dynamic| Agent

    Agent -->|store_in_kb| KB
    Agent -->|add_context| SP
    SP -->|sync| GH

    style SP fill:#f9f,stroke:#333,stroke-width:4px

Short-Term (KB)

  • Execution summaries
  • Recent conversations
  • Temporary context
  • Search-based retrieval

Long-Term (System Prompt)

  • Core behaviors
  • Learned rules
  • Anti-patterns
  • Quality standards

DevDuck Implementation

def _build_system_prompt(self):
    """Build adaptive system prompt."""

    # 1. Load base prompt from env/file
    base = _get_system_prompt()

    # 2. Add environment context
    context = f"""
    Environment: {platform.system()} {platform.machine()}
    Python: {sys.version_info}
    Model: {self.model}
    """

    # 3. Add own source code (self-awareness)
    own_code = get_own_source_code()

    # 4. Add conversation history
    recent = get_last_messages()

    # 5. Add recent logs
    logs = get_recent_logs()

    return f"{base}\n\n{context}\n\n{own_code}\n\n{recent}\n\n{logs}"

The GitHub Variable Pattern

sequenceDiagram
    participant Agent
    participant Local as Local Env
    participant API as GitHub API
    participant GH as Repository Variable

    Agent->>API: PATCH /actions/variables/SYSTEM_PROMPT
    API->>GH: Update variable

    Note over GH: Persisted across<br/>all runs

    GH->>Local: Next workflow loads
    Local->>Agent: Updated prompt available

Why GitHub Variables?

  1. Persistence: Survives workflow runs
  2. Version Control: Changes are visible
  3. Access Control: Uses same permissions
  4. Multi-Repo: Can sync across repos
def _update_github_repository_variable(repository, name, value, token):
    """Update a GitHub repository variable."""
    url = f"https://api.github.com/repos/{repository}/actions/variables/{name}"
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/vnd.github+json",
    }
    response = requests.patch(url, headers=headers, json={
        "name": name,
        "value": value
    })
    return response.status_code == 204

Best Practices

Self-Improvement Tips

1. Be Selective Don't add every observation. Only persistent, reusable learnings.

2. Be Specific Bad: "Be careful with PRs" Good: "Never create duplicate PRs for same issue. Iterate on one branch."

3. Include Source "Learning from @username on 2025-01-15: ..."

4. Organize by Category Use headers: Anti-Patterns, Quality Patterns, Tool Usage

5. Prune Regularly Review and remove outdated learnings

Avoid Prompt Bloat

System prompts have token limits. Periodically consolidate:

  1. Merge related learnings
  2. Remove redundant entries
  3. Move detailed context to KB
  4. Keep prompt focused on rules

Measuring Evolution

graph LR
    V1[v1: Basic Rules] --> V2[v2: + Anti-Patterns]
    V2 --> V3[v3: + Quality Gates]
    V3 --> V4[v4: + User Feedback]
    V4 --> V5[v5: + Tool Practices]

    style V5 fill:#bfb,stroke:#333,stroke-width:4px

Track your agent's evolution: - Version count: How many updates? - Learning types: What categories grow? - User feedback: How many corrections? - Success rate: Are learnings helping?

The Continuous Learning Mindset

🧠 EVERY EXECUTION = LEARNING OPPORTUNITY

1. Retrieve → What do I already know?
2. Execute → Apply knowledge
3. Observe → What happened?
4. Reflect → What did I learn?
5. Store → Persist for future
6. Evolve → Update my rules

An agent that doesn't learn is just a script. An agent that learns becomes a partner. 🧬