What it is
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.
Architecture
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.
API
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
Retrieval
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.
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
Agent Ecosystems
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.
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.
Personality
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.
Serve
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.
YOU MUST NOT, AVOID, Note:) into the system prompt.Visualizer
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.
Benchmarks
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.
Small subsets and a single judge, so not comparable to published leaderboards. How to run them, and what each measures, is in the README.