judge-classify · store verbatim · hybrid semantic recall · live world-state · LLM-agnostic · local-first · introspectable
Install · Proof · How it works · API · License
HyperMEM is the memory layer between "chat" and "a character that remembers you." It watches a conversation, decides what is worth remembering, stores it verbatim, and later injects the relevant memories back into the context window, so an AI companion can recall a fact told 10,000 messages ago as reliably as one from yesterday, without a growing context and without remembering the wrong things.
It is LLM-agnostic (Ollama, OpenAI, Anthropic, or any OpenAI-compatible
endpoint) and ships with a Python engine, a REST server, live world-state
tracking (worldIDA), and JSON persistence.
It is also register-agnostic: the judge classifies, the store is verbatim, and worldIDA tracks physical state. None of it filters or reshapes content, so it serves every roleplay type identically: SFW, suggestive, explicit. A companion app never has to run two memory stacks.
- Judge-classify - the fact-checker decides what matters (JSON, robustly extracted) but never writes the memory text. Your words are the memory.
- Verbatim store - the user's message is stored intact (capped at
max_memory_chars), so the exact tokens survive for recall. No paraphrase drift. - Hybrid semantic recall - embedding + lexical + importance + recency, budgeted for the context window. No LLM re-ranking of the whole list.
- Type-aware lifecycle - a newer fact about the same subject supersedes the old one; episodic events consolidate into durable knowledge; decay archives what stops mattering.
- Live world-state (
worldIDA) - one compact physical state object per session (scene, positions, physical state, feasibility), fully rewritten every turn, injected in full. Narrative time (time of day, elapsed story days) gets its own block. - Provenance - for any memory and any query, the live score breakdown. No magic, no black box.
- REST + Python - same engine over HTTP (
hypermem-server) or inline. - Local-first - runs against a local Ollama; your data stays on your machine.
Your companion app
(chat bot, game, CLI, REST client, your own code...)
| messages (the conversation)
v
+------------------------------------------------------------------+
| HyperMEM (runs locally, your data stays here) |
| -------------------------------------------------------------- |
| Judge (classify) -> Verbatim store -> Lifecycle |
| (what matters) (your words) (supersede/consolidate)|
| |
| Recall (hybrid score) -> Inject into context <- worldIDA |
| (embedding+lexical+ |
| importance+recency) |
+------------------------------------------------------------------+
| relevant memories + world state
v
LLM provider (Ollama - OpenAI - Anthropic - any OpenAI-compatible)
- Judge decides what is worth remembering (importance, type, subject, keywords) without rewriting it.
- Verbatim store keeps the exact words, so recall can match them later.
- Lifecycle supersedes changed facts, consolidates episodic events, and decays what stops mattering.
- Recall ranks by a hybrid score and injects only what fits the context budget.
- worldIDA tracks the live physical scene state, injected in full every turn; narrative time (morning/evening, elapsed days) rides alongside in its own block.
# 1 - Install
pip install hypermem # core (any LLM via Ollama/OpenAI/Anthropic)
pip install "hypermem[server]" # + REST server (fastapi, uvicorn)
# or, from source:
# git clone https://github.com/4biddencode/hypermem.git && cd hypermem && pip install -e .
# 2 - Point it at your LLM (default: Ollama, qwen2.5:7b on localhost:11434)
ollama serve # if you haven't already
# 3 - Run the demo (real model, real numbers, no mocks)
python examples/demo.py
Live: 8 facts planted, 40 filler messages, 8/8 recall, a changed fact superseded, provenance, worldIDA. Real Ollama, no mocks.
Or use it inline:
import asyncio
from hypermem import HyperMEM
hm = HyperMEM() # defaults: Ollama, qwen2.5:7b on localhost:11434
async def main():
# HyperMEM auto-tags important details as they arrive, stored verbatim
await hm.add_message("user", "My name is Emanuel, I live in Vienna")
await hm.add_message("user", "I'm planning a hike in the Alps next week")
# Later, the relevant memories come back, even with different wording
ctx = await hm.get_context("Where do I live?")
print(ctx)
# Why did that surface? Live score breakdown, no magic.
await hm.explain_recall("Where do I live?", hm.memories()[0]["id"])
asyncio.run(main())Output:
[RELEVANT MEMORIES]
- My name is Emanuel, I live in Vienna (importance: 100%)
[/RELEVANT MEMORIES]
Put ctx into your system prompt and your AI now answers with facts it was
never given in the visible chat history.
Numbers are from the real benchmark (benchmarks/full_suite.py) against a real
model (Ollama, qwen2.5:7b). No mocks, no cherry-picking. Low is better for
latency, high is better for recall and contradiction handling.
| Metric | Result | What it means |
|---|---|---|
| Recall @ 100 msgs | ~0.9+ | of 8 planted facts, ~7-8 come back after 40 filler messages |
| Paraphrase | ~0.9+ | "Where do I live?" still finds "my name is Emanuel, I live in Vienna" |
| Contradiction: new wins | 1.0 | a changed fact supersedes the old one, deterministically |
| Contradiction: stale leak | 0.0 | the superseded memory never resurfaces in recall |
| Judge latency | ~1.4 s | classify one message (LLM call, local model) |
| Recall latency | ~0.2-0.5 s | hybrid score, budgeted for the context window |
| worldIDA update | ~3 s | one compact state object, fully rewritten per turn |
The point of the tables: HyperMEM does not hope to remember the right things - it is measured, and the numbers hold up across a real conversation.
- AI companions / roleplay - give the character a persistent memory of the user and the story, without a growing context window.
- Chat agents & assistants - remember user preferences, facts, and project context across sessions.
- Games with a narrative - the NPC remembers what happened, and what you told it.
- Anything that talks to an LLM over multiple turns and wishes it could remember.
HyperMEM is a library and a small REST server, not a plugin you install into a host app. You wire it in yourself, in a few lines:
- Python -
from hypermem import HyperMEM, thenadd_message/get_context. - REST - run
hypermem-server, then:POST /sessions- create a conversationPOST /sessions/{id}/messages- feed a messageGET /sessions/{id}/context?message=...- get relevant memoriesGET /sessions/{id}/memories/{id}?query=...- provenance (why it surfaced)
Any language that can do HTTP can use HyperMEM. The server is stateless except for JSON files on disk, so you can run one instance for many conversations.
hypermem/- the engineengine.py- the pipeline (judge -> store -> lifecycle -> recall -> context)llm.py- robust JSON extraction, provider transportworld_ida.py- live world-state trackingserver.py- REST servertypes.py- config, memory, persona
examples/demo.py- a real demo (facts planted, filler turns, recall)benchmarks/- the honest numbers, reproducibletests/- hermetic, no network
Run it, point any HTTP client at it, done:
pip install -e ".[server]"
hypermem-server --port 8080 --llm-provider ollama --llm-model qwen2.5:7b# create a session
curl -X POST localhost:8080/sessions -d '{}'
# feed a message (judge decides if it matters, stores it verbatim)
curl -X POST localhost:8080/sessions/session_123/messages \
-H 'content-type: application/json' \
-d '{"role":"user","content":"My name is Emanuel, I live in Vienna"}'
# later, ask for relevant memories
curl "localhost:8080/sessions/session_123/context?message=Where%20do%20I%20live?"Sessions are persisted as JSON on disk (.hypermem_data/ by default), so the
server survives restarts. No database, no external service.
One compact state object per session tracking only the physical world - where the scene is, how each character is sitting, exactly where they are, whether a described action is physically possible. Fully rewritten every turn and injected in full. It is the "here and now" that episodic memories are too slow to capture:
{
"scene": {"location": "tavern", "sub_location": "corner booth",
"ongoing_action": "drinking ale"},
"user": {"physical_state": "seated at the table", "position": "left of the booth"},
"character": {"physical_state": "leaning forward", "position": "across from you"},
"meta": {"physically_possible": true}
}Emotional/social state (mood, relationship) is deliberately not tracked -
worldIDA is physical-only. Narrative time (time of day + how many in-story
days have passed, via a monotonic counter) is a separate [NARRATIVE TIME]
context block, so the AI still knows it's morning of day 3 without polluting
the physical state.
Each HyperMEM instance holds its own memories, its own world-state, and its
own persona. Two sessions never share memory unless you wire them to. The
persona (name, description, traits, backstory, boundaries) is stored with the
session and injected with context, so the same engine can power two very
different characters without cross-contamination.
Everything is configurable via HyperMemConfig (Python) or CLI flags (server).
The important ones:
| Option | Default | What it does |
|---|---|---|
llm_provider |
auto |
ollama | openai | anthropic |
llm_model |
qwen2.5:7b |
which model judges / recalls |
llm_endpoint |
http://localhost:11434 |
provider base URL |
auto_tag_threshold |
0.4 |
minimum importance to store a memory |
max_active_memories |
100 |
cap on active (non-archived) memories |
max_memory_chars |
1000 |
verbatim content cap per memory |
embedding_provider |
auto |
ollama | openai | none |
The public surface is small on purpose. Everything else is internal.
hm = HyperMEM(config) # engine, one per session
await hm.add_message(role, content) # judge -> store -> lifecycle -> recall
await hm.remember(content, memory_type) # store a memory directly
await hm.recall(query) # rank memories for a query
await hm.get_context(message) # recall, formatted for the context window
await hm.explain_recall(query, memory_id) # live score breakdown (provenance)
hm.memories() # list active memories
hm.set_persona(Persona(...)) # persona for this session
await hm.update_world_ida(user, ai) # refresh world-state
hm.save(path) / hm.load(path) # JSON persistence| Method | Endpoint | Purpose |
|---|---|---|
POST |
/sessions |
create a session |
GET |
/sessions |
list sessions |
DELETE |
/sessions/{id} |
delete a session |
POST |
/sessions/{id}/messages |
feed a message |
POST |
/sessions/{id}/remember |
store a memory directly |
GET |
/sessions/{id}/recall?query= |
rank memories |
GET |
/sessions/{id}/context?message= |
get context for a message |
GET |
/sessions/{id}/memories |
list memories |
GET |
/sessions/{id}/memories/{id}?query= |
provenance |
PUT |
/sessions/{id}/persona |
set persona |
GET |
/sessions/{id}/world-ida |
get world-state |
POST |
/sessions/{id}/world-ida/update |
update world-state |
GET |
/health |
liveness |
hypermem/
engine.py # the pipeline
llm.py # provider + robust JSON
world_ida.py # live world-state
server.py # REST server
types.py # config, memory, persona
examples/
demo.py # real, reproducible demo
benchmarks/
full_suite.py # the numbers in "Proof"
tests/ # hermetic, no network
HyperMEM is source-available. You are welcome to read it, run it, and contribute fixes and improvements. Please open an issue or PR - see CONTRIBUTING for the details, and the license below for what you can and cannot do with the code.
Source-Available License - you can read, run, and modify the code for your own use, and contribute back. Redistributing a competing hosted service built on it requires attribution. See the full license for the exact terms.

