Three-tier memory for AI agents. Keeps context clean, relevant, and manageable — no more drowning your LLM in 3000+ characters of diary before it can think.
Battle-tested in production at Forged Logic.
Most AI memory tools dump every conversation into the context window. After 50 exchanges, your agent's identity prompt gets silently truncated and it reverts to generic assistant behavior.
pyforge-memory uses three tiers instead:
| Tier | What it is | Budget | Behavior |
|---|---|---|---|
| Verbatim | Last N exchanges exactly as they happened | ~400 chars | Keeps the flow |
| Keyword | Memory entries matching keywords in the current message | ~300 chars | Relevant recall |
| Digest | Compressed rolling summary of older conversations | ~300 chars | Continuity |
Total context drops from ~3000 characters to ~1000 — and every character is the right character.
- Three-tier architecture — verbatim recency, keyword relevance, compressed history
- Poison filtering — detects and blocks generic assistant-script output before it poisons memory
- Configurable — set your own forbidden terms, stop words, memory limits
- File-based — JSONL storage, no database, no API keys, runs anywhere
- Knowledge directory — keyword-search across text files for domain context
- Framework agnostic — works with any LLM API (Ollama, OpenAI, Claude, local)
pip install pyforge-memoryfrom pyforge_memory import MemoryEngine
# Initialize with storage paths
engine = MemoryEngine(
memory_dir="./my_agent/memory",
knowledge_dir="./my_agent/knowledge"
)
# Your LLM callable (any function that takes messages and returns text)
def llm_call(messages):
# ... call your LLM here ...
return response
# Build context for each user message
messages = engine.build_context(
user_message="what did we discuss about the database schema?",
system_prompt="You are a helpful coding assistant.",
query_fn=llm_call,
)
# Send to your LLM
response = llm_call(messages)
# Save the exchange
engine.save_exchange("what did we discuss about the database schema?", response)User message arrives
│
▼
┌──────────────────┐
│ 1. Extract │ Pull meaningful keywords, strip stop words
│ keywords │
└──────┬───────────┘
│
▼
┌──────────────────┐
│ 2. Verbatim │ Last N raw exchanges, poison-filtered,
│ layer │ near-duplicate detection
└──────┬───────────┘
│
▼
┌──────────────────┐
│ 3. Keyword │ Search memory + knowledge files
│ layer │ for keyword matches, score and rank
└──────┬───────────┘
│
▼
┌──────────────────┐
│ 4. Digest │ Compressed summary of old conversations
│ layer │ auto-generated when memory > 10 entries
└──────┬───────────┘
│
▼
┌──────────────────┐
│ 5. Assemble │ [system] + verbatim + keyword + digest
│ context │ + [user] → ready for LLM
└──────────────────┘
engine = MemoryEngine(
forbidden_terms=[
"i am an ai assistant",
"as a language model",
# Add your own patterns
]
)
# Check any text
if engine.is_poisoned("As an AI assistant, I cannot..."):
print("Caught it!")Drop text files into your knowledge directory. They're keyword-searched when relevant:
my_agent/knowledge/
├── database-schema.txt
├── api-docs.txt
└── coding-conventions.txt
- Verbatim alone → loses context from older conversations
- Keyword alone → loses the flow of the current conversation
- Digest alone → too compressed, misses specifics
Three tiers together: recency + relevance + compression.
MIT © The Constellation Forge
If this helped your project, tips are welcome:
GyhqwvFv4ZX3co7T2tziLZTU1vMJoYjfJx2dpG3FPXsc