Integrate

Pydantic AI memory: message history, persistence and Harness Memory

Pydantic AI separates three memory problems that are often given the same name: the message history of a conversation, the persistence of that conversation across requests, and long-term memory that survives after the thread ends. The first two are core Pydantic AI primitives. The third is Pydantic AI Harness Memory, a Markdown notebook with scoped tools and pluggable stores. The application still owns tenant identity, retention and deletion.

Updated November 7, 202612 min readAI Memory field guide
A Pydantic AI agent connected to a conversation store and a scoped memory notebook with file-based stores.

Does Pydantic AI have built-in memory?

Pydantic AI has message history and conversation persistence in the core library, plus an optional Harness Memory capability for long-term memory across conversations. The distinction matters because the three layers have different lifetimes, different storage and different failure modes.

Message history is what the model saw during a run and can see again on the next run. Conversation persistence is where that history lives between requests. Harness Memory is a separate notebook that the agent can write, search and delete across runs, scoped by an application-resolved namespace.

What is the difference between message history, persistence and Harness Memory?

These layers compose, but they are not interchangeable. Storing a conversation does not create long-term memory, and a long-term memory notebook does not replace the message history the model needs for the current turn.

LayerQuestion it answersWhere it lives
Message historyWhat did this run and the current conversation contain?In the run result and the `Conversation` object
Conversation persistenceHow do we resume this thread after a restart?Your database or a `ConversationStore`
Step persistenceWhat did each run do, and can we resume or fork it?Pydantic AI Harness `StepPersistence`
Harness MemoryWhat should the agent remember across conversations?A Markdown notebook in a file, SQLite or Postgres store
Source of truthWhat plan, permission or account state is true now?The business system of record

How does Pydantic AI message history work?

After a run, the result exposes `all_messages()` and `new_messages()`, including JSON variants. The messages can be inspected for debugging or passed back to continue a conversation. Pydantic AI also exposes a `Conversation` object that holds the messages plus the running usage, the conversation ID and any deferred tool requests.

To persist a conversation, serialize the `Conversation` with `ConversationTypeAdapter` and store the JSON in your own database, or use a `ConversationStore` that appends only the new messages from each run. Pass the conversation back with `conversation=` on the next run. For crash recovery inside a run, use `StepPersistence`; for a process that must survive a mid-tool-call failure, use durable execution.

  • Store the conversation in a column keyed by `conversation_id`.
  • Append `new_messages()` when you need writes proportional to the turn.
  • Keep the usage and deferred tool requests with the conversation.
  • Use `StepPersistence` for run snapshots, not as a substitute for long-term memory.
  • Do not treat a conversation ID as an authorization token.
Persist and resume a Pydantic AI conversationpython
from pydantic_ai import Agent, ConversationTypeAdapter

agent = Agent('openai:gpt-6.1-sol', instructions='Be a helpful assistant.')

result = agent.run_sync('Tell me a joke.')
stored = ConversationTypeAdapter.dump_json(result.conversation)

conversation = ConversationTypeAdapter.validate_json(stored)
result = agent.run_sync('Explain?', conversation=conversation)

How does Pydantic AI Harness Memory work?

Harness Memory gives each agent a notebook of Markdown files. `MEMORY.md` is the main notebook; other files hold longer or focused notes. The model gets four tools: `write_memory` appends or replaces a unique text fragment, `read_memory` reads a bounded prefix, `delete_memory` deletes a file and `search_memory` searches across the notebook with configured limits.

The notebook lives in a store such as `FileStore`, `InMemoryStore`, `SqliteMemoryStore` or `PostgresMemoryStore`. Writes use optimistic concurrency and an idempotency identifier derived from the run, step and tool call. The application chooses the namespace, not the model, which is the key isolation boundary.

A Pydantic AI agent with Harness Memorypython
from pydantic_ai import Agent
from pydantic_ai.capabilities import LocalWorkspace
from pydantic_ai_harness import Memory
from pydantic_ai_harness.memory import FileStore

agent = Agent(
    'anthropic:claude-opus-5-5',
    capabilities=[LocalWorkspace('.'), Memory(FileStore('.agent-memory'))],
    defer_model_check=True,
)

How should Pydantic AI memory namespaces work?

The namespace is resolved by application code, such as the authenticated user ID from the run dependencies. It is not supplied to the memory tools, so the model cannot select another user’s namespace in a tool call. That is a stronger boundary than a prompt instruction or a model-chosen tenant ID.

The store still needs the right deployment boundary. A `FileStore` that keeps files in the run workspace can be read by other file tools; if namespaces separate users who must not see each other, give the store its own workspace and permissions. For a multi-tenant product, make the tenant the outer scope and test a semantically similar user in another tenant before production.

  • Resolve the namespace from trusted application context.
  • Never let the model choose a tenant or user namespace.
  • Give the store its own workspace when file tools can read the run workspace.
  • Keep tenant and user scope consistent across stores and tools.
  • Test namespace isolation with two users who have similar names.

How does Pydantic AI inject memory into a run?

