Local-first AI memory system — realms, domains, entities, hybrid search, entity graph, MCP
Project description
Alt Memory
Local-first persistent memory for AI agents. Store, search, and manage structured memory with hybrid vector/keyword search, a knowledge graph, agent diaries, personas, file mining, and an MCP server — all offline, no external services.
pip install alt-memory
Benchmarked at ~8ms/tool (FAISS backend, numpy embedder) — roughly 7x faster than the predecessor system.
Table of Contents
- Installation
- Quick Start — CLI
- Core Concepts
- Full CLI Reference
- Python API
- MCP Server
- Search Architecture
- Embedder System
- Backend Switching
- Knowledge Graph
- Agent Records / Diaries
- File Mining
- Personas
- AAAK Compression
- Palace Graph (Tunnels)
- Sync & Maintenance
- Configuration
- Docker
- Architecture
- License
Installation
pip install alt-memory
This gives you FAISS + tokenizers (for numpy BERT embedder). On first use, it auto-selects the best embedder available.
| Install | Backend | Embedder |
|---|---|---|
pip install alt-memory |
FAISS | numpy BERT (all-MiniLM-L6-v2 via pure numpy) |
pip install alt-memory[chroma] |
+ ChromaDB | same |
pip install alt-memory[onnx] |
same | + ONNX MiniLM / Gemma / BERT |
pip install alt-memory[all] |
+ ChromaDB | + ONNX + sentence-transformers |
Extras explained
| Extra | Packages |
|---|---|
[chroma] |
chromadb>=1.5.4 |
[onnx] |
onnxruntime, huggingface_hub, transformers |
[all] |
chroma + onnx + sentence-transformers |
Requirements: Python ≥ 3.10, Windows/Linux/macOS.
Quick Start — CLI
# Initialize a new dimension
alt-memory init
# Check status
alt-memory status
# Store a memory (realm=work, domain=bugs)
alt-memory add --realm work --domain bugs --content "Login freezes on Safari 18.2"
# Search — hybrid by default (vector + keyword)
alt-memory search "login safari" --limit 5
# Browse
alt-memory list --realm work
alt-memory realms
alt-memory rooms
# Knowledge graph
alt-memory kg-add --subject LoginBug --predicate affects --object Safari
alt-memory kg-query LoginBug
alt-memory kg-stats
# Agent diary
alt-memory record --agent claude --entry "Investigated the Safari freeze"
# Mine a file (auto-chunk, extract entities)
alt-memory mine --realm work --domain code src/auth.py
# MCP server
alt-memory mcp --transport stdio
Init with project detection
# Run init in a project directory — auto-detects corpus origin, entities, domains
alt-memory init /path/to/project --llm-provider ollama --llm-model qwen2.5
Core Concepts
| Concept | What it is | Default MCP prefix | SQL analogy |
|---|---|---|---|
| Dimension | A directory on disk containing SQLite + FAISS/Chroma + config | (implicit) | database server |
| Realm | Top-level bucket (e.g. work, personal, agent_claude) |
*_realm |
database |
| Domain | Category within a realm (e.g. bugs, ideas, code) |
*_domain |
table |
| Entity | Individual memory item with content + metadata | *_entity |
row |
| KG fact | Relationship triple (subject → predicate → object) with temporal validity |
kg_* |
edge |
| Node | Cross-reference entry connecting source files to entity references | *_node |
index |
| Tunnel | Cross-realm link between domains (the "palace graph") | *_tunnel |
foreign key |
| Record | Per-agent temporal diary entry | record_* / memory_* |
log |
| Persona | Character definition (system prompt + name) with isolated realm | *_persona |
schema |
Hybrid search combines FAISS/Chroma vector similarity with SQLite FTS5 keyword matching, re-ranked by weighted BM25.
On-disk layout
~/.alt-memory/
├── dimension.db # SQLite + FTS5 (all entities, metadata, KG)
├── index.faiss # FAISS vector index (or chroma.sqlite3 for ChromaDB)
├── dimension.json # Config (backend, embedder, model settings)
├── persona.json # Persona registry
├── nodes/ # Packed cross-reference node storage
├── entity_registry.json # Entity name → ID mappings
├── knowledge_graph.json # Relationship store (backup/sync)
└── aaak_cache.json # AAAK compression cache
All data is portable — copy ~/.alt-memory to another machine and it works.
Full CLI Reference
30+ commands. The dimension path defaults to ~/.alt-memory; override with --dimension.
Init & Status
| Command | Description |
|---|---|
alt-memory init [dir] |
Initialize dimension; optionally scan a project directory for entities/domains |
alt-memory status |
Show dimension status (JSON: entity count, realms, domains, embedder) |
alt-memory repair-status |
Quick health check (entity count, SQLite integrity) |
CRUD
| Command | Description |
|---|---|
alt-memory add -w <realm> -r <domain> -c <content> |
Add an entity |
alt-memory get <entity_id> |
Get an entity by ID |
alt-memory list [-w <realm>] [-r <domain>] [-l <limit>] [-o <offset>] |
List entities with pagination |
alt-memory delete <entity_id> |
Delete an entity |
alt-memory realms [--verbose] |
List all realms |
alt-memory rooms [--realm] |
List all domains (optionally filtered) |
Search
| Command | Description |
|---|---|
alt-memory search <query> [-w <realm>] [-r <domain>] [--mode <mode>] |
Search. Modes: hybrid (default), vector, keyword |
alt-memory check-dup <content> [--threshold 0.9] |
Check for duplicate content |
Knowledge Graph
| Command | Description |
|---|---|
alt-memory kg-add -s <subject> -p <predicate> -o <object> |
Add a KG fact |
alt-memory kg-query [entity] [--predicate] [--as-of] [--direction] |
Query KG facts |
alt-memory kg-invalidate -s <subject> -p <predicate> -o <object> |
Mark a fact as ended |
alt-memory kg-stats |
KG statistics |
Records (Agent Diaries)
| Command | Description |
|---|---|
alt-memory record -a <agent> -e <entry> [-t <topic>] |
Write a diary entry |
alt-memory record-read -a <agent> [--last-n 10] |
Read diary entries |
alt-memory record-ingest --dir <path> |
Ingest daily summary files into the dimension |
Mining
| Command | Description |
|---|---|
alt-memory mine <file> |
Mine a single file into the dimension |
alt-memory mine <dir> [--mode projects|convos|extract] |
Mine a directory of files |
alt-memory sweep <path> |
Sweep .jsonl files (message-granular mining) |
alt-memory split [--source] [--output-dir] |
Split mega-files into per-session files |
MCP Server
| Command | Description |
|---|---|
alt-memory mcp --transport stdio |
Run MCP server over stdio (for AI coding agents) |
alt-memory mcp --transport sse --port 8316 |
Run MCP server over HTTP SSE |
Maintenance
| Command | Description |
|---|---|
alt-memory sync [--apply] [--project-dir DIR] |
Prune stale entities (gitignored/deleted sources) |
alt-memory rebuild-fts |
Rebuild FTS5 full-text search index |
alt-memory migrate [--rebuild-faiss] [--status] |
Schema migration and FAISS rebuild |
alt-memory repair [--integrity] [--vacuum] [--rebuild-fts] |
Repair utilities |
alt-memory rebuild-from-sqlite |
Rebuild FAISS index from SQLite ground truth |
alt-memory aaak <text> |
Compress text to AAAK format |
Other
| Command | Description |
|---|---|
alt-memory wake-up [--agent <name>] |
Show L0+L1 wake-up context |
alt-memory hook run --hook <h> --harness <h> |
Run a hook (claude-code / codex) |
alt-memory instructions <topic> |
Output skill instructions for AI agents |
Python API
from alt_memory import Dimension
d = Dimension(path="~/.alt-memory") # or Dimension(path="./my-dim", backend="faiss")
d.init()
Core CRUD
# Add an entity
eid = d.add_entity("work", "bugs", "Login freezes on Safari",
metadata={"priority": "high"}, source_file="src/auth.py")
# Get by ID
entity = d.get_entity(eid)
# List with filters
entities = d.list_entities(realm="work", domain="bugs", limit=20, offset=0)
# Update
d.update_entity(eid, content="Updated description", metadata={"status": "fixed"})
# Delete
d.delete_entity(eid)
d.delete_entities([eid1, eid2])
# Batch add
ids = d.batch_add_entities([
("work", "bugs", "Bug one", {}, "", None),
("work", "bugs", "Bug two", {}, "", None),
])
Search
# Hybrid (default) — vector + keyword, re-ranked
results = d.search("login safari", n_results=10, mode="hybrid")
# Vector-only — semantic similarity
results = d.search("authentication timeout", mode="vector")
# Keyword-only — exact match via FTS5
results = d.search("Safari 18.2", mode="keyword")
# Filter by realm/domain
results = d.search("login", realm="work", domain="bugs")
# Programmatic search (used by MCP)
results = d.search_memories("login", n_results=5, realm="work",
max_distance=0.5, candidate_strategy="union")
Each SearchResult has: id, text, distance, metadata, realm, domain.
Realm & Domain Management
# Realms
d.list_realms() # → [{"name": "work", "entity_count": 42, ...}]
d.get_or_create_realm("work", "Work stuff")
d.delete_realm("work") # deletes all domains and entities within
# Domains
d.list_domains(realm="work") # → [{"name": "bugs", "entity_count": 10, ...}]
d.get_or_create_domain("work", "bugs", "Bug tracking")
d.delete_domain("work", "bugs")
Knowledge Graph
# Add facts
d.kg.add("LoginBug", "affects", "Safari", valid_from="2026-05-01")
d.kg.add("LoginBug", "priority", "high")
# Query
facts = d.kg.query("LoginBug") # all facts about LoginBug
facts = d.kg.query("LoginBug", as_of="2026-05-15") # temporal query
facts = d.kg.query("LoginBug", direction="outgoing") # outgoing edges only
# Invalidate
d.kg.invalidate("LoginBug", "affects", "Safari", ended="2026-06-01")
# Stats & timeline
d.kg.stats()
d.kg.timeline(entity="LoginBug") # chronological story of an entity
Agent Records (Diaries)
# Write entries at different layers
d.diary_write("claude", "DEBUG: found race condition in auth retry", topic="debug")
d.diary_write("claude", "SESSION:2026-05-31|fixed.auth|★★★", topic="summary")
# Read
entries = d.diary_read("claude", last_n=5)
# List all agents with records
d.list_agents() # Note: standalone function, see API note below
Note on standalone functions: Some operations are standalone functions in their respective modules, not
Dimensionmethods. These includesync(sync_dimensioninsync.py), traversal functions (traverse,build_graph,create_tunnelindim_graph.py), and mining functions (mine_file_into_dimension,mine_text_into_dimension,batch_mineinminer.py). They accept a dimension path string or Dimension object. See the MCP tools table for the full list — all operations are available via the MCP server regardless.
Backend & Embedder Control
# Switch vector store backend
d.set_backend("chroma") # FAISS → ChromaDB
d.set_backend("faiss") # ChromaDB → FAISS
# Switch embedding model (auto-reindexes all entities)
d.set_embedder("sentence") # sentence-transformers (best quality)
d.set_embedder("numpy") # TF-IDF+SVD (lightest)
d.set_embedder("minilm") # ONNX MiniLM
d.set_embedder("spacy") # spaCy GloVe
d.set_embedder("embeddinggemma") # Google Gemma via ONNX
# Device control for ONNX embedders
d.set_embedder("minilm", device="cpu")
d.set_embedder("minilm", device="cuda")
d.set_embedder("minilm", device="dml") # DirectML on Windows
Status & Maintenance
# Status
status = d.status() # → {entities, realms, domains, embedder, ...}
taxonomy = d.get_taxonomy() # → {realm: {domain: count, ...}, ...}
# FTS rebuild
d.rebuild_fts()
# Duplicate check
dup = d.check_duplicate("new content to check", threshold=0.9)
# Reconnect after external changes
d.reconnect()
# Memories filed away check
d.memories_filed_away()
Export / Import
# Export all entities as JSON-serializable list
export = d.export_collection()
export = d.export_collection(realm="work", domain="bugs") # filtered
# Import entities from list
count = d.import_entities(export, overwrite=False)
Personas
See the full dedicated docs at docs/personas.md.
# Quick reference
d.create_persona("coder", system_prompt="You are an expert Python developer.")
d.set_persona("coder")
d.get_persona() # → active persona dict
d.get_persona_character() # → "You are an expert Python developer."
d.get_persona_character("coder") # → same, by name
d.list_personas() # → all registered personas
d.delete_persona("coder") # → True/False
d.switch_persona("architect") # alias for set_persona
MCP Server
The MCP server exposes 65 tools over stdio (for coding agents) or SSE (for remote access).
# Stdio mode — for AI coding agents (Claude Code, Codex, Cline)
alt-memory mcp --transport stdio
# SSE mode — for remote/local HTTP access
alt-memory mcp --transport sse --port 8316
AI Agent Configuration
Configure in your MCP client:
{
"mcpServers": {
"alt-memory": {
"command": "alt-memory",
"args": ["mcp", "--transport", "stdio"]
}
}
}
All 65 MCP Tools
| Category | Tool | Required Params | Optional Params | Description |
|---|---|---|---|---|
| Search | search |
query |
n_results, realm, domain, mode |
Hybrid/vector/keyword search |
check_duplicate |
content |
threshold |
Check if content exists | |
| CRUD | add_entity |
realm, domain, content |
metadata, source_file, entity_id |
Store a memory |
get_entity |
entity_id |
— | Fetch by ID | |
update_entity |
entity_id |
content, metadata, realm, domain |
Update fields | |
delete_entity |
entity_id |
— | Delete one | |
delete_entities |
entity_ids (array) |
— | Bulk delete | |
list_entities |
— | realm, domain, limit, offset |
List with pagination | |
batch_add_entities |
entities (array) |
— | Bulk add | |
import_entities |
entities (array) |
overwrite |
Import from JSON | |
export_collection |
— | realm, domain |
Export as JSON | |
| Realms | create_realm |
name |
description |
Create top-level bucket |
delete_realm |
name |
— | Delete realm + contents | |
list_realms |
— | — | List all | |
get_taxonomy |
— | — | Realm → domain → count | |
get_status |
— | — | Entity count, embedder info | |
| Domains | create_domain |
realm, name |
description |
Create domain |
delete_domain |
realm, name |
— | Delete domain | |
list_domains |
— | realm |
List domains | |
| KG | kg_add |
subject, predicate, object |
valid_from, valid_to, source |
Add fact |
kg_query |
— | entity, predicate, as_of, all, direction |
Query facts | |
kg_invalidate |
subject, predicate, object |
ended |
End a fact | |
kg_stats |
— | — | KG statistics | |
kg_timeline |
— | entity |
Chronological story | |
| Records | record_write |
agent, entry |
topic, realm |
Diary entry |
record_read |
agent |
last_n, realm |
Read diary | |
list_agents |
— | — | All agents with records | |
| Mine | mine_file |
filepath, realm, domain |
— | Mine a single file |
mine_text |
text, realm, domain |
source, chunk |
Mine text content | |
batch_mine |
directory |
realm, pattern |
Mine a directory | |
sync |
— | project_dir, realm, apply |
Prune stale entities | |
| Graph | create_tunnel |
source_realm, source_domain, target_realm, target_domain |
label, source_entity_id, target_entity_id |
Link domains |
delete_tunnel |
tunnel_id |
— | Remove a tunnel | |
list_tunnels |
— | realm |
List all tunnels | |
find_tunnels |
— | realm_a, realm_b |
Find bridges between realms | |
follow_tunnels |
realm, domain |
— | Follow connections | |
traverse |
start_domain |
max_hops |
Walk the graph | |
graph_stats |
— | — | Overview of connections | |
| Backend | set_backend |
backend (faiss|chroma) |
reindex |
Switch vector store |
get_backend |
— | — | Current backend name | |
| Embedder | set_embedder |
model |
device, reindex |
Switch embedder |
set_default_embedder |
model |
— | Set global default | |
get_default_embedder |
— | — | Get global default | |
| Persona | get_persona |
— | — | Active persona |
set_persona |
name |
system_prompt, description, metadata |
Set/switch persona | |
switch_persona |
name |
system_prompt, description, metadata |
Alias for set | |
create_persona |
name |
system_prompt, description, metadata |
Create without activating | |
list_personas |
— | — | All registered | |
delete_persona |
name |
— | Remove from registry | |
get_persona_character |
— | name |
Get system prompt string | |
| AAAK | aaak_compress |
text |
max_len |
Compress to AAAK |
aaak_decompress |
text |
— | Decompress AAAK | |
aaak_parse |
text |
— | Parse AAAK entry | |
get_aaak_spec |
— | — | Full AAAK specification | |
| Other | hook_settings |
— | silent_save, desktop_toast |
Configure hooks |
memories_filed_away |
— | — | Checkpoint status | |
rebuild_fts |
— | — | Rebuild FTS5 index | |
reconnect |
— | — | Reconnect to database | |
get_people_map |
— | — | Name variant mappings | |
set_people_map |
map |
— | Set name variant mappings | |
init_dimension |
— | — | Initialize dimension | |
close_dimension |
— | — | Close dimension gracefully | |
ping |
— | — | Health check |
All 65 tools are available as JSON-RPC calls. Example:
{"name": "add_entity", "arguments": {"realm": "work", "domain": "bugs", "content": "Login freezes on Safari 18.2"}}
{"name": "search", "arguments": {"query": "login safari", "n_results": 5}}
{"name": "set_embedder", "arguments": {"model": "minilm"}}
{"name": "set_backend", "arguments": {"backend": "chroma"}}
Search Architecture
Three Search Modes
| Mode | Method | How it works | Best for |
|---|---|---|---|
| Vector | mode="vector" |
Embed query → FAISS/Chroma cosine distance ranking | Semantic similarity ("find related concepts") |
| Keyword | mode="keyword" |
FTS5 token match → BM25 ranking | Exact term lookup ("find where I wrote 'login bug'") |
| Hybrid | mode="hybrid" (default) |
Vector + keyword merged, re-ranked by 0.6 vector + 0.4 BM25 |
General-purpose |
Search Pipeline
search(query, realm, domain, mode)
│
├── mode="keyword" ──▶ _build_fts_query(query)
│ │ "login safari" → "login* AND safari*"
│ │ "login AND safari" → passed through
│ │ "\"login safari\"" → phrase query
│ ▼
│ FTS5 MATCH on entities_fts
│ JOIN entities for realm/domain filter
│ ORDER BY rank (BM25)
│ Fallback to vector search if FTS5 fails
│
├── mode="vector" ────▶ embedder.embed(query) → np.ndarray
│ FAISS IndexIDMap.search() or ChromaDB query()
│ Cosine distance → filter by realm/domain → top-k
│
└── mode="hybrid" ────▶ Over-fetch 2× from both vector + keyword
Union dedup by entity ID (vector first)
Final score = 0.6 × vec_sim + 0.4 × BM25_norm
Return top-n_results
Full Pipeline (search_memories)
Used by the MCP search tool for richer results:
- Over-fetch 3× candidates from vector + keyword
- Apply
max_distancethreshold (filter out distant results) - Merge candidates —
"vector"strategy (default) or"union"(append BM25-only results) - Node boost — entities from files with cross-reference nodes get priority
- Hydration — for boosted results, expand with ±1 neighbor chunks for context
- BM25 re-rank with weights
0.6 vector + 0.4 BM25 - Attach
node_previewtext to boosted results - Return top-n_results dict
FTS5 Query Construction
| Input | Output | Rule |
|---|---|---|
"login safari" |
"login* AND safari*" |
Bare terms → prefix wildcard + AND |
"login AND safari" |
passed through | Operators (AND, OR, NOT, NEAR) verbatim |
"\"login safari\"" |
passed through | Phrase queries verbatim |
"multi-part" |
"multi* AND part*" |
Hyphenated terms split on - |
Direct Lookups (non-search)
d.get_entity("entity_id") # SQL PK lookup
d.list_entities(realm="...") # SQL with filters, ORDER BY created_at DESC
Embedder System
Auto-Detection
Alt Memory automatically picks the best embedder at runtime. No configuration needed.
Priority: sentence-transformers → numpy BERT → TF-IDF+SVD
Quality: ★★★★★ → ★★★★ → ★★
Speed: ★★★★ → ★★★ → ★★★★★
Deps: PyTorch (~800MB) → tokenizers → none
Embedder Reference
| Name | Quality | Speed | Dependencies | Platform |
|---|---|---|---|---|
sentence |
★★★★★ | ★★★★ | sentence-transformers + PyTorch | all |
numpy_bert |
★★★★ | ★★★ | tokenizers (included) | all incl. Alpine |
minilm |
★★★★ | ★★★★★ | onnxruntime [onnx] |
glibc |
embeddinggemma |
★★★★★ | ★★★★ | onnxruntime [onnx] |
glibc |
bert |
★★★★ | ★★★★ | onnxruntime or tokenizers [onnx] |
all |
spacy |
★★★ | ★★★ | spacy + en_core_web_md | all |
numpy |
★★ | ★★★★★ | none (always available) | all |
All embedders produce 384-dimensional vectors.
Switching Embedders
# CLI
export ALT_DEFAULT_EMBEDDER=minilm # set global default
export ALT_DEFAULT_EMBEDDER=numpy # TF-IDF+SVD (lightest)
# Python
d.set_embedder("sentence") # auto-reindexes all entities
d.set_embedder("numpy", reindex=False) # skip reindex (existing vectors stale)
# MCP
{"name": "set_embedder", "arguments": {"model": "minilm", "device": "cpu"}}
{"name": "set_default_embedder", "arguments": {"model": "numpy"}}
Device control for ONNX embedders:
"auto"— probe CUDA → CoreML → DirectML → CPU (default)"cpu"— force CPU execution"cuda"— NVIDIA GPU via CUDA"coreml"— Apple Silicon"dml"— Windows DirectML
When you change the embedder, all entities are automatically re-embedded. On large dimensions this can take time.
Backend Switching
Swap between FAISS and ChromaDB at runtime. All data persists in SQLite — only the vector index changes.
# CLI
alt-memory backend chroma # Note: use MCP or Python API for switching
# Python
d = Dimension(path="~/.alt-memory", backend="chroma") # initial backend
d.set_backend("faiss") # hot-swap — moves vectors between backends
d.set_backend("chroma")
# MCP
{"name": "set_backend", "arguments": {"backend": "chroma"}}
{"name": "get_backend", "arguments": {}}
When reindex=True (default), all entities are re-embedded into the new store.
Knowledge Graph
The KG stores structured relationship triples with temporal validity.
Concepts
- Subject — the entity doing/being something (e.g.
LoginBug) - Predicate — the relationship type (e.g.
affects,priority,found_in) - Object — the connected entity (e.g.
Safari,high,v4.3.0) - Temporal validity —
valid_from/valid_todates let you answer "what was true at a given time"
MCP Usage
{"name": "kg_add", "arguments": {"subject": "LoginBug", "predicate": "affects", "object": "Safari"}}
{"name": "kg_add", "arguments": {"subject": "LoginBug", "predicate": "priority", "object": "high", "valid_from": "2026-05-01"}}
{"name": "kg_query", "arguments": {"entity": "LoginBug"}}
{"name": "kg_query", "arguments": {"entity": "LoginBug", "as_of": "2026-05-15"}}
{"name": "kg_invalidate", "arguments": {"subject": "LoginBug", "predicate": "priority", "object": "high", "ended": "2026-06-01"}}
{"name": "kg_stats", "arguments": {}}
{"name": "kg_timeline", "arguments": {"entity": "LoginBug"}}
Agent Records / Diaries
Per-agent temporal entries with three memory layers.
L0 — Immediate Records (per-exchanges)
d.diary_write("claude", "DEBUG: found race condition in auth retry", topic="debug")
d.diary_write("claude", "User prefers async Python with asyncio", topic="preference")
L1 — Daily Summaries (end of session)
d.diary_write("claude", "SESSION:2026-05-31|fixed.auth.race.cond|★★★", topic="summary")
L2 — Patterns (weekly/ongoing)
d.diary_write("claude", "PATTERN: auth.timeouts→rate.limit.insufficient|★★★★★", topic="pattern")
Reading
alt-memory wake-up --agent claude --last-n 5 # L0+L1 context
alt-memory record-read --agent claude --last-n 10
entries = d.diary_read("claude", last_n=5)
MCP
{"name": "record_write", "arguments": {"agent": "claude", "entry": "Fixed login bug", "topic": "debug"}}
{"name": "record_read", "arguments": {"agent": "claude", "last_n": 5}}
{"name": "list_agents", "arguments": {}}
File Mining
Mine source files, conversations, and text into the dimension. Auto-chunks, extracts metadata, and stores entities with source file references.
CLI
# Mine a single file
alt-memory mine src/auth.py --realm myproject --domain code
# Mine a directory (auto-globs, respects .gitignore)
alt-memory mine /path/to/project --realm myproject
# Conversation mode
alt-memory mine /path/to/convos --mode convos
# Extraction mode
alt-memory mine /path/to/formats --mode extract
# Preview without filing
alt-memory mine /path/to/project --dry-run
# Sweep .jsonl files
alt-memory sweep /path/to/file.jsonl
Python
from alt_memory.miner import mine_file_into_dimension, batch_mine, mine_text_into_dimension
# Single file
mine_file_into_dimension(dim, "src/auth.py", "myproject", "code")
# Directory (batch)
batch_mine(dim, "/path/to/project", realm="myproject",
respect_gitignore=True, file_limit=100)
# Text content
mine_text_into_dimension(dim, text, "myproject", "notes", source="clipboard")
MCP
{"name": "mine_file", "arguments": {"filepath": "src/auth.py", "realm": "myproject", "domain": "code"}}
{"name": "batch_mine", "arguments": {"directory": "/path/to/project", "realm": "myproject"}}
{"name": "mine_text", "arguments": {"text": "raw text...", "realm": "myproject", "domain": "notes"}}
Personas
Full documentation: docs/personas.md
A persona is a character definition — a system prompt with a name, matching the Eternal AI .txt file model. Model and framework are deployment choices, not part of the character definition.
Each persona gets an isolated persona_<name> realm for memories, KG facts, and diary entries.
d.create_persona("donald_trump", system_prompt="Act as if you are Donald Trump...")
d.set_persona("donald_trump")
prompt = d.get_persona_character()
# → "Act as if you are Donald Trump..."
# Inject as {"role": "system", "content": prompt} in your LLM call
7 MCP tools: get_persona, set_persona, switch_persona, create_persona, list_personas, delete_persona, get_persona_character.
AAAK Compression
AAAK is a compressed memory dialect — readable by humans and LLMs without decoding. Uses 3-letter entity codes, emotion markers, pipe-separated fields, and importance ratings.
# CLI
alt-memory aaak "Alice loves Jordan, they have two kids: Riley (18, into sports)"
# → FAM: ALC→♡JOR | 2D(kids): RIL(18,sports) | ★★★★
# Decompress / parse
alt-memory aaak "FAM: ALC→♡JOR" --output-format json
from alt_memory import aaak_compress, aaak_decompress, aaak_parse_entry
compressed = aaak_compress("Long text here")
parsed = aaak_parse_entry(compressed)
original = aaak_decompress(compressed)
{"name": "aaak_compress", "arguments": {"text": "Your long text here"}}
{"name": "aaak_decompress", "arguments": {"text": "FAM: ALC→♡JOR..."}}
{"name": "aaak_parse", "arguments": {"text": "FAM: ALC→♡JOR..."}}
{"name": "get_aaak_spec", "arguments": {}}
Palace Graph (Tunnels)
The palace graph connects domains across realms via tunnels — explicit cross-realm relationships.
from alt_memory.dim_graph import create_tunnel, traverse, graph_stats, find_tunnels
# Link two domains
create_tunnel(
source_realm="work", source_domain="bugs",
target_realm="personal", target_domain="learnings",
label="Same root cause",
)
# Walk the graph from a domain
traverse(start_domain="bugs", max_hops=2)
# Find bridges between realms
find_tunnels(realm_a="work", realm_b="personal")
{"name": "create_tunnel", "arguments": {
"source_realm": "work", "source_domain": "bugs",
"target_realm": "personal", "target_domain": "learnings",
"label": "Same root cause"
}}
{"name": "traverse", "arguments": {"start_domain": "bugs", "max_hops": 2}}
{"name": "graph_stats", "arguments": {}}
{"name": "follow_tunnels", "arguments": {"realm": "work", "domain": "bugs"}}
Sync & Maintenance
Sync (prune stale entities)
Removes entities whose source files were deleted or moved:
# Dry-run preview
alt-memory sync --project-dir /path/to/repo
# Actually delete
alt-memory sync --project-dir /path/to/repo --apply
# Limited to one realm
alt-memory sync --project-dir /path/to/repo --realm myproject --apply
Repair
# Quick health check
alt-memory repair-status
# Check SQLite integrity
alt-memory repair --integrity
# Run VACUUM
alt-memory repair --vacuum
# Rebuild FTS5 index
alt-memory repair --rebuild-fts
# Interactive repair mode
alt-memory repair --mode status
alt-memory repair --mode scan
alt-memory repair --mode prune
alt-memory repair --mode rebuild
# Full rebuild from SQLite (covers FAISS corruption)
alt-memory rebuild-from-sqlite
Migration
# Check schema status
alt-memory migrate --status
# Apply pending migrations
alt-memory migrate
# Rebuild FAISS from SQLite
alt-memory migrate --rebuild-faiss
# Dry run
alt-memory migrate --dry-run
Maintenance
# Rebuild just the FTS5 index
alt-memory rebuild-fts
# Check for duplicate content
alt-memory check-dup "content to check"
Configuration
Global configuration is stored in ~/.alt-memory/config.json.
Environment Variables
| Variable | Default | Description |
|---|---|---|
ALT_DIM_PATH |
~/.alt-memory |
Default dimension path |
ALT_DEFAULT_EMBEDDER |
auto |
Force a specific embedder (numpy, numpy_bert, sentence, minilm, spacy) |
ALT_EMBEDDING_DEVICE |
auto |
ONNX device (cpu, cuda, coreml, dml) |
Config File (~/.alt-memory/config.json)
{
"dim_path": "~/.alt-memory",
"default_embedder": "numpy_bert",
"embedding_device": "auto",
"people_map": {"Alex": "Alexander", "Beth": "Elizabeth"},
"hooks_auto_save": true,
"hook_silent_save": true,
"hook_desktop_toast": false
}
Hook Settings (via MCP)
{"name": "hook_settings", "arguments": {"silent_save": true, "desktop_toast": false}}
Docker
# FAISS + numpy BERT (Alpine, ~117MB content)
docker run -v ~/.alt-memory:/root/.alt-memory kilv/alt-memory:alpine mcp
# Full install (Debian, includes chroma + onnx)
docker run -v ~/.alt-memory:/root/.alt-memory kilv/alt-memory:latest mcp
Tags:
kilv/alt-memory:latest— Debian-based, full installkilv/alt-memory:4.5.1— versioned Debiankilv/alt-memory:alpine— Alpine-based, FAISS + numpy BERT (~117MB)kilv/alt-memory:4.5.1-alpine— versioned Alpine
Architecture
┌──────────────────────────────────────────────────────┐
│ MCP Server (stdio / SSE) │
│ 65 JSON-RPC tools for AI agents │
├──────────────────────────────────────────────────────┤
│ Dimension │
│ orchestrates realms, domains, entities │
├──────────────────────┬───────────────────────────────┤
│ Vector Store │ SQLite + FTS5 │
│ (FAISS / ChromaDB) │ (entities, KG, metadata) │
├──────────────────────┴───────────────────────────────┤
│ Embedder Layer (pluggable) │
│ numpy (TF-IDF+SVD) ── numpy_bert ── minilm (ONNX) │
│ sentence-transformers ── spaCy ── embeddinggemma │
└──────────────────────────────────────────────────────┘
Key files
| File | Purpose |
|---|---|
alt_memory/dimension.py |
Main Dimension class — all CRUD, search, status, personas |
alt_memory/mcp_server.py |
MCP server — 65 JSON-RPC tools over stdio/SSE |
alt_memory/cli.py |
CLI — 30+ commands |
alt_memory/backends/embedder.py |
Embedder factory — numpy, ONNX, sentence, spaCy |
alt_memory/backends/faiss_store.py |
FAISS vector store |
alt_memory/backends/chroma_store.py |
ChromaDB vector store |
alt_memory/backends/knowledge_graph.py |
Knowledge Graph (temporal triples) |
alt_memory/searcher.py |
BM25 ranking, hybrid re-rank, neighbor expansion |
alt_memory/dim_graph.py |
Palace graph — tunnels, traversal |
alt_memory/miner.py |
File mining — auto-chunk, entity extraction |
alt_memory/sync.py |
Sync — prune stale entities |
alt_memory/dialect.py |
AAAK compression dialect |
alt_memory/layers.py |
L0/L1/L2 memory stack |
alt_memory/config.py |
Configuration manager |
License
MIT
Project details
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 alt_memory-4.5.2.tar.gz.
File metadata
- Download URL: alt_memory-4.5.2.tar.gz
- Upload date:
- Size: 283.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aeff0c5eff98b1cfc5f3a66fd6ebdee62ade2f7d058af238ade2626e02185698
|
|
| MD5 |
45e4344eef7e985a74922ca4ff625a00
|
|
| BLAKE2b-256 |
20b4799839f1bb9b8ff103a62da6c277e4428104323961516791e3bce65be939
|
File details
Details for the file alt_memory-4.5.2-py3-none-any.whl.
File metadata
- Download URL: alt_memory-4.5.2-py3-none-any.whl
- Upload date:
- Size: 284.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aae6069ef281f261a7cac932cdc61b9a2ee8e6eef0bc49d26d76d72f74d7f4b2
|
|
| MD5 |
7a7f484f88432d38b966d0f5912360d1
|
|
| BLAKE2b-256 |
22f31e5f0fb7804bb553481e4f798fc1c95431d78abab7e30b7df869f495500c
|