Autonomous memory for AI agents. Bi-temporal graph + episodic log + procedural skills. MCP-native.
  • Go 99.7%
  • Makefile 0.2%
Find a file
airaneel c0570d6cd2
All checks were successful
build-image / build (push) Successful in 19s
Шаринг областей в API, и «менялся ли факт» — на всех путях, а не только в recall
Обход supersedes существовал с начала (store.FactPredecessors, рекурсия по
первичному ключу), но звал его только recall. Виды, перечисляющие факты
одной сущности или одного эпизода, приходили с пустым predecessors — и
клиент, показывающий факт, не мог сказать, у кого из них есть прошлое.
Читателю оставалось открывать каждую строку или считать, что прошлого нет
ни у кого. Один рекурсивный запрос на страницу, не по строке и не
группировкой по ключу: у факта без объекта ключ схлопывается в
(src, predicate), и группировка отчиталась бы обо всех атрибутах хоста как
об одной длинной истории.

Заодно шаринг: сервис ListShares/InviteToScope/AcceptShare/RevokeShare/
CancelInvite жил только в MCP, и GUI не мог ни показать, кому область
открыта, ни открыть её.

Доли — единственное место, где наружу уходит tenant, и намеренно: общее
правило в том, что субъект не покидает сервер, но грант с вымаранной второй
стороной не говорит владельцу ничего, на что можно действовать — отзыв
принимает id получателя, а различить двух получателей на одной области и
есть весь вопрос.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 01:39:23 +03:00
.forgejo/workflows ci: correct the workflow header about registry auth 2026-07-28 13:17:57 +03:00
cmd JSON-поверхность на huma: доменные типы публикуются, DTO не заводятся 2026-08-17 19:08:14 +03:00
configs skills: raise the floor to 0.60, where no wrong recipe comes back alone 2026-07-30 14:56:54 +03:00
internal Шаринг областей в API, и «менялся ли факт» — на всех путях, а не только в recall 2026-08-18 01:39:23 +03:00
pkg/types Шаринг областей в API, и «менялся ли факт» — на всех путях, а не только в recall 2026-08-18 01:39:23 +03:00
.gitignore Sprint 0: bootstrap mnemos memory server 2026-04-27 15:08:17 +03:00
.golangci.yml Sprint 0: bootstrap mnemos memory server 2026-04-27 15:08:17 +03:00
.mcp.json gopls подключён как MCP-сервер проекта 2026-08-16 12:16:49 +03:00
CLAUDE.md Шаринг областей в API, и «менялся ли факт» — на всех путях, а не только в recall 2026-08-18 01:39:23 +03:00
complexity_test.go Функция ограничена цикломатической сложностью 10, а не строками 2026-08-16 12:18:10 +03:00
docker-compose.yml Sprint 0: bootstrap mnemos memory server 2026-04-27 15:08:17 +03:00
Dockerfile build: cross-compile natively instead of emulating the target arch 2026-07-14 11:36:35 +03:00
go.mod JSON-поверхность на huma: доменные типы публикуются, DTO не заводятся 2026-08-17 19:08:14 +03:00
go.sum JSON-поверхность на huma: доменные типы публикуются, DTO не заводятся 2026-08-17 19:08:14 +03:00
LICENSE Sprint 0: bootstrap mnemos memory server 2026-04-27 15:08:17 +03:00
main.go Sprint 0: bootstrap mnemos memory server 2026-04-27 15:08:17 +03:00
Makefile JSON-поверхность на huma: доменные типы публикуются, DTO не заводятся 2026-08-17 19:08:14 +03:00
PLAN.md scope: three recall modes + mnemos_scopes discovery 2026-07-12 14:04:22 +03:00
README.md extractor: the graph has one producer, so cut the other 2026-07-30 10:30:36 +03:00
rules_test.go Три списка, которые вели руками, теперь сверяются с тем, что описывают 2026-08-16 12:17:32 +03:00

mnemos

Autonomous memory for AI agents. Bi-temporal graph + episodic log + procedural skills. One Go binary, one Postgres. MCP-native. MIT.

mnemos is a memory server that any MCP-compatible client (Claude Desktop, Claude Code, Cursor, Windsurf, custom agents) can connect to. It stops agents from forgetting between sessions and gives them a real bi-temporal knowledge graph instead of a flat vector store.

Why another memory system

mnemos Memory MCP MemPalace Mem0 Graphiti
Bi-temporal graph ⚠️ flat
Procedural skills
Multi-agent scoping ⚠️ ⚠️
Sleep consolidation
Single binary
Any LLM (OAI-compat) n/a

How it works