Automatic injection is on by default. On the first request of a run, Harness Memory adds a `<memory>` block with an excerpt of `MEMORY.md` and the names of the other files, but only when memory changed since the latest snapshot. The guidance, the notebook excerpt and the file listing share `max_tokens`, which defaults to 2,000; `max_lines` defaults to 200 and `max_memory_size` caps each backend read.

Set `inject_memory=False` to keep memory out of the conversation; the tools remain available and the model fetches memory only when it needs it. When the guidance alone fills the budget, nothing is injected and the memory outcome is recorded as `budget_exhausted`. Snapshots are added to the conversation history, so a later snapshot supersedes an earlier one for the same memory.

SettingDefaultWhat it controls
`max_tokens`2,000Guidance, excerpt and file listing budget
`max_lines`200Lines of `MEMORY.md` shown in the snapshot
`max_memory_size`Store-specificMaximum bytes read from the backend
`inject_memory`TrueWhether memory is added to the conversation
`heading`UnsetLabel used for the guidance and memory block

How does Pydantic AI memory interact with compaction?

Long conversations can be compacted by provider-native compaction, `SummarizingCompaction` or a history processor. Harness Memory snapshots are part of the conversation history, so compaction can drop them. When that happens, Memory enqueues the same snapshot again on the same request, without reading the store again.

Keep the conversation history on the server when snapshot metadata matters. A UI round trip that loses the metadata on a snapshot can make the next run produce a fresh snapshot every time. List compaction before Memory in the capability order so Memory sees the history compaction leaves, and test the combination rather than assuming the two features compose automatically.

What are the limits of Pydantic AI memory?

Pydantic AI Harness is on 0.x releases, so the API can change between minor versions. The memory is a Markdown notebook, not a managed multi-tenant memory service: extraction quality, merge behavior, retention and deletion policy are still the application’s responsibility. The core library provides message history and persistence, not a hosted memory control plane.

Memory files can also contain prompt-injection content or sensitive data. Pydantic AI Harness documents artifact scanning for memory files and skills, but scanning is not a substitute for redaction, access control and a deletion workflow. When several frameworks or products need the same durable user context, place an external memory contract behind them.

  • Harness Memory is 0.x; pin versions and read release notes.
  • A Markdown notebook can become noisy or contradictory over time.
  • File tools can read every namespace in the same workspace unless separated.
  • Compaction and snapshots need an explicit test matrix.
  • Deleting a notebook file does not delete application logs or exports.
  • Cross-framework memory needs a provider-neutral contract.

How do you test Pydantic AI memory before production?

Test the conversation layer and the long-term notebook separately. Resume a stored conversation and confirm the messages, usage and deferred tool requests round-trip. Then write a memory note, start a new conversation and confirm the note is injected within the token budget. Change the note and verify the next snapshot supersedes the old one.

Finally, test the boundaries: a second namespace, a second tenant, a read-only workspace, a deletion request and a compaction that drops the snapshot. A memory system is not production-ready until a wrong fact can be corrected and a departing user can disappear from the notebook, the conversation store and every derived copy.

TestPass condition
Conversation round-tripMessages, usage and deferred requests survive serialization
New conversation, same namespaceThe notebook is available within `max_tokens`
Changed memoryThe latest snapshot supersedes the earlier one
Wrong namespaceNo notebook file from another scope is returned
Read-only workspaceWrite and delete tools are hidden or refused
CompactionMemory is re-enqueued without duplicating the store read
DeletionNotebook files and application copies disappear from future reads

What is the recommended Pydantic AI memory architecture?

Use message history and a conversation store for thread continuity. Use Harness Memory when the agent must remember a user across conversations. Keep the namespace application-owned, give the store the right workspace boundary and budget the injected memory. Add an external memory layer when the same context must serve several frameworks or products with centralized correction and deletion.

Frequently asked questions

Does Pydantic AI have built-in memory?

Pydantic AI provides message history and conversation persistence in the core library. Pydantic AI Harness adds an optional Memory capability for long-term memory across conversations.

What is Pydantic AI Harness Memory?

Harness Memory gives an agent a Markdown notebook with `write_memory`, `read_memory`, `delete_memory` and `search_memory` tools over file, SQLite or Postgres stores. The application owns the namespace.

How do you persist a Pydantic AI conversation?

Serialize the `Conversation` with `ConversationTypeAdapter` and store it in your database, or use a `ConversationStore`. Pass the conversation back with `conversation=` on the next run.

How does Harness Memory choose a user namespace?

Application code resolves the namespace, such as the authenticated user ID from the run dependencies. The namespace is not supplied to the memory tools, so the model cannot choose another user’s namespace.

What is the default memory token budget?

Harness Memory shares `max_tokens` across the guidance, the `MEMORY.md` excerpt and the file listing. The default is 2,000 tokens, with `max_lines` defaulting to 200.

When should I use an external memory API with Pydantic AI?

Use one when several frameworks or products need the same durable user context, or when centralized correction, export and deletion are hard requirements beyond one application store.

Store the conversation, scope the notebook

Start with one persisted conversation and one application-owned namespace, then test a changed fact, a compaction and a deletion before expanding.

Pydantic AI Memory: Harness Memory, Namespaces & Stores | AI Memory