Memory, personality, and context continuity for LLM agents. Python implementation inspired by OpenClaw's architecture, using AWS Bedrock.
pip install -e ./pyclawmemfrom pyclawmem import AgentMemory
agent = AgentMemory.from_config("path/to/CONFIG.yaml")
session = agent.start_session()
# Your message loop:
prepared = agent.before_llm_call("What's the status of the project?", session)
response = your_llm_call(prepared.messages, prepared.system_prompt)
agent.after_llm_call(response, session)
# When done:
agent.end_session(session)
agent.close()before_llm_call handles auto-recall, context pruning, and compaction automatically.
after_llm_call persists the response to the session transcript.
end_session auto-captures facts and exports the session to markdown.
import chainlit as cl
from pyclawmem import AgentMemory
agent = AgentMemory.from_config("CONFIG.yaml")
@cl.on_chat_start
async def start():
session = agent.start_session()
cl.user_session.set("session", session)
await cl.Message(content=f"Hi! I'm {agent.identity.name}.").send()
@cl.on_message
async def on_message(message: cl.Message):
session = cl.user_session.get("session")
prepared = agent.before_llm_call(message.content, session)
# Call your LLM (Bedrock, OpenAI, etc.)
response = await call_your_llm(prepared.messages, prepared.system_prompt)
agent.after_llm_call(response, session)
await cl.Message(content=response).send()
@cl.on_chat_end
async def end():
session = cl.user_session.get("session")
if session:
agent.end_session(session)agent.identity # AssistantIdentity(name, avatar, emoji)
agent.message_prefix # "[AgentName]" for outbound messages
agent.context_tokens # Effective context window sizeagent.search_memory("authentication flow") # File-based hybrid search
agent.search_facts("user preferences") # Conversational fact search
agent.store_fact("User prefers dark mode") # Manual fact storage
agent.forget_fact("abc123") # GDPR deletion
agent.resolve_typing_mode(is_group_chat=True)pyclawmem/
├── CONFIG.yaml # Model IDs, regions, tuning parameters
├── memory/
│ ├── types.py # Pydantic data models
│ ├── embeddings.py # Bedrock Titan embeddings
│ ├── store.py # SQLite + FTS5 storage
│ └── manager.py # Hybrid search, file indexing, sync
├── personality/
│ ├── soul.py # SOUL.md loading + system prompt
│ ├── identity.py # IDENTITY.md parsing
│ └── workspace.py # Bootstrap file management
├── context/
│ ├── session.py # JSONL transcript persistence
│ ├── compaction.py # LLM summarization when context fills
│ └── pruning.py # Stale context removal
└── integration.py # Example: how to wire into an agent loop
boto3 # AWS Bedrock API calls
numpy # Vector normalization and cosine similarity
pydantic # Data models and validation
pyyaml # CONFIG.yaml parsing
Install: pip install boto3 numpy pydantic pyyaml
Edit CONFIG.yaml to set:
- Embedding model: Bedrock Titan model ID and dimensions
- LLM model: Bedrock Claude model for compaction summaries
- Memory: SQLite path, chunk size, hybrid search weights
- Context: Token budget, compaction threshold
- Workspace: Bootstrap files directory
AWS credentials are resolved via standard boto3 chain (env vars, ~/.aws/credentials, IAM role).
Files in the workspace memory/ directory are chunked, embedded via Bedrock Titan, and stored in SQLite. Search combines:
- Vector similarity (cosine, 70% weight) — finds semantically related content
- BM25 keyword search (FTS5, 30% weight) — finds exact term matches
Results are merged, deduped by (path, line), and scored.
Workspace bootstrap files define the agent's identity:
| File | Purpose |
|---|---|
SOUL.md |
Persona, values, behavioral philosophy |
IDENTITY.md |
Structured: name, emoji, creature, vibe, avatar |
USER.md |
Who the human is |
AGENTS.md |
Operating manual |
TOOLS.md |
Environment-specific notes |
MEMORY.md |
Curated long-term memory |
These are loaded into the system prompt as "Project Context". SOUL.md gets special treatment: the system prompt explicitly instructs the LLM to embody its persona.
- Session persistence: JSONL transcripts with auto-repair for corrupted files
- Compaction: When context exceeds 85% of budget, older messages are LLM-summarized. Tool failures and file operations are preserved across compaction.
- Pruning: Stale context (old identity reads, expired memory injections) is removed before each LLM call.
To integrate pyclawmem into your agent, hook into these lifecycle events:
from pyclawmem.personality.workspace import load_bootstrap_files, build_context_prompt
from pyclawmem.memory.manager import MemoryManager
# Build system prompt from personality files
files = load_bootstrap_files("~/.pyclawmem/workspace")
system_prompt = build_context_prompt(files)
# Sync memory index
memory.sync(["~/.pyclawmem/workspace/memory"])from pyclawmem.context.pruning import prune_stale_context
from pyclawmem.context.compaction import needs_compaction, compact, apply_compaction
# Auto-recall: search memory for relevant context
results = memory.search(user_message)
# Inject results as <relevant-memories> in system context
# Prune stale context
messages = prune_stale_context(messages)
# Compact if needed
if needs_compaction(messages, max_tokens):
result = compact(messages, model_id="anthropic.claude-3-haiku-20240307-v1:0")
messages = apply_compaction(messages, result)from pyclawmem.context.session import SessionStore
# Persist to transcript
sessions.append_message(session, assistant_message)memory.close()This is a library, not a complete agent. You still need:
- An LLM call layer (Bedrock Converse, LangChain, etc.)
- A user interface (CLI, web, messaging platform)
- Tool execution framework
- Authentication and access control
pyclawmem provides the memory, personality, and context management that sits between your agent loop and your LLM provider.