Pluggable memory system with hierarchical recall, FTS search, and multiple backend support.
Project description
Harness Memory
Pluggable long-term memory system for LLM agents — structured recall, full-text search, and automatic knowledge extraction from conversations.
English · 中文
Highlights
- Zero Dependencies — Core package uses only Python stdlib + sqlite3; no heavy ML frameworks required
- L0→L4 Memory Pipeline — Automatic extraction of facts from conversations, promotion to structured atoms, entity pages, and audit journal
- Multi-Stage Recall — 8-stage pipeline: query parsing, routing, rerank, diversify, suppress, token budget, cache, co-reference resolution
- Hierarchical Memory Tree — Manual root → branch → leaf structure; auto-mirrored from the pipeline
- Pluggable Backends — SQLite (default), PostgreSQL
- Host Integrations — Native plugins for OpenClaw and Hermes agent platforms
- Full CLI — 20+ command groups for every layer of the system
How It Works
Harness Memory runs a five-layer pipeline that converts raw conversation events into structured, searchable knowledge:
L0 RawEvent Every message/tool-call captured from the host agent (immutable)
│ LLM extraction (session_end or daily)
▼
L1 Candidate LLM-extracted fact awaiting promotion (Fact/Decision/Task/Preference)
│ 5-check promotion worker (value → evidence → entity → duplicate → conflict)
▼
L2 AtomCard Structured fact linked to an entity, FTS-indexed, append-only
│ grouped by
▼
L3 Entity Anchor node (User/Person/Project/…) + alias table
EntityPage LLM-generated markdown summary, auto-regenerated on change
│ every mutation logged to
▼
L4 Journal Append-only audit log (promote/merge/conflict/deprecate/gc)
At recall time, a query runs through the recall pipeline (router → multi-source gather → rerank → diversify → suppress → budget) and returns snippets from atoms, entity page headlines, the memory tree, and raw events — merged and ranked in a single pass.
Quick Start
Installation
pip install harness-memory
With CLI support:
pip install "harness-memory[cli]"
Optional backends:
pip install "harness-memory[postgres]" # PostgreSQL backend
Python API
from harness_memory import Memory
from harness_memory.recall import recall_for_prompt_v2
memory = Memory(namespace="my-agent")
# Store a memory node manually
memory.store("User prefers Python over Java", topic="preferences")
# Recall via the full M4 pipeline (atom + tree + raw, reranked)
result = recall_for_prompt_v2(memory, "programming language preference")
print(result.rendered) # markdown block ready for prompt injection
# Or recall manually stored tree nodes
for node in memory.recall("programming language"):
print(f"[{node.topic}] {node.content}")
Auto-extraction from conversations
from harness_memory import Memory
from harness_memory.extractor import CandidateExtractor
from harness_memory.llm import LLMClient # plug in your host LLM
memory = Memory(namespace="my-agent")
extractor = CandidateExtractor(llm=my_llm_client)
# At session end: extract candidates from L0 raw events
from harness_memory.extractor import extract_session
result = extract_session(memory=memory, extractor=extractor, session_id="sess-123")
# Promote pending candidates to structured atoms
promotion = memory.promote_candidates()
print(f"promoted={promotion.promoted}, merged={promotion.merged}, conflicts={promotion.conflicts}")
CLI
# Ingest conversation files
harness-memory --namespace my-agent ingest --source ~/.claude/projects/myapp/
# Recall
harness-memory --namespace my-agent recall "user authentication preferences"
# Inspect the pipeline
harness-memory --namespace my-agent candidate list --status pending
harness-memory --namespace my-agent atom list --entity-id <id>
harness-memory --namespace my-agent entity list
harness-memory --namespace my-agent memory tree
# Operations
harness-memory --namespace my-agent export --out backup.jsonl
harness-memory --namespace my-agent gc run
Architecture
Storage Layers
| Layer | Type | Table(s) | Description |
|---|---|---|---|
| L0 | RawEvent |
raw_events |
Immutable event log; source of truth |
| L1 | Candidate |
candidates |
LLM-extracted facts awaiting promotion |
| L2 | AtomCard |
atoms |
Promoted structured facts; primary recall source |
| L3 | Entity, EntityPage, Alias |
entities, entity_pages, aliases |
Entity anchors + auto-generated summaries |
| L4 | JournalEntry |
journal |
Append-only audit log |
| — | MemoryNode |
memory_nodes |
Manual / auto-mirrored hierarchical tree |
Promotion Pipeline (L1 → L2)
The promotion worker runs 5 checks in order. First terminal result wins:
- Value — drop if
importance=low AND confidence=low(chit-chat noise) - Evidence — verify cited raw event IDs exist in L0
- Entity — resolve or create the entity this fact belongs to (alias → name → LLM → new)
- Duplicate — merge if an identical assertion already exists on the entity
- Conflict — flag if polarity flips vs an existing atom (negation detection)
Recall Pipeline (M4)
recall_for_prompt_v2 runs 8 stages per query:
parse query → route (entity/time/coref hints) → gather (atom+tree+raw)
→ rerank (BM25 + importance + confidence + recency + layer_prior)
→ diversify (≤N per entity) → suppress (Jaccard dedup)
→ token budget enforcement → cache → render markdown
Memory Tree ↔ Pipeline Bridge
The MemoryNode tree and the L0–L4 pipeline are bridged in both directions:
- Write: every promoted AtomCard is auto-mirrored as a leaf node under an entity branch in the tree (tagged
metadata["mirror"]="auto"). Best-effort — tree failure never rolls back the atom. - Read:
recall_for_prompt_v2queries atom + tree + raw and merges results through the rerank/suppress pipeline. Tree layer prior = 0.70 (between atom 1.0 and raw 0.50).
CLI Reference
harness-memory [GLOBAL OPTIONS] COMMAND [ARGS]
Global options: --config PATH, --backend sqlite|postgres, --db PATH, --dsn DSN, --namespace NS, --json
| Command group | Description |
|---|---|
config show/set |
Show or set configuration values |
ingest |
Archive conversation files (Claude Code, OpenAI, generic JSONL) |
conversations list/export |
Manage stored conversations |
summary pending/set |
Manage conversation summaries |
raw add/list/search/show |
L0 raw event management |
candidate list/show/review |
L1 candidate inspection and manual review |
atom list/show/search |
L2 atom inspection |
entity list/show |
L3 entity management |
page show/regen/edit |
L3 entity page management |
journal list |
L4 audit log |
memory store/get/update/delete/tree/recall |
MemoryNode tree management |
recall |
Run the full M4 recall pipeline |
thread list/show/delete |
LangGraph checkpoint thread management |
export / import / migrate / backfill |
Migration and data operations |
gc run |
Garbage collection |
openclaw setup/doctor |
OpenClaw host integration |
hermes install/doctor |
Hermes host integration |
Host Integrations
Harness Memory can run as a native memory provider inside agent hosting platforms.
OpenClaw
pip install "harness-memory[cli]"
openclaw plugins install npm:@agentmemory/openclaw-plugin
harness-memory openclaw setup # register the plugin and bridge Python
harness-memory openclaw doctor # verify the integration
The OpenClaw plugin (plugins/openclaw/agentmemory/) is a TypeScript shell that spawns the Python bridge (agentmemory-bridge) and registers registerMemoryCapability with the host runtime.
Hermes
pip install harness-memory-hermes
harness-memory-hermes install # install the Hermes adapter
harness-memory-hermes doctor # verify the integration
See docs/release-packaging.md for release artifact boundaries and docs/agentmemory-openclaw-hermes-usage.md for source-checkout setup guides.
Python API Reference
Memory
from harness_memory import Memory
memory = Memory(namespace="my-agent", backend="sqlite",
backend_config={"db_path": "~/my-memory.db"})
| Method | Layer | Description |
|---|---|---|
store(content, topic, level, parent_id, metadata) |
Tree | Create a MemoryNode |
recall(query, limit) |
Tree | FTS search over tree nodes |
add_raw(content, event_type, ...) |
L0 | Append a raw event |
add_candidate(candidate) |
L1 | Persist a candidate |
promote_candidates(candidates, limit, llm_hook) |
L1→L2 | Run promotion worker |
add_atom(atom) |
L2 | Persist an atom directly |
search_atoms(query, limit) |
L2 | FTS search over atoms |
add_entity(entity) |
L3 | Persist an entity |
upsert_entity_page(page) |
L3 | Upsert an entity page |
append_journal(entry) |
L4 | Append an audit entry |
list_journal(...) |
L4 | Query the audit log |
add_conversation(record) |
Conv | Persist a conversation |
search(query, limit) |
Conv | FTS over conversation messages |
Recall
from harness_memory.recall import recall_for_prompt_v2
result = recall_for_prompt_v2(
memory,
query="authentication flow",
thread_id="thread-abc", # enables co-reference resolution
limit=5,
total_budget_tokens=1500,
)
print(result.rendered) # inject directly into prompt
for snippet in result.snippets:
print(snippet.layer, snippet.text) # "atom" | "tree" | "raw"
Supported Conversation Formats
| Format | Extension | Detection |
|---|---|---|
| Claude Code | .jsonl |
type field: human_message / assistant_message |
| Generic JSONL | .jsonl |
role + content fields per line |
| OpenAI JSON | .json |
messages array with role/content objects |
Development
make dev # Install dev dependencies
make lint # Ruff check + format check
make typecheck # mypy strict
make test # pytest
make all # lint + typecheck + test
Related Projects
| Project | Description |
|---|---|
| harness-agent | Production-grade AI agent platform built on LangChain Deep Agents |
| harness-browser | AI-friendly browser automation via CDP |
| harness-im-bridge | Multi-platform IM channel bridge for AI agents |
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file harness_memory-0.1.2.tar.gz.
File metadata
- Download URL: harness_memory-0.1.2.tar.gz
- Upload date:
- Size: 34.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1f2d20f0406bd521fc69257027aa69ccf0839782d7dca9a045e9bfb3bbb5d2e
|
|
| MD5 |
d4f04b064d4dad8174dac96f7c2ee93a
|
|
| BLAKE2b-256 |
7e9ca765ad08a245878c3215695f42ff6acf17b6dee909528e1000415c2cd439
|
File details
Details for the file harness_memory-0.1.2-py3-none-any.whl.
File metadata
- Download URL: harness_memory-0.1.2-py3-none-any.whl
- Upload date:
- Size: 229.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11e4f110b5d006a596f306d3db463f8e49ecc42572babed6f854aa7f3208ab04
|
|
| MD5 |
d0aead4318530109ec1adf0977d677be
|
|
| BLAKE2b-256 |
6fc6da0b755ec8d5b91ef1a9657ebdd9fa40cd59444655a01f13b319da2d377b
|