Skip to content
Back to blog
Article

/improve: How pydantic-deep Agents Learn from Their Own Session History

Kacper Włodarczyk · · 7 min read · Updated on April 19, 2026
pydantic-ai python ai-agents open-source developer-tools
Table of Contents

For three months my AI agent made the same wrong query every morning.

Search “pydantic”, zero results. Search “pydantic-ai”, forty-seven. Click the right repo. Every. Single. Session.

I would watch it happen, sigh, and move on, because I knew correcting the agent was pointless. By tomorrow it would forget the correction anyway. This is the default state of most AI agents today, and it’s the reason we built /improve.

Kacper Włodarczyk, AI engineering consultant at Vstorm. We’ve shipped 30+ production AI agent systems. pydantic-deep is our open-source agent runtime for Python, built on what we’ve learned from those deployments.

1. The problem: AI agents are stateless by default

Every time you start an agent session, the agent starts from zero.

It doesn’t remember that last Tuesday it tried searching GitHub for “pydantic” and got 0 results, then tried “pydantic-ai” and got 47. It doesn’t remember that you prefer async patterns over sync. It doesn’t remember that the API you’re working with returns paginated results and needs special handling.

For a single-use tool, this is fine. For a coding agent you use every day, it’s a significant limitation. You end up re-explaining the same context repeatedly. The agent makes the same mistakes across sessions.

/improve is our solution to this.

2. What /improve does: the pipeline

/improve is a post-session pipeline that extracts what happened in a session, distills learnings, and writes them to a persistent knowledge file (MEMORY.md) that future sessions load automatically.

Here’s the flow:

  1. 1

    Session ends

    tool_log.jsonl is saved with the raw tool calls (up to 20K chars).

  2. 2

    /improve command triggered

    Manually or as a post-session hook.

  3. 3

    Extraction agent reads raw traces

    Pulls structured UserFactInsight + AgentLearningInsight records.

  4. 4

    Synthesis agent merges insights with raw traces

    Outputs concrete proposed changes to context files.

  5. 5

    MEMORY.md is updated

    Calibrated confidence scores; 0.7 threshold filters out speculation.

  6. 6

    Next session loads MEMORY.md on startup

    Agent begins with everything the previous session learned.

The output isn’t a log file you read later. It’s living documentation that changes how the agent behaves in the next session.

3. UserFactInsight vs AgentLearningInsight

We designed two distinct insight categories because they serve different purposes.

UserFactInsight captures facts about you:

  • “User prefers async Python patterns over sync”
  • “User is working on pydantic-deep, an AI coding agent”
  • “User wants concise responses, not extensive explanations”
  • “User’s projects live in ~/Projects, not ~/code”

AgentLearningInsight captures what the agent learned about the domain, tools, and patterns:

  • “GitHub search works better with ‘pydantic-ai’ than ‘pydantic’”
  • “The Anthropic API returns usage data in stream chunks, not just at completion”
  • “Tool X fails silently on empty input, check before calling”

UserFactInsight personalizes behavior. AgentLearningInsight improves correctness. Both live in MEMORY.md, organized by category.

One design decision worth noting: we relaxed the synthesis rules so that UserFactInsight can be extracted from a single session. Previously, a fact needed to appear across multiple sessions to be included. In practice, a user preference stated clearly once should be remembered.

4. The Meta-Harness finding: raw traces beat summaries

This is the part that surprised us most during development.

We tested two approaches for what input the synthesis agent receives:

Approach A: Extraction agent produces summaries → synthesis works from summaries.

Approach B: Extraction agent produces insights AND passes raw tool traces → synthesis works from both.

Approach B won clearly. We called this the Meta-Harness finding.

Here’s why. Consider a session where the agent searched GitHub:

Summary: “Agent searched GitHub and found the relevant repository.”

Raw trace:

browser.navigate("github.com/search?q=pydantic+agent")
# → 0 results
browser.navigate("github.com/search?q=pydantic-ai+agent")
# → 47 results
browser.click("vstorm-co/pydantic-deep")
# → success

