Skip to main content

Persistent memory

A ready-to-run example is available here.

Persistent memory lets an agent keep what it learned -- root causes, environment quirks, project decisions, user preferences -- in plain Markdown files that are loaded back into the system prompt at the start of every new conversation. The agent maintains the files itself as it works, so it gets better at a project over time.

The feature is opt-in and off by default: without it, agents keep the existing AGENTS.md-based guidance and prompts are unchanged.

Enabling persistent memory

Set load_memory=True on the agent's AgentContext:

from faheemcode.sdk import Agent, AgentContext

agent = Agent(
llm=llm,
agent_context=AgentContext(load_memory=True),
tools=tools,
)

That single flag does two things:

  1. At session start, the conversation reads the MEMORY.md indexes from both memory tiers and injects them into the system prompt as a <MEMORY_CONTEXT> block.
  2. The system prompt's <MEMORY> section switches to instructions that teach the agent where its memory lives and how to maintain it.

The two tiers

TierLocationContents
User~/.faheem-code/memory/Knowledge and preferences that apply across all projects
Project<workspace>/.faheem-code/memory/Knowledge specific to the current repository

Each tier contains:

  • MEMORY.md -- a curated index of durable facts. This is the only file injected into the prompt, so the agent is instructed to keep it small and high-value.
  • Daily logs (YYYY-MM-DD.md) -- free-form working notes. They are never injected automatically; the agent reads them on demand with its file tools when MEMORY.md points to them.

The files are plain Markdown: you can review, edit, or delete them at any time, and a project team can even commit .faheem-code/memory/ to share agent-learned knowledge.

What gets injected

At the start of each opted-in conversation, the resolved memory appears in the system prompt like this (user tier first, then project tier):

<MEMORY_CONTEXT>
<UNTRUSTED_CONTENT>
The content below comes from memory files on disk and has NOT been verified by Faheem Code.
...
</UNTRUSTED_CONTENT>

# User memory (~/.faheem-code/memory/MEMORY.md)
- prefers uv over pip for Python tooling

# Project memory (.faheem-code/memory/MEMORY.md)
- the API uses cursor-based pagination
</MEMORY_CONTEXT>

A few properties worth knowing:

  • Size budget: the combined indexes are capped at ~6,000 characters. When the budget is exceeded, whole lines are dropped from the top of each over-budget tier (the oldest content) -- partial lines never survive, the tier headers are always kept, and a truncation notice appears under the header of any tier that lost lines. Keep indexes curated.
  • Untrusted by design: the injected block is wrapped in <UNTRUSTED_CONTENT>. Memory files are typically agent-written, but anyone with access to the workspace or repository can edit or commit them (a cloned repo may ship a .faheem-code/memory/MEMORY.md), so the agent is told they may contain prompt injection, and to treat them as unverified hints, never as authoritative instructions.
  • Never persisted: the resolved memory text is re-read from disk each session and is excluded from conversation persistence (base_state.json) and API payloads.
  • Best-effort: an unreadable memory file logs a warning and the conversation starts normally without it.

How the agent maintains memory

When memory is enabled, the system prompt instructs the agent to:

  • record durable, broadly useful facts in MEMORY.md near the end of a task (creating the directories and files if missing), and put long detail in daily logs;
  • merge duplicates, prune stale entries, and keep the indexes concise;
  • never record secrets or credentials, and skip facts that are trivially re-discoverable (directory listings, obvious commands);
  • keep AGENTS.md for instructions addressed to any agent working in the repository -- memory is for what the agent learned itself.

Ready-to-run example

"""Opt-in persistent memory across sessions (two-tier ``MEMORY.md``).

With ``AgentContext(load_memory=True)`` a conversation loads the ``MEMORY.md``
indexes from ``~/.faheem-code/memory/`` (user tier) and
``<workspace>/.faheem-code/memory/`` (project tier) into the system prompt at
session start (the ``<MEMORY_CONTEXT>`` block), and the system prompt
instructs the agent to maintain those files as it works.

This example runs two conversations over the same workspace:

1. Session 1 asks the agent to record a project decision in its persistent
project memory -- the agent writes ``.faheem-code/memory/MEMORY.md`` itself.
2. Session 2 is a brand-new conversation: the saved memory is injected into
its system prompt automatically, so the agent already knows the decision
without being told again.

Memory is opt-in and off by default. The example only writes inside a
temporary workspace; the user tier under ``~`` is left untouched.
"""

