KIZUNA-MEM temporal graph memory engine

Your agents forget everything. Fix that.

Persistent memory that tracks relationships, handles knowledge updates, and retrieves context via spreading activation. Not another vector store.

zig + rust · p95 31ms measured · 10K tenants · zero data loss
GitHub stars
main.py
python typescript rust elixir
## observe, retrieve, repeat
from kizuna_mem import Client

mem = Client(tenant_id="user-42")

# ingest a fact
mem.observe("User switched to Pro plan")

# spreading activation retrieval
ctx = mem.retrieve("billing info?")
# → Pro plan (2m ago), payment method,
#   upgrade history, related preferences

Vector search finds similar text. Your agent needs to understand.

RAG and vector stores treat memories as isolated chunks of text ranked by cosine similarity. They can't track what changed, what's connected, or what matters right now.

Vector store
here are 10 chunks sorted by cosine similarity
Kizuna-Mem
here's what's true now, what changed, and what's related
01 — AMNESIA

Total context reset every session.

Your agent learns preferences, context, history — then forgets it all. Users repeat themselves. Trust erodes.

session 1: "I prefer dark mode"
session 2: "What theme do you prefer?"
02 — STALE FACTS

Knowledge updates break retrieval.

Free tier in January, Pro in March. Vector stores return both ranked by similarity. Without temporal validity, your agent serves outdated facts confidently.

✗ sim=0.94 "free tier"  ← stale
✓ sim=0.91 "pro plan"   ← current
03 — ISOLATED CHUNKS

No relationships between memories.

Vector stores treat each memory as an independent point in embedding space. They can't connect "Sarah works on Alpha" to "Sarah's on vacation" — because those chunks aren't similar, they're related.

vector: "alpha" ↛ sarah ↛ vacation
graph:  alpha → sarah → vacation mar 20
04 — CONTEXT COLLAPSE

Similarity ≠ relevance.

"Project Strawberry" (a codename) and "strawberries at the market" are close in embedding space but completely unrelated. Vector search conflates them. Graph memory knows the difference because it tracks what things are, not just what they sound like.

✗ cosine "strawberry" → groceries, recipes, project
✓ graph  "strawberry" → entity:project → sprint, team

Memory that matures, like biological memory does.

Three phases mirror how human memory works: immediate capture, pattern recognition, long-term consolidation. Grounded in ACT-R cognitive architecture.

1
Observe
real-time · sync

Raw conversations hit the graph immediately. Entities extracted, relationships mapped, timestamps recorded. WAL ensures zero data loss.

input: "User switched to Pro plan"

creates:
  node  user-42
  edge  has_plan
  node  pro_plan
  t_event 2024-03-14T10:32:00Z
2
Reflect
async · background

Deduplicates facts, resolves entities, supersedes stale data. Old facts aren't deleted — they're temporally invalidated.

free_tier → invalidated
pro_plan   → current

entity resolution:
  "John" + "John Smith"entity:john_smith
3
Consolidate
nightly · batch

Builds community clusters, extracts stable user traits, produces multi-level hierarchy. Episodes → facts → entities → communities → profile.

profile:
  plan:  pro (since mar)
  theme: dark (stable)

communities:
  billing ← plan / payment / invoices
  prefs   ← theme / notifications / lang
Spreading Activation Retrieval
not vector similarity — graph energy propagation

When you query Kizuna-Mem, it doesn't just find similar text. It finds anchor nodes in the graph, then propagates activation energy outward through edges — like ripples in water.

  1. 1. Anchor — query maps to entry nodes via entity match + embedding similarity
  2. 2. Propagate — energy flows through edges, decaying by distance and fan-out
  3. 3. Boost — recent and frequently accessed nodes get base-level activation bonus (ACT-R)
  4. 4. Rank — top-K nodes by final activation score, temporally filtered
Why this matters

Vector search asks: "what text looks like this query?" Spreading activation asks: "what in the graph is connected to what this query is about?"

Graph Traversal
query: "billing info?"

                    payment_method
                   ╱ 0.61
● billing ━━━▸ ● pro_plan
  1.0    0.82   0.82   ╲
   ╲                  upgrade_history
    ╲                  0.48
     ╲                ╲
      free_tier        invoices
      0.31 ✗ stale      0.29
Activation Trace
query: "billing info?"
activation path:
  billing ━━0.82━▸ pro_plan
                ┣━0.61━▸ payment_method
                ┣━0.48━▸ upgrade_history
                ┗━0.29━▸ invoices
  billing ━━0.31━▸ free_tier (superseded)

returned: 4 active nodes, 1 filtered
fan decay applied at pro_plan (4 edges)
Vector Similarity

Returns chunks ranked by cosine distance. No relationships. No temporal filtering. "Strawberry" matches groceries and projects alike.