The summary is accurate but loses everything interesting: what the first query was, that it failed, what the agent tried next. The raw trace preserves the full decision path.

From the raw trace, the synthesis agent can extract: “Use ‘pydantic-ai’ not ‘pydantic’ for GitHub searches, the exact package name gets significantly more results.”

From the summary: “GitHub search succeeded.” Useless.

Summaries optimize for readability, but synthesis needs the decision path. The raw trace is the actual evidence. Summaries are lossy compression of that evidence.

Practical implication: tool_log.jsonl now stores up to 20K characters of raw tool call data per session. (The previous limit was 2K, which silently truncated most real sessions.)

5. MEMORY.md as evolving agent knowledge base

MEMORY.md lives at .pydantic-deep/main/MEMORY.md. The agent loads it on startup before any user prompt is processed.

After a few sessions with /improve, it might look like:

# Memory
## User Facts
- Prefers async Python patterns
- Working on pydantic-deep (github.com/vstorm-co/pydantic-deep)
- Projects live in ~/Projects/
- Prefers minimal output, not verbose explanations
## Agent Learnings
- GitHub: use "pydantic-ai" not "pydantic" for better search results
- Anthropic API usage data available in stream (not just completion)
- Project uses underscores in filenames, not hyphens
- Check for empty input before calling file read tools

This file grows and refines with each /improve run. Conflicting information gets resolved. Stale facts get updated.

Key constraint: /improve writes to this file, it doesn’t read from it during extraction. This prevents circular reinforcement of existing beliefs.

6. The bugs we fixed, shipping reality

/improve v0.3.4 shipped with significant reliability fixes:

Crash on {} in prompt templates Template strings passed through str.format(). Any {} in user content caused a KeyError. Fix: escape {{{ before format, unescape after.

Silent failures /improve could fail mid-session and report success. We added: failed_sessions count and last_error message.

API key not loaded The synthesis agent was created before the keystore was queried. Fix: load API keys before instantiating agents.

Wrong model used The synthesis agent was hardcoded to an OpenRouter fallback model. Fixed to use the model from config.toml.

MEMORY.md path mismatch /improve was writing to ./MEMORY.md (project root) rather than .pydantic-deep/main/MEMORY.md (where the agent reads it). The writes were succeeding, but the agent wasn’t reading them.

This last one is the kind of bug that’s invisible until you check: “wait, why isn’t the agent remembering anything?“

7. Closing the arc

This week, pydantic-deep got:

Combine all of these and you have an agent that doesn’t get stuck, doesn’t go blind, runs safely in isolation, can see the web, shows you everything it does and costs, and gets better every time you use it.

Key Takeaways

  • AI agents are stateless by default, every session starts from zero without explicit memory
  • /improve runs post-session, reads tool_log.jsonl, extracts insights, updates MEMORY.md
  • Two insight types: UserFactInsight (about you) and AgentLearningInsight (about the domain)
  • Raw traces beat summaries (Meta-Harness finding), the full decision path is the evidence; summaries are lossy
  • MEMORY.md is the agent’s evolving knowledge base, loaded on startup, updated after /improve
  • Reliability matters, 5 bugs fixed in v0.3.4 that made /improve unreliable in real conditions
  • No retraining required, improvement comes from context, not model weights

This whole week was about pydantic-deep. If you want it plugged into a full-stack app, full-stack-ai-agent-template ships it integrated, from FastAPI backend to Next.js frontend, with pydantic-deep wired in.

Try it

Terminal window
curl -fsSL https://oss.vstorm.co/install.sh | bash

GitHub: github.com/vstorm-co/pydantic-deep

What sessions would you run /improve on first?

Share this article

Ready to ship your AI app?

Pick your frameworks, generate a production-ready project, and deploy. 75+ options, one command, zero config debt.

Need help building production AI agents?