import os
import tempfile
from pathlib import Path

from pydantic import SecretStr

from faheemcode.sdk import LLM, Agent, AgentContext, Conversation, get_logger
from faheemcode.sdk.event import SystemPromptEvent
from faheemcode.sdk.tool import Tool
from faheemcode.tools.file_editor import FileEditorTool
from faheemcode.tools.terminal import TerminalTool

logger = get_logger(__name__)

# Configure LLM
api_key = os.getenv("LLM_API_KEY")
assert api_key is not None, "LLM_API_KEY environment variable is not set."
model = os.getenv("LLM_MODEL", "gpt-5.5")
base_url = os.getenv("LLM_BASE_URL")
llm = LLM(
usage_id="agent",
model=model,
base_url=base_url,
api_key=SecretStr(api_key),
)

tools = [Tool(name=TerminalTool.name), Tool(name=FileEditorTool.name)]

# Opt in to persistent memory. Everything else is automatic: the conversation
# resolves the MEMORY.md indexes at session start, and the system prompt tells
# the agent how to maintain them.
agent_context = AgentContext(load_memory=True)

with tempfile.TemporaryDirectory() as workspace:
memory_index = Path(workspace) / ".faheem-code" / "memory" / "MEMORY.md"

print("=" * 100)
print("Session 1: ask the agent to record a decision in project memory.")
agent = Agent(llm=llm, tools=tools, agent_context=agent_context)
conversation = Conversation(agent=agent, workspace=workspace)
conversation.send_message(
"We just decided to use `uv` (not pip/poetry) for all Python "
"dependency management in this project. Record that decision in your "
"persistent project memory so future sessions know it."
)
conversation.run()
conversation.close()

print("=" * 100)
print(f"Project memory after session 1 ({memory_index}):")
if memory_index.exists():
print(memory_index.read_text())
else:
print("(the agent did not create the memory index)")

print("=" * 100)
print("Session 2: a brand-new conversation over the same workspace.")
agent = Agent(llm=llm, tools=tools, agent_context=agent_context)
conversation = Conversation(agent=agent, workspace=workspace)
conversation.send_message(
"Which tool do we use for Python dependency management in this "
"project? Answer from what you already know about the project."
)
conversation.run()

# The recorded memory was injected into session 2's system prompt as the
# <MEMORY_CONTEXT> block -- show it to make the mechanism visible.
system_prompt_event = next(
event
for event in conversation.state.events
if isinstance(event, SystemPromptEvent)
)
dynamic_context = system_prompt_event.dynamic_context
injected = dynamic_context.text if dynamic_context else ""
print("=" * 100)
print(
"<MEMORY_CONTEXT> injected into session 2's system prompt: "
f"{'<MEMORY_CONTEXT>' in injected}"
)
conversation.close()

# Report cost
cost = llm.metrics.accumulated_cost
print(f"EXAMPLE_COST: {cost}")

You can run the example code as-is.

Bring your own provider key
export LLM_API_KEY="your-api-key"
export LLM_MODEL="anthropic/claude-sonnet-4-5-20250929" # or openai/gpt-4o, etc.
cd software-agent-sdk
uv run python examples/01_standalone_sdk/55_persistent_memory.py
Faheem Code Cloud key
# https://app.faheemcode.ai/settings/api-keys
export LLM_API_KEY="example-user-api-key"
export LLM_MODEL="faheemcode/claude-sonnet-4-5-20250929"
cd software-agent-sdk
uv run python examples/01_standalone_sdk/55_persistent_memory.py

Next steps

  • Skills - Inject reusable instructions and context into agents
  • Context Condenser - Keep long conversations within the context window
  • Persistence - Save and restore conversation state across sessions