Skip to main content
Glama
chinwe

compound-memory

compound-memory

CI PyPI Python License: MIT

English | 简体中文

Local-first shared memory for multiple AI agents — plain Markdown files that compound in value as they are used. Memory lives on your disk as frontmatter-annotated Markdown, gets stronger with every confirmed use, decays into a revivable archive when neglected, and auto-commits to a local git history on every write.

Why

Every agent session starts from zero: preferences get re-asked, project conventions get re-discovered, the same pitfall gets hit twice. compound-memory gives all your agents one shared store:

  • Local-first — nothing leaves your machine; memories are human-readable Markdown files, not rows in an opaque database.

  • MCP-native — exactly 5 tools (memory_write / memory_search / memory_get / memory_link / memory_feedback) as the single read-write boundary; works with any MCP host (Claude Code, ZCode, WorkBuddy, …), plus a full CLI for operations.

  • Compounding — confirmed usage raises confidence, related memories are recalled as neighbors, validation from a different host counts as independent evidence, and distillation merges many raw memories into fewer, denser ones.

  • Multi-agent by design — a _shared namespace everyone reads, plus agent-* private namespaces each host owns; cross-host validation is tracked per host.

  • Optional semantic recall — vector search via sqlite-vec + BGE embeddings, with automatic graceful fallback to pure lexical search when unavailable.

Related MCP server: SharedBrain

Quick Start

For AI agents

Paste this one-liner into your coding agent (Claude Code, Cursor, ZCode, …) and let it do the rest:

Set up compound-memory (https://github.com/chinwe/compound-memory) — a local-first multi-agent shared memory (MCP server + CLI) — on this machine: install it (`uv tool install compound-memory`, or clone the repo and `uv sync --extra dev`), initialize the store (`compound-memory init`, defaults to ~/.agents/memory), register its stdio MCP server in this host's MCP config — command `compound-memory-server` (PyPI install) or `uvx --from compound-memory compound-memory-server`, env `COMPOUND_MEMORY_ROOT=~/.agents/memory` and `COMPOUND_MEMORY_AGENT_ID=agent-<your-host-id>` — then verify by calling `memory_search` and expecting a `{"hits": [...]}` response; if the host needs a restart to load MCP servers, tell me. Host-specific configs and the usage protocol: docs/agent-integration.md in the repo.

For humans

1. Install

Python ≥ 3.11. Either route works:

# Route A: clone the repo (uv-managed; same path the MCP config uses)
git clone https://github.com/chinwe/compound-memory.git
cd compound-memory && uv sync --extra dev

# Route B: install from PyPI (no clone needed)
uv tool install compound-memory   # or: pip install compound-memory

2. Initialize your store

Defaults to ~/.agents/memory; override with the COMPOUND_MEMORY_ROOT env var.

uv run compound-memory init

This lets your everyday agents read/write the shared store automatically:

{
  "mcpServers": {
    "compound-memory": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "--directory", "<repo>", "compound-memory-server"],
      "env": {
        "COMPOUND_MEMORY_ROOT": "~/.agents/memory",
        "COMPOUND_MEMORY_AGENT_ID": "agent-<your-host-id>"
      }
    }
  }
}

