Memoire
Local-first semantic memory for AI coding agents.
Memoire stores lessons from AI agent runs, ranks them by trust, reinforces only what actually helped, and lets multiple agents share one database without cross-contamination.
Why
AI coding agents repeat the same mistakes across sessions:
Task 1 → use float for money → tests fail
Task 2 → use float for money again → tests fail again
With Memoire:
Task 1 fails → store lesson: "Never use float for money. Use Decimal."
Task 2 starts → recall: score=0.84 trust=0.41 action=HINT
Task 2 passes → reinforce: trust rises because the memory helped
What It Does
- Storage: SQLite, local-only, no external API calls
- Embeddings:
all-MiniLM-L6-v2via ONNX Runtime — runs fully offline - Deduplication: stable BLAKE3 fingerprints, exact-content deduplication
- Quality scoring: actionability, consequence, novelty, reusability, evidence
- Trust model: EMA with reinforcement, penalty, time decay, cold-start seed
- NLI contradiction detection: three-signal ensemble (cosine + polarity + negation asymmetry)
- MMR recall: suppresses near-duplicate results from top-k slots
- Namespaces: hard multi-tenant isolation in one SQLite file
- Export/Import: JSON snapshot backup and restore
- Interfaces: Rust library, Python (PyO3), C FFI, MCP server, HTTP API
- WASM:
qualitymodule (NLI + scoring) available without SQLite or ONNX
Install
Requirements: Rust ≥ 1.75, C linker (MSVC on Windows). First run downloads the embedding model.
git clone https://github.com/tazwaryayyyy/Memorie-AI
cd Memorie-AI
cargo build --release
Outputs:
| Target | Path |
|---|---|
| CLI | target/release/memoire |
| HTTP server | target/release/memoire-server |
| Shared lib (Linux) | target/release/libmemoire.so |
| Shared lib (macOS) | target/release/libmemoire.dylib |
| Shared lib (Windows) | target/release/memoire.dll |
Quick Start
Rust
use memoire::Memoire;
let m = Memoire::new("agent.db")?;
m.remember("Never use float for money. Use Decimal for billing calculations.")?;
let memories = m.recall("billing precision", 5)?;
for mem in &memories {
println!("[score={:.3} trust={:.3} state={}] {}", mem.score, mem.trust, mem.state, mem.content);
}
if let Some(top) = memories.first() {
m.reinforce_if_used(top.id, "Implemented billing with Decimal.", true)?;
}
Python
pip install maturin
maturin dev --manifest-path bindings/python/Cargo.toml
from memoire import Memoire, MemoryPolicy
with Memoire("agent.db", namespace="billing-agent") as m:
m.remember("Never use float for money. Use Decimal for billing calculations.")
memories = m.recall("billing precision", top_k=5)
decisions = MemoryPolicy().evaluate(memories)
context = MemoryPolicy().inject_context(decisions)
Trust Model
Every recalled memory carries four signals:
| Field | Meaning |
|---|---|
score |
Semantic relevance + recency + quality weight |
trust |
How strongly the agent should rely on this memory |
uncertainty |
Whether the signal is noisy or oscillating |
state |
active, shadow, or archived |
Recommended policy
| Trust | Action |
|---|---|
≥ 0.75 |
FOLLOW — inject as strong context |
≥ 0.45 |
HINT — inject softly, verify before acting |
< 0.45 |
IGNORE |
Trust combines: reinforcement history (35%), confidence (25%), recency (20%), importance (15%), contradiction survival (5%). Cold-start seeds trust_ema = quality × 0.5 so new memories aren't invisible. Time decay: trust × exp(−0.01 × days_since_last_used).
Core API
Rust
let mut m = Memoire::new("agent.db")?;
// Store, recall, recall with MMR dedup, cross-encoder reranking
let ids = m.remember("lesson text")?;
let results = m.recall("query", 5)?;
let diverse = m.recall_mmr("query", 5, 0.5)?;
let reranked = m.recall_reranked("query", 5)?;
let explained = m.recall_explained("query", 5)?; // Detailed rank attribution
// Feedback and optimization
m.reinforce_if_used(ids[0], "agent output", true)?;
m.penalize_if_used(&[ids[0]], 1.0)?;
m.recompute_prototypes()?; // Re-align centroids with updated embeddings
m.forget(ids[0])?;
// Background Maintenance Scheduler
// Triggers maintenance_pass() every 300s or after 10 insertions
m.start_background_maintenance(300, 10);
// Export / import
let snapshot = m.export_namespace()?;
let target = Memoire::new_ns("backup.db", "billing-agent")?;
target.import_namespace(&snapshot)?;
Python
with Memoire("agent.db") as m:
count = m.remember("lesson text")
memories = m.recall("query", top_k=5)
diverse = m.recall_mmr("query", top_k=5, mmr_lambda=0.5)
explained = m.recall_explained("query", top_k=5) # List of attribution breakdowns
ok = m.reinforce_if_used(memories[0].id, "output", True)
outcomes = m.penalize_if_used([memories[0].id], failure_severity=1.0)
m.recompute_prototypes() # Re-align centroids
m.start_background_maintenance(interval_secs=300, threshold=10)
deleted = m.forget(memories[0].id)
snapshot = m.export_namespace()
For C/FFI consumers: docs/FFI_GUIDE.md.
NLI Contradiction Detection
When two memories address the same topic but make opposing claims, Memoire archives the lower-quality one. Detection uses a three-signal ensemble:
- Cosine similarity ≥ 0.80 — same topic cluster
- Opposing polarity — one asserts, the other negates
- Negation asymmetry — negation tokens present in one text but not the other
Configurable via ScoringConfig:
use memoire::quality::ScoringConfig;
let config = ScoringConfig {
use_nli_contradiction: true, // default: true
nli_cosine_threshold: 0.80, // default: 0.80
..ScoringConfig::default()
};
let m = Memoire::new("agent.db")?.with_scoring_config(config);
Set use_nli_contradiction: false to revert to the original polarity-only gate.
Namespaces
Multiple agents share one SQLite file with hard isolation:
let agent_a = Memoire::new_ns("shared.db", "agent-a")?;
let agent_b = Memoire::new_ns("shared.db", "agent-b")?;
agent_a.remember("JWT tokens expire after 15 minutes.")?;
assert!(agent_b.recall("JWT", 5)?.is_empty()); // fully isolated
Export / Import
memoire export --namespace billing-agent --output billing.json
memoire import billing.json --namespace billing-agent
The snapshot preserves content, trust_ema, reinforcement_count, importance_base, confidence, and created_at. Embeddings are recomputed on import.
MCP Server
cd mcp-server && uv sync --locked && uv run memoire-mcp
Claude Desktop config:
{
"mcpServers": {
"memoire": {
"command": "uv",
"args": ["--directory", "/path/to/memoire/mcp-server", "run", "memoire-mcp"],
"env": { "MEMOIRE_DB_PATH": "/path/to/agent.db" }
}
}
}
Available tools: memoire_health, memoire_remember, memoire_recall, memoire_reinforce, memoire_penalize, memoire_batch_feedback, memoire_resolve_conflicts, memoire_forget, memoire_count, memoire_status, memoire_clear, memoire_export, memoire_import, memoire_identify_gaps, memoire_namespace_health. All accept a namespace parameter.
HTTP API Server + Dashboard
./target/release/memoire-server # → http://localhost:6779
cd dashboard && npm install && npm run dev # → http://localhost:3000
Set MEMOIRE_ALLOWED_PATHS in dashboard/.env.local to restrict which database paths the dashboard may open.
Token authentication
All routes except GET /health are protected by an optional bearer-token guard.
# Enable auth — set this before starting the server
export MEMOIRE_API_TOKEN="your-strong-secret"
./target/release/memoire-server
# → "Token auth enabled (MEMOIRE_API_TOKEN is set)."
# Every call must include the header:
curl -H "Authorization: Bearer your-strong-secret" \
http://localhost:6779/recall -d '{"db":"agent.db","ns":"default","query":"billing"}'
If MEMOIRE_API_TOKEN is unset the server prints a warning and allows all traffic — appropriate for local-only usage. Never expose the server on a public interface without setting the token.
WASM Build
The quality module (NLI, scoring, polarity detection) compiles to wasm32-unknown-unknown without SQLite or ONNX:
cargo build --target wasm32-unknown-unknown --no-default-features --features wasm
Offline / Air-Gapped
./target/release/memoire cache-models
Model is cached under ~/.cache/fastembed/. Subsequent runs need no network.
Tests
cargo test --lib
cargo test --test integration_test
cargo clippy --all-targets --all-features -- -D warnings
MCP tests:
cd mcp-server && uv sync --locked --extra dev && uv run pytest
More Detail
Security
Database file permissions
On Unix, Memoire restricts the .db file to 0600 (owner read/write only) at pool initialisation. No extra steps are needed. On Windows, use filesystem ACLs or NTFS permissions to achieve equivalent isolation.
HTTP server authentication
Set MEMOIRE_API_TOKEN to a strong secret before running memoire-server. Every request to a protected route must include Authorization: Bearer <token>. The /health endpoint is always public. See HTTP API Server for usage.
For production deployments over a network, place memoire-server behind a reverse proxy (nginx, Caddy) with TLS.
Python thread safety
PyMemoire wraps the inner Memoire in an Arc<Mutex>. Concurrent calls from multiple Python threads block on the lock instead of raising PyO3 borrow errors. No additional user-side locking is required.
Status
Production-ready for local and MCP-server deployments. The Rust core, PyO3 binding, CLI, MCP server, HTTP API, and dashboard are all covered by CI.
Author
Tazwar Ahnaf · @TazwarEnan
License
MIT. See LICENSE.
No comments yet
Be the first to share your take.