smrti

Memory engine for AI agents.

Bayesian beliefs. Emotional valence. Attention-weighted salience. Spaces that evolve apart. A single SQLite file.

$ pip install smrti GitHub
Memory‑Enriched
Response

Knowledge stored as atoms

smrti is an AtomSpace-inspired graph database for agent memory. Each node—an atom—carries a Bayesian truth value, an emotional valence, and an attention weight. Retrieval ranks by salience, relevance scaled by standing, not by timestamp. Your agent remembers what matters, not just what happened last.

Evidence is append-only. Observations are logged and revised into truth values during consolidation epochs via PLN (Probabilistic Logic Networks); a superseded claim loses, and a report that a memory was used counts as evidence too. Multi-tenant isolation keeps agent memories separate by tenant and space.

type
concept · belief · episode · goal · relation
truth
probability [0,1] + confidence [0,1]
attention
STI (short-term) + LTI (long-term)
valence
emotional tone [-1,1] + intensity [0,1]
entity
person · org · project · role · tool · technology · skill · topic · media · health · …
links
source → target with typed relations

Seven layers, one SQLite file

Vector indexing via sqlite-vec (multilingual-MiniLM-L12-v2, 384 dimensions, 50+ languages) and lexical indexing via FTS5, both in the one file. Entity resolution cascades through exact match, cross-type label match, alias lookup, fuzzy matching (RapidFuzz), and embedding similarity before creating new nodes.

smrti facade
servers config.py · mcp.py · rest.py · proxy.py · viz_routes.py · reflect_loop.py · tools.py
personality params.py · presets.py
evolution epoch.py · truth.py (PLN revision) · reinforcement.py · attention.py · valence.py · healing.py · connections.py
spaces set_ops.py (five set operations on two spaces) · emergence.py (bridge spaces)
retrieval fan_out.py (KNN + BM25, rank fusion) · salience.py · diversify.py · classify.py · text.py
extraction extract.py (hybrid GLiNER + LLM extraction) · ner.py (16-type zero-shot NER) · resolve.py (5-tier entity resolution) · pronouns.py · sentiment.py · temporal.py (relative dates resolved at write time) · aliases.py
core models.py · atomspace.py · db.py · embed.py · provenance.py

Seven operations

remember, recall, believe, reinforce, reflect, forget, personality. The Python API is the same interface the MCP and REST servers expose.

from smrti import Smrti

engine = Smrti(personality="deterministic")

# Store a memory with negative valence
engine.remember(
    "Deploying on Friday caused a 2-hour outage",
    valence=-0.8
)

# Positive experience
engine.remember(
    "Feature flags made the rollout safe",
    valence=0.6
)
# Salience-ranked retrieval
results = engine.recall("deployment risks")

for r in results:
    print(
        f"{r.atom.content}",
        f"salience={r.salience:.2f}",
        f"confidence={r.atom.truth.confidence:.2f}",
        f"valence={r.atom.valence.valence:.1f}",
    )

# KNN + BM25, fused → 1-hop graph expansion → salience → diversity cap
# Negative-valence atoms surface first when relevant
# Assert a belief with supporting evidence
engine.believe(
    "Feature flags reduce deployment risk",
    probability=0.85,
    evidence="3 successful staged rollouts"
)

# Evidence is appended, never overwritten;
# engine.evidence(atom_id) reads the log back.
# The consolidation epoch revises truth via PLN.
# Report that recalled memories were used
results = engine.recall("deployment risks")
engine.reinforce([r.atom.id for r in results])

# Use is weak evidence: confidence climbs a little,
# capped per epoch. Probability does not move.
# Run a consolidation epoch
epoch = engine.reflect()

print(epoch)
# EpochResult(
#   beliefs_updated=3,
#   atoms_decayed=12,
#   atoms_pruned=1,
#   lti_promoted=2,
#   new_connections=4,
#   contradictions_resolved=1,
#   orphans_healed=2
# )

# Revise evidence → decay → propagate → heal → promote
# → resolve contradictions → prune. Runs when the space is used.
# Stop matching memories from surfacing
forgotten = engine.forget("Friday deployment outage", top_k=5)

# Confidence sinks below the surfacing floor and the atoms
# are stamped: excluded from every recall, never lifted back
# by consolidation, and removed by a later epoch.
# Switch preset at runtime
engine.set_personality("analytical")

# 6 presets: balanced, analytical, curious,
# empathetic, maverick, deterministic
# Each tunes 17 hyperparameters that control
# learning rate, decay, promotion, and salience weights

Salience scoring

Candidates come from a vector KNN and a BM25 search fused by reciprocal rank fusion, then one hop out through the graph. Relevance gates standing: similarity multiplies the standing terms, so a memory that is not about the question cannot outrank one that is. Personality hyperparameters set the weights, and a diversity cap keeps one moment from filling more than a sixth of the answer.

S = similarity × ( wsim + wsti × STI + wconf × confidence + wlti × LTI + wval × |valence| × intensity )

Dynamic weight shifting

When valence drops below −0.5, weight shifts from STI to valence. Severe negative-valence atoms (errors, failures) get an LTI floor of 0.5 on creation, preventing epoch pruning. Critical errors outrank recent trivia. Ranking reads the tone a memory was written with, not the mood it has absorbed from its neighbours.