Writes are fast and dumb; understanding happens later — like sleep.

  1. observe appends an event to the episodic log (embed + insert, no LLM).
  2. The consolidate worker ticks in the background: extracts subject predicateobject facts from unconsolidated events via any OpenAI-compatible LLM, and writes them into the graph bi-temporally — a repeated fact reinforces the existing edge instead of duplicating it, a contradicting fact supersedes the old one (which stays queryable as history), an out-of-order historical fact backfills a closed interval. The reflect step folds message → tool_call* chains into procedural skills with a running success rate (a correction event inside a chain counts as failure).
  3. recall is hybrid: vector search over facts and episodes, plus 1-hop graph expansion from query-matched entities, plus pins, plus skills — filtered by scope and the bi-temporal pivot (at).
  4. Decay: importance of untouched memories halves every decay_half_life; anything recall returns gets its clock reset. Old noise fades, things you keep coming back to stay strong.

Scopes are slash-separated namespaces (andy/raidflow) — materialized paths, so both ancestor and descendant lookups are cheap. Recall has three modes:

  • empty scope → whole tenant. No scope given means "search everything I have" — the sensible default for an agent that hasn't mapped its memory.
  • explicit scope → walk-up. andy/raidflow sees itself + ancestors up to global, but not siblings or children. This is the isolation guarantee: project A's facts never leak into project B.
  • descendants: true → subtree. Widens an explicit scope to also include everything nested under it.

Call mnemos_scopes to discover which namespaces exist before targeting one. Facts, events, skills and pins are scoped; entities (nodes) are global. Two scopes may hold contradicting facts.

Quick start

docker compose up -d postgres ollama       # pgvector + local LLM
docker compose exec ollama ollama pull nomic-embed-text
docker compose exec ollama ollama pull llama3.1:8b-instruct

go build -o mnemos .
./mnemos migrate up
./mnemos serve                             # StreamableHTTP on :8090

MCP endpoint: http://localhost:8090/mcp. Also served on the same port: /healthz, /readyz, /metrics (Prometheus). For local stdio clients: server.transport: stdio.

MCP tools

Tool Purpose Key args
mnemos_observe record an event into the episodic log content*, kind (message/tool_call/observation/decision/correction/reflection), scope, parent_id
mnemos_recall hybrid retrieval: vector + 1-hop graph + temporal query*, scope (empty = whole tenant), descendants, at (RFC3339), since/until, limit
mnemos_facts bi-temporal facts about an entity ("what was true at T") node_id*, at
mnemos_skill procedural patterns: "how did I do this before" task*, scope, descendants, limit
mnemos_search_nodes find entities by name (trigram) or meaning (vector) query*, kind, limit
mnemos_scopes list namespaces that hold memory (counts, last activity)
mnemos_pin core memory, always returned by recall text*, scope, ttl

There is deliberately no forget/update/delete — contradictions are handled by bi-temporal supersession in the consolidate worker.

Configuration

Defaults < YAML file < MNEMOS_* env vars. Full annotated example: configs/mnemos.example.yaml.

./mnemos --config /etc/mnemos.yaml serve
# or pure env:
MNEMOS_DATABASE_DSN="postgres://mnemos:pw@host:5432/mnemos?sslmode=disable" \
MNEMOS_EMBEDDINGS_BASE_URL="http://ollama:11434/v1" ./mnemos serve

Embeddings take any OpenAI-compatible endpoint (Ollama, OpenAI, DeepSeek, vLLM, proxies). Embedding dimension is fixed at 768 by the schema — for OpenAI text-embedding-3-* set dimensions: 768 and request_dimensions: true. The embedder is the only model mnemos calls: fact extraction was removed once it had been switched off for good, and the agent writing through MCP is the sole producer of the graph.

Postgres needs the vector, pg_trgm and btree_gist extensions. vector is not trusted, so on a shared instance pre-create it as superuser — migrations use IF NOT EXISTS.

Importing existing memory

./mnemos import claude ~/Downloads/claude-export/   # Claude.ai export.zip contents
./mnemos import markdown ~/notes --scope andy/notes # one event per .md file

Imports write plain events; the consolidate worker turns them into graph facts on its own schedule (backfilled timestamps land as historical facts).

Development

make test        # unit tests; integration tests skip without a DB
make lint vet

Integration tests run against any pgvector Postgres:

docker run -d --rm -e POSTGRES_USER=mnemos -e POSTGRES_PASSWORD=mnemos \
  -e POSTGRES_DB=mnemos_test -p 54329:5432 pgvector/pgvector:pg16
MNEMOS_TEST_DATABASE_URL="postgres://mnemos:mnemos@localhost:54329/mnemos_test?sslmode=disable" \
  go test ./... -count=1

Architecture, schema and design decisions: PLAN.md. Conventions and invariants for contributors (and agents): CLAUDE.md.

Status

Sprints 07 complete: storage, memory service, MCP server, bi-temporal write path (supersession, dedup/reinforce), decay, importers, observability (Prometheus + OTel). Running against Postgres 16/17 + pgvector 0.8. Not yet: multi-tenant auth, web UI, replication (see PLAN.md §8).

License

MIT