Installed from PyPI? Swap command/args for uvx + ["--from", "compound-memory", "compound-memory-server"] — no repo clone needed. Setting COMPOUND_MEMORY_AGENT_ID is strongly recommended: the store then resolves caller identity from the process env, so a model misreporting its identity (or forging someone else's source) is rejected loudly.

Verify: ask your agent to call memory_search (any keyword) — a {"hits": [...]} response means you're connected. Or run uv run compound-memory stats from the CLI.

4. Next step

Inject the usage protocol from skills/compound-memory/SKILL.md into your host (the search → feedback → distill loop), per docs/agent-integration.md §6.

Demo

compound-memory CLI demo: init → write → search → feedback → stats

One full loop: write → search → feedback (with cross-host first-validation bonus) → store health. Real output from v0.4.0, long payloads trimmed:

uv run compound-memory init
{ "ok": true, "root": "~/.agents/memory" }

Two different hosts each write one stable fact (new memories start at confidence 0.5, uses 0):

uv run compound-memory write \
  "Deploy serverless functions on this platform times out at 10s — keep handlers under that budget" \
  fact agent-claude --key vercel-timeout
{
  "id": "20261007_86adf1",
  "ns": "_shared",
  "type": "fact",
  "source": "agent-claude",
  "content": "Deploy serverless functions on this platform times out at 10s — keep handlers under that budget",
  "confidence": 0.5,
  "uses": 0,
  "key": "vercel-timeout",
  "validated_by": []
  ...
}
uv run compound-memory write \
  "User prefers concise replies with tables and code examples" \
  fact agent-zcode --key user-style

Search ranks by score (--explain attaches per-hit ranking components for debugging):

uv run compound-memory search "serverless timeout"
[
  {
    "id": "20261007_86adf1", "score": 1.0292, "similarity": 1.0,
    "type": "fact", "source": "agent-claude",
    "content": "Deploy serverless functions on this platform times out at 10s — keep handlers under that budget",
    "neighbors": []
  },
  {
    "id": "20261007_6a0c0c", "score": 0.5211, "similarity": 0.4919,
    "type": "fact", "source": "agent-zcode",
    "content": "User prefers concise replies with tables and code examples",
    "neighbors": []
  }
]

A different host used this memory and reported it back — uses +1, conf +0.1; and since the reporter agent-workbuddy ≠ source agent-claude, the first cross-host validation adds another +0.15:

uv run compound-memory feedback 20261007_86adf1 agent-workbuddy
{
  "id": "20261007_86adf1",
  "confidence": 0.75,
  "uses": 1,
  "last_used": "2026-10-07",
  "validated_by": ["agent-workbuddy"],
  "evidence": {
    "success_count": 1, "failure_count": 0, "contradiction_count": 0,
    "last_verified": "2026-10-07",
    "recent": [{ "date": "2026-10-07", "agent": "agent-workbuddy", "outcome": "success" }]
  }
  ...
}

Store health at a glance (fixed-bucket histograms, liveness, distillation yield):

uv run compound-memory stats
{
  "total": 2, "archived": 0, "active": 2,
  "avg_confidence": 0.625,
  "by_type": { "fact": 2 },
  "by_ns": { "_shared": 2 },
  "review_queue_entries": 0,
  "uses_histogram": { "0": 1, "1-2": 1, "3-5": 0, "6-9": 0, "10+": 0 },
  "confidence_histogram": { "<0.3": 0, "0.3-0.6": 1, "0.6-0.8": 1, "0.8-1.0": 0 },
  "recent_feedback_7d": 1, "cross_validated": 0,
  "distilled_total": 0, "distilled_recent_7d": 0
}

Three things to notice:

  • New memories start at confidence 0.5 and move on evidence — feedback carries an outcome: success raises it, failure lowers it (floor 0.05), contradiction freezes it into the review queue, obsolete archives immediately.

  • First validation from a different host earns an independent bonus (once per host per memory), with validated_by / evidence trails — confidence is evidence of correctness, not popularity.

  • Hits embed one-hop neighbors automatically (empty here — no links yet; memory_link creates bidirectional links that get recalled for free).

How compounding works

Interest source

Mechanism

① Usage reinforcement

memory_feedback: uses+1, conf+0.1

② Link value

memory_link creates bidirectional links; memory_get pulls one-hop neighbors; search hits embed up to 3 compact neighbors (active memories only, --no-neighbors to disable)

③ Distillation

distill-plan (CLI, deterministic candidates + dual-signal dedup annotations) → agent judgment → distill-apply atomic commit (product links back to sources; sources archived but revivable)

④ Cross-agent validation

Feedback from an agent other than the source adds conf +0.15

Scoring (weights are the W_* constants in src/compound_memory/scoring.py): 0.70·similarity + 0.15·confidence + 0.10·recency(0.5+0.5·e^(−Δt/τ)) + 0.05·type weight. With the vector channel enabled, ranking switches to RRF fusion with an ε=0.04 prior tie-break (see the spec, "index as cache").

The 5 MCP tools

Tool

Purpose

Key points

memory_write

Write a memory

type: episode/fact/insight/skill/decision; source: your agent id; give fact/insight/decision a stable key; optional valid_from/valid_until (ISO dates) and project scope

memory_search

Retrieve

Returns {"hits": [...]} ranked by score; embeds up to 3 one-hop neighbors; dual-channel by default (_shared + caller's own private ns); optional project (fail-closed) and explain

memory_get

Fetch by id

Always contains a found key; pulls one-hop neighbors; private-ns targets require reader

memory_link

Link two memories

Bidirectional; both sides must be in the same ns; private-ns links require owner identity

memory_feedback

Report "this memory was actually used"

Default outcome=success: uses+1, conf+0.1; first cross-host validation +0.15; also failure / contradiction / obsolete / unknown. Mandatory after adopting a hit — that's the loop that makes the store compound

Tool descriptions embed the protocol rules themselves, so agents keep the loop intact even without host-side rules injected. Full parameter reference: docs/agent-integration.md.

CLI

uv sync --extra dev              # first clone: build .venv (later `uv run` reuses it)

uv run compound-memory init               # initialize an empty store
uv run compound-memory write "Vercel Serverless has a 10s timeout" episode agent-workbuddy
uv run compound-memory search "Vercel timeout"   # hits embed one-hop neighbors (limit 3, --no-neighbors to disable)
uv run compound-memory feedback <id> agent-claude
uv run compound-memory decay          # run from cron
uv run compound-memory revive <id>    # revive an archived memory
uv run compound-memory distill-plan   # distillation candidates: merge_with (same-key strong) + possible_dup_of (BM25 weak) + promotion_candidate (high-activity episodes)
uv run compound-memory distill-apply "the merged insight" insight agent-workbuddy --sources <id1>,<id2>  # atomic: product (links, origin=distillation) + source archival, one commit
uv run compound-memory stats            # health: uses/confidence buckets + liveness + distillation yield
uv run compound-memory rebuild-index  # rebuild the search cache anytime
uv run compound-memory review-queue   # conflict queue (CLI-only entry)
uv run compound-memory git-log        # audit trail

More operations: explain <id> (confidence composition + evidence detail for one memory), forget <id> --agent <id> (terminal removal, ADR-0009), review-resolve (adjudicate conflicts), extract <transcript|dir> (deterministic session-transcript mining).

Architecture

Agent (MCP client / CLI)
  └─ memory_write | memory_search | memory_get | memory_link | memory_feedback
       └─ MemoryStore (~/.agents/memory)
            ├─ namespaces/_shared/{episode,fact,insight,skill}/*.md   shared area
            ├─ namespaces/agent-*/...                                  private areas
            ├─ archive/...                                             decayed archive (revivable)
            ├─ index/tokens.json                                       rebuildable search cache
            ├─ review-queue.md                                         fact/insight conflict queue
            └─ .git/                                                   auto-commit on every write

Scheduled distillation prep (launchd / cron / systemd)

Per ADR 0001, the deterministic prep runs on a schedule while judgment (summarizing / merging) stays with the calling agent. Every day at 09:00 the candidate list lands in <root>/distill/last-plan.json. Pick one scheduler — launchd (macOS standard, catches up after sleep), systemd user timer (Persistent=true, same catch-up), or cron (most portable, no catch-up) — all three drive the same platform-neutral scripts/distill-prepare.sh. Ready-made templates with copy-paste instructions: scripts/com.compound-memory.distill-prepare.plist.tmpl (launchd), scripts/compound-memory-distill-prepare.{service,timer}.example (systemd), and the Chinese README for cron. The script runs set -eu: any failure exits non-zero (visible via launchctl list / systemctl --user list-timers / cron mail, log at distill/prepare.log). distill/ is a runtime artifact directory (auto-gitignored) — no commit noise; only distill-apply after agent judgment lands one atomic commit.

Documentation

Development

uv run pytest tests/ -q     # full suite (MCP tool boundary + distillation + lifecycle/index/CLI + input defense)
uv run mypy src/compound_memory/

Test seams: the MCP tool boundary via in-process mcp.Client(server) (no subprocess) plus unit tests for core modules (scoring / index / store ops). CI runs tests, type checks, and a pure-wheel install smoke across Python 3.11/3.12/3.13.

Release

PyPI versions are immutable and the tag must match pyproject.toml's version (the release workflow verifies this and fails loudly). Releases go through GitHub Actions + PyPI Trusted Publisher (OIDC, no token): push a tag like v0.1.0 and release.yml builds and publishes automatically.


MCP Registry name: mcp-name: io.github.chinwe/compound-memory

Available Tools

5 tools
memory_feedbackA

Report feedback on a memory with an outcome (closes the compounding loop — call after actually adopting a memory). outcome: 'success' (default, the memory worked), 'failure' (it misled you — confidence drops 0.2, floor 0.05), 'contradiction' (you dispute it — confidence frozen and a review entry is queued pending adjudication), 'obsolete' (it is superseded — archived immediately), 'unknown' (records the event only). Anything else is rejected. Success raises confidence (+0.1; extra +0.15 when a different agent validates for the first time). agent must be your own source agent id. Memories in a private 'agent-' namespace accept feedback only from the owner (agent = 'agent-' or ''). Archiving is reversed on feedback (except outcome=obsolete, which archives instead).

ParametersJSON Schema
NameRequiredDescriptionDefault
agentYes
mem_idYes
outcomeNosuccess

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the entire behavioral burden and does so richly: exact confidence deltas (+0.1 success, +0.15 for first-time cross-agent validation, -0.2 failure with 0.05 floor), freezing and queued review for 'contradiction', immediate archiving for 'obsolete', rejection of any other value, ownership restriction for private 'agent-<name>' namespaces, and archiving being reversed on feedback. This is far beyond what any structured field provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose and the trigger before enumerating outcomes, and every clause carries information not present in the schema. The dense run of parentheticals makes it slightly heavy to scan, but there is little genuine filler to cut.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter mutation tool with no annotations, no output schema, and 0% schema coverage, the description covers timing, per-outcome behavior, and authorization thoroughly. The one remaining gap is what the caller receives back (returned confidence, review-entry id), though the state changes themselves are disclosed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: every meaningful value of 'outcome' is defined with its side effect and the default is noted, and 'agent' is constrained to "your own source agent id" with the private-namespace ownership rule spelled out. Only 'mem_id' is left implicit, which is reasonable for a self-evident identifier.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Report feedback on a memory with an outcome") and immediately differentiates itself from siblings like memory_write/memory_get by framing feedback as the step after a memory is adopted. The compounding-loop phrasing makes its role in the memory lifecycle unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"call after actually adopting a memory" gives a clear trigger condition, and the per-outcome effects tell the agent which outcome applies when. It stops short of explicitly comparing itself to the sibling tools or stating when not to call it, so it is clear context without full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_getA

Fetch a memory by id; one-hop link neighbors are included by default. reader: your own source agent id — required when the memory lives in a private 'agent-' namespace (readable only by its owner host). project: your workspace project slug — get-by-id itself is always readable regardless of project, but embedded neighbors are filtered to global ones plus your project's. After adopting it, call memory_feedback (agent = your source id).

ParametersJSON Schema
NameRequiredDescriptionDefault
mem_idYes
readerNo
projectNo
include_neighborsNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does substantial work: it discloses that neighbors are returned by default, that private-namespace reads require the owner's reader id, and that embedded neighbors are filtered to global plus the caller's project. It does not describe return shape, error modes, or whether missing ids fail loudly, leaving some behavioral gaps for a 4-parameter read tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action and default behavior are front-loaded in the first clause, and the parameter notes follow in order. The longer em-dash sentences and the trailing memory_feedback instruction add real information but make the block denser than it needs to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no annotations, the description supplies the permission model, the default neighbor behavior, and the project-scoping rule — enough for an agent to call it correctly in the common case. It stops short of describing the response payload or failure behavior, which a 0%-coverage schema leaves entirely undocumented.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and largely does: reader gets meaning plus a required-when condition, project gets meaning plus its filtering effect on neighbors, and include_neighbors is implied by 'included by default'. Only mem_id is left undefined, which is self-evident from the purpose sentence.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch a memory by id', and immediately narrows scope by noting that one-hop link neighbors are included by default. It never explicitly contrasts with memory_search or memory_link, so an agent gets the gist but must infer the boundary between this and the search sibling on its own.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states a real conditional rule ('reader: required when the memory lives in a private agent-<name> namespace') and a follow-up workflow ('After adopting it, call memory_feedback'). What is missing is a negative case — there is no statement of when to prefer memory_search or memory_link instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_writeA

Write a memory. type: episode|fact|insight|skill|decision; source: writing agent id; ns: '_shared' or 'agent-'. key: stable id for fact/insight/decision (enables conflict review). Write only stable facts (preferences, conventions, environment constraints, pitfalls), not session-temporary details; volatile status notes (in-progress work, remaining todos) either carry valid_until or stay out — a stale status memory is worse than none; prefer reusing an existing key over a new entry. valid_from/valid_until: optional ISO dates (YYYY-MM-DD) marking the fact's validity window — once valid_until has passed, the memory is excluded from search results but still readable via memory_get. project: optional lowercase-slug scope tag (lowercase alphanumeric segments joined by dashes) for workspace-specific memories — tagged memories are hidden from searches that do not pass the same project, while untagged (global) memories stay visible everywhere; declare your workspace project per the host usage rules and pass it on every write/search in that workspace. Returns the stored memory; conflict: true means a different version with the same key exists and a review entry was queued.

ParametersJSON Schema
NameRequiredDescriptionDefault
nsNo_shared
keyNo
typeYes
linksNo
sourceYes
contentYes
projectNo
valid_fromNo
valid_untilNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses conflict handling ("conflict: true means a different version with the same key exists and a review entry was queued"), the post-expiry lifecycle (excluded from search but readable via memory_get), and project-based visibility scoping. It stops short of stating auth requirements, rate limits, or upsert/idempotency semantics for repeat writes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then grouped by parameter and lifecycle concern; nearly every sentence adds usable information. It is dense and semicolon-packed, which costs a little readability, but there is no obvious filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter mutation tool with no annotations and no output schema, the description covers scope, conflict behavior, temporal validity, and project isolation, plus the return value. The remaining gaps are the undocumented links parameter and content semantics, which are minor but real.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and largely does: it defines type values (episode|fact|insight|skill|decision), ns values ('_shared' or 'agent-<name>'), key semantics (stable id enabling conflict review), valid_from/valid_until format (ISO YYYY-MM-DD) and behavior, and project format (lowercase-slug) and visibility effect. Only links and content are left undocumented beyond their names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ("Write a memory") and immediately enumerates the memory types, which tells an agent exactly what this tool stores. It does not name a sibling explicitly, so an agent must infer that this is the write path versus memory_search/memory_get, keeping it just below a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-and-when-not guidance: write stable facts (preferences, conventions, constraints, pitfalls) and not session-temporary details, with a stated rationale ("a stale status memory is worse than none"). It also directs the agent to reuse an existing key over creating a new entry and explains the valid_until escape hatch, leaving little to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.4.3
    • First observedmemory_feedback
    • First observedmemory_get
    • First observedmemory_link
    • First observedmemory_search
    • First observedmemory_write

TDQS

A4.2/5.0

Scored across 5 tools

Disambiguation5/5

Each tool maps to a distinct action: search, get, write, link (association), and feedback (outcome reporting). The boundaries are clear with no functional overlap between any pair.

Naming Consistency5/5

All five tools follow an identical memory_<verb> pattern (write, search, get, link, feedback). Fully predictable and consistent.

Tool Count5/5

Five tools cover the core memory operations (persist, retrieve, associate, evaluate) without redundancy. The set is well-scoped for a memory substrate.

Completeness4/5

Write/search/get/link/feedback cover the lifecycle, and update is handled implicitly via same-key writes while obsolete-archiving substitutes for delete. Explicit update/edit or a bulk-list operation are minor gaps an agent can work around.

Maintenance

ActivityNo data
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Local-first, file-based memory layer for AI agents — one shared Markdown vault across Claude, Codex, Gemini, Cursor and any MCP client. Provides read/write memory tools with an audit trail, per-agent trust levels, and Git sync; no cloud and no lock-in.
    2
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Local-first, multi-user shared memory for AI agents with semantic search, offline support, and team synchronization.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to capture, structure, remember, and retrieve source-backed memory as local Markdown files, with reviewable writes and no cloud dependency.
    199
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides AI agents with persistent, local cross-session shared memory by combining vector semantic retrieval with knowledge graph relationships, and supports short/long-term memory management and local backups.
    -