Severity classification

Each recall result carries a severity tag. The proxy injects memories as plain imperative instructions into the system prompt: YOU MUST NOT, AVOID, or Note:

  • critical_warning — caller-stated valence < −0.5, intensity > 0.5, on anything but a bare concept
  • known_antipattern — probability < 0.3, confidence > 0.3; where a superseded preference lands
  • context — neutral background

Spaces as social graphs

read_spaces decides who can see whom. Give each agent its own space and personality, then wire them together. Each space consolidates independently, so the same event decays differently for every agent.

researcher
personality: curious
Fast learning, aggressive exploration. Forgets quickly. Keeps only what excites.
reads
researcher
shared
deployer
personality: deterministic
Fast learning, slow decay. Holds onto critical failures. Never forgets an outage.
reads
deployer
shared
coordinator
personality: analytical
Reads every space. Filters through its own analytical lens. Sees the whole picture.
reads
coordinator
shared
researcher
deployer
agent teams
Private working memory per agent, shared project context. Personality shapes what each one considers important.
simulations
Private beliefs and a shared commons. Each agent remembers the same event differently over time.
role-based perspectives
Different contexts for the same user. An analytical work space and an empathetic personal space, cross-readable when needed.

Spaces also support set theory operations: space_overlap, space_intersection, space_difference, space_union, space_symmetric_difference. Matching uses a three-signal contextual score (embedding + entity-type + graph neighborhood) that correctly separates homonyms like "Java" the language from "Java" the island. When two spaces overlap significantly, space_merge() materialises a bridge space — new atoms with PLN-merged truth values and blended valence, linked back to both parents. Bridges are built only on request, through space_merge as an MCP tool, a REST route, or the facade; the consolidation epoch never grows one.

17 hyperparameters, 6 presets

Each preset tunes how the agent learns, forgets, and weighs emotion. Swap at runtime with set_personality() or define custom profiles.

balanced
Default. Equal weight distribution across all dimensions.
learn
0.30
decay
0.10
promote
0.70
valence
0.10
analytical
Slow belief updates. Strict promotion. Confidence-heavy retrieval.
learn
0.15
decay
0.05
promote
0.90
valence
0.05
curious
Fast learning. Aggressive exploration. Attention-weighted recall.
learn
0.50
decay
0.20
promote
0.50
valence
0.15
empathetic
Emotion-dominant. High valence weight. Mood-sensitive scoring.
learn
0.40
decay
0.08
promote
0.70
valence
0.35
maverick
Low decay. Broad connections. Eclectic, exploratory recall.
learn
0.10
decay
0.15
promote
0.40
valence
0.20
deterministic
Agentic workflows. Fast learning + slow decay. Strict LTI promotion.
learn
0.40
decay
0.08
promote
0.85
valence
0.12

Five modes, same engine

All server modes run entity extraction after every remember() call, building concept nodes and relation edges from stored episodes (GLiNER locally, an LLM for the claims), and resolve relative dates against the write time. Disable with SMRTI_EXTRACT=0 and SMRTI_TEMPORAL=0. Set SMRTI_API_KEY to require a key on every HTTP request; REST and proxy expose Prometheus metrics at /metrics. smrti stop ends whatever smrti serve started.

MCP
Stdio server for Claude, Cursor, and any MCP-compatible client. 8 tools: remember, recall, reflect, forget, status, personality, space_query, space_merge.
smrti serve mcp
REST
FastAPI on port 8420. JSON request/response. remember, recall, reinforce, reflect, forget, status, personality, and the two-space routes space_query and space_merge.
smrti serve rest
Proxy
OpenAI-compatible on port 8421. Injects relevant memories as plain imperative instructions (YOU MUST NOT, AVOID, Note:) into the system prompt.
smrti serve proxy
Visualizer
Interactive graph explorer. Inspect atoms, relations, attention weights, and valence in the browser. Auto-refresh at 2 s, 5 s, 10 s, or 30 s intervals.
smrti serve viz
Town
smrti-town on port 8430: a city-builder demo where every citizen carries its own memory graph and acts on what it remembers. Ships in the same wheel.
smrti serve town
Smrti Visualizer — graph explorer showing concept nodes, episode nodes, and typed relation edges

Concept nodes (blue) linked to episodes (green) via typed edges. Node size encodes LTI. Valence-tinted stroke. Inspector panel shows full atom stats on click.

Retrieval scored apart from answering

Two harnesses ingest a published dataset as episodes and answer its questions through recall. Retrieval and answering are scored separately, so a strong answering model cannot hide a retrieval regression. Config as of 2026-08-26: extraction off, no consolidation epochs, top_k 50, the deterministic preset, one model answering and judging. That measures retrieval alone, and it predates the current ranking formula.

LongMemEval-S
40 questions, one per ability in turn. Retrieval hit 0.975, evidence recall 0.912, answers 0.900. Five of six abilities retrieve without a miss.
HaluMem
3 personas, 180 questions. Correct 0.517, hallucination 0.394, omission 0.089. Strong on what the user never said (2.9% invented), weak on synthesis.

Small subsets and a single judge, so not comparable to published leaderboards. How to run them, and what each measures, is in the README.