Spreading Activation

Propagates energy through typed edges. Fan decay prevents popular nodes dominating. Recency + frequency boost via ACT-R base-level.

Everything a production memory system needs.

BITEMPORAL MODEL

Two timelines per fact.

Event time (when it happened) and ingestion time (when the system learned it). Answer ‘what did we know on Tuesday?’ accurately.

MULTI-TENANT

10K tenants, isolated.

Every API call scoped by tenant_id. Complete memory isolation between users. Built-in, not bolted on.

CRASH-SAFE

WAL. Zero data loss.

Write-ahead log ensures every observation persists before acknowledgement. Crash, restart, lose nothing.

ENTITY RESOLUTION

“John” = “John Smith”.

The Reflector automatically merges references to the same entity. Aliases, nicknames, partial mentions — resolved into a single graph node.

COMMUNITY DETECTION

Auto-clustering topics.

The Consolidator groups related entities into communities — billing, preferences, projects — with generated summaries for fast context loading.

USER PROFILES

Traits emerge over time.

Stable patterns extracted automatically: preferences, habits, communication style. Your agent gets smarter the longer it knows someone.

Four SDKs. Five minutes.

Thin HTTP client wrappers. Install, connect, observe, retrieve. Same API shape in every language.

python pip install kizuna-mem
typescript npm i @kizuna/mem
rust cargo add kizuna-mem
elixir {:kizuna_mem, "~> 0.1"}
Observe
from kizuna_mem import Client

mem = Client(tenant_id="user-42")

# ingest facts as they happen
mem.observe(
    "User upgraded to Pro plan",
    source="billing-agent"
)

mem.observe(
    "Prefers dark mode, dislikes emails",
    source="onboarding"
)
Retrieve
# spreading activation retrieval
ctx = mem.retrieve(
    "What plan is the user on?"
)

# rich structured response
ctx.memories     # ranked nodes
ctx.profile      # stable traits
ctx.activations  # score + path
ctx.communities  # topic clusters
Observe
import { Client } from '@kizuna/mem'

const mem = new Client({ tenantId: 'user-42' })

await mem.observe(
  'User upgraded to Pro plan',
  { source: 'billing-agent' }
)
Retrieve
const ctx = await mem.retrieve(
  'What plan is the user on?'
)

ctx.memories     // ranked nodes
ctx.profile      // stable traits
ctx.activations  // score + path
ctx.communities  // topic clusters
Observe
use kizuna_mem::Client;

let mem = Client::new("user-42");

mem.observe(
    "User upgraded to Pro plan",
    Source::new("billing-agent"),
).await?;
Retrieve
let ctx = mem.retrieve(
    "What plan is the user on?"
).await?;

ctx.memories     // ranked nodes
ctx.profile      // stable traits
ctx.activations  // score + path
ctx.communities  // topic clusters
Observe
alias KizunaMem.Client

{:ok, mem} = Client.start_link(
  tenant_id: "user-42"
)

Client.observe(mem,
  "User upgraded to Pro plan",
  source: "billing-agent"
)
Retrieve
{:ok, ctx} = Client.retrieve(mem,
  "What plan is the user on?"
)

ctx.memories     # ranked nodes
ctx.profile      # stable traits
ctx.activations  # score + path
ctx.communities  # topic clusters

Built to be measured.

Latency numbers are measured from the test suite. LongMemEval-S and LoCoMo scores are targets — academic evaluation runs are planned for Phase 2.

System LongMemEval-S LoCoMo P95 Latency Temporal Graph
Kizuna-Mem ≥85% (target) ≥88% (target) 31ms
EverMemOS 83.0% 93.1%
Cortex / HydraDB 90.2%
Zep / Graphiti 71.2%
TiMem 76.9%

Zig for the graph. Rust for the vectors.

Two processes, each playing to their language's strengths. Shared-memory IPC with CRC32 checksums. No GC pauses on the hot path.

Z
Zig Core
├── mmap-backed graph store
├── WAL crash recovery
├── BM25 + temporal indexes
├── Observer / Reflector / Consolidator
├── Spreading activation engine
├── Arena allocator (per-query)
└── HTTP API server
Why Zig — Explicit allocators, no hidden allocs on hot path, comptime lookup tables, pointer control for mmap alignment
R
Rust Sidecar
├── BGE-small-en-v1.5 embeddings
├── HNSW vector index
├── SIMD distance kernels (AVX2/NEON)
├── ONNX NER entity extraction
└── LLM client
Why Rust — Mature ML ecosystem (ort, candle), SIMD intrinsics, existing HNSW + embedding libraries
zig  ◀━━ shared-memory ring buffer · CRC32 checksums ━━▶  rust

Give your agents memory.

Open source. Early access.

git clone https://github.com/kizuna/kizuna-mem