Skip to content

Architecture

mememory is a Go monorepo with three binaries, a React admin UI, and a Docker-based infrastructure layer. This page covers the system design, data flow, and key implementation decisions.

System Overview

                     Host Machine                          Docker Stack
                ┌─────────────────────┐          ┌──────────────────────────┐
                │                     │          │                          │
User ────────── │   mememory CLI      │──HTTP──> │   Admin API (:4200)      │
                │   (bootstrap,       │          │   mememory                 │
                │    status)          │          │      │                   │
                │                     │          │      ├── REST endpoints  │
                └─────────────────────┘          │      └── Web UI (React) │
                                                 │            │             │
Agent ──stdio── │   server              │──────────│────────────┤             │
                │   (inside Docker)   │          │            │             │
                │                     │          │            ▼             │
                └─────────────────────┘          │   ┌──────────────┐      │
                                                 │   │  PostgreSQL  │      │
                                                 │   │  + pgvector  │      │
                                                 │   │  (:5432)     │      │
                                                 │   └──────────────┘      │
                                                 │                          │
                                                 │   ┌──────────────┐      │
                                                 │   │   Ollama     │      │
                                                 │   │  (:11434)    │      │
                                                 │   └──────────────┘      │
                                                 └──────────────────────────┘

Components

server (MCP server)

The MCP server binary (server inside the container, built from cmd/mememory-server/). Communicates with agents via stdio (stdin/stdout). Registers 7 MCP tools and 2 MCP resources. Runs inside the mememory Docker container.

  • Entry point: cmd/mememory-server/main.go
  • Runs a background TTL cleanup goroutine (hourly)
  • On startup: requires DATABASE_URL (fails fast if missing), connects to PostgreSQL, runs CREATE EXTENSION IF NOT EXISTS vector, applies migrations, probes embedding dimension, validates database column

admin (Admin API)

The Admin API and web UI server (admin inside the container, built from cmd/mememory-admin/). Serves REST endpoints on port 4200 and the React admin UI as static files.

  • Entry point: cmd/mememory-admin/main.go
  • REST API: internal/api/router.go, internal/api/handler.go
  • Static file serving: embedded React build from web/dist/

mememory CLI

Native Go binary for host-side operations. Does not connect to PostgreSQL or Ollama directly — communicates with the Admin API over HTTP.

  • Entry point: cmd/mememory/main.go
  • Commands: bootstrap, status, version
  • Auto-detects project from git repository root

PostgreSQL + pgvector

Stores all memories with their vector embeddings. Uses the HNSW index for approximate nearest neighbor search with cosine distance.

  • Docker image: pgvector/pgvector:pg17
  • Data persisted to $DATA_DIR/postgres/ (CLI auto-resolves DATA_DIR to an OS-standard path)
  • Schema managed via embedded SQL migrations
  • Cosine distance operator: <=> (lower = more similar)

Ollama

Runs local embedding models. The default model is nomic-embed-text (768 dimensions). No data leaves the machine.

  • Docker image: custom build that pulls the model on start
  • Data persisted to $DATA_DIR/ollama/
  • HTTP API at port 11434

React Admin UI

Single-page application for browsing and managing memories. Built with React + TypeScript.

  • Source: web/
  • Communicates with Admin API endpoints
  • Served as static files by the admin binary

Directory Structure

mememory/
├── cmd/
│   ├── mememory-server/       # MCP server → `server` binary in container
│   │   └── main.go
│   ├── mememory-admin/        # Admin API → `admin` binary in container
│   │   └── main.go
│   └── mememory/            # Native CLI (bootstrap, status, version)
│       ├── main.go
│       ├── bootstrap.go
│       └── status.go
├── internal/
│   ├── api/                 # REST API handlers (chi router)
│   │   ├── router.go
│   │   └── handler.go
│   ├── bootstrap/           # Shared bootstrap formatter (Markdown output)
│   │   └── format.go
│   ├── embeddings/          # Embedding provider abstraction
│   │   ├── embedder.go      # Embedder interface
│   │   ├── factory.go       # Provider factory (Config → Embedder)
│   │   ├── ollama.go        # Ollama HTTP client
│   │   ├── openai.go        # OpenAI-compatible HTTP client
│   │   └── probe.go         # Dimension auto-detection
│   ├── mcp/                 # MCP server registration
│   │   ├── tools.go         # 7 MCP tools + help text
│   │   └── resources.go     # MCP resources (bootstrap)
│   ├── engine/              # Business logic layer
│   │   ├── service.go       # Scoring, contradiction detection, CRUD
│   │   └── types.go         # Type re-exports
│   ├── postgres/            # PostgreSQL client
│   │   ├── client.go        # Queries, migrations, hierarchical WHERE
│   │   └── migrations/      # Embedded SQL migrations
│   └── types/               # Shared types (Memory, Scope, MemoryType, DTOs)
│       └── types.go
├── docker/
│   ├── docker-compose.yml   # Stack definition (postgres, ollama, admin)
│   ├── Dockerfile           # Multi-stage build (Go + React → Alpine)
│   └── ollama.Dockerfile    # Ollama with auto model pull
├── web/                     # React admin UI source
├── site/                    # VitePress documentation
├── scripts/
│   └── setup.sh             # First-time infrastructure setup
├── Makefile                 # Build and dev commands
└── go.mod

Data Flow

remember (store a memory)

Agent calls remember(content="...", scope="project", project="match", type="rule")

MCP tool handler validates input, sets defaults

Embedder.EmbedOne(content) → 768-dim float32 vector

Contradiction check: SearchWithWhere(vector, scope hierarchy, limit=5)
    → Any existing memory with similarity > 0.75 → warning

PostgreSQL INSERT (id, content, embedding, metadata)

If supersedes is set → UPDATE old memory weight to 0.1

Return Memory object + contradiction warnings (if any)

recall (search memories)

Agent calls recall(query="database architecture", project="match")

Embedder.EmbedOne(query) → query vector

HierarchicalWhere("", "match") → WHERE (scope='global' OR (scope='project' AND project='match'))

PostgreSQL: SELECT *, 1-(embedding <=> query_vector) AS score ... ORDER BY distance LIMIT 15

Filter expired (TTL check)

Filter superseded (collect supersedes IDs, remove targets)

Score each: similarity × scope_weight × memory_weight × temporal_decay

Sort by final score, trim to requested limit

Return [{memory, score}, ...]

bootstrap (session initialization)

mememory bootstrap --project match

Auto-detect project from git root (if --project not set)

HTTP GET /api/memories?scope=global&type=bootstrap&limit=100 → global bootstrap memories
HTTP GET /api/memories?scope=project&project=match&type=bootstrap&limit=100 → project bootstrap memories

Merge results

Format as Markdown with a hard-coded System section, then Bootstrap/Rules/Feedback/Facts/Decisions/Context groups

Append a `## Bootstrap Stats` block with project source, memory counts, token estimate, budget percent

If estimated tokens exceed MaxBootstrapTokens (30_000) → append `WARNING: bootstrap exceeds budget` to Stats block (no truncation)

Print to stdout → captured by SessionStart hook → injected into agent context

Why PostgreSQL Over a Dedicated Vector DB

mememory uses PostgreSQL with pgvector instead of a dedicated vector database (Qdrant, Pinecone, Weaviate). Reasons:

  1. Single dependency. One database for both metadata and vectors. No need to synchronize between a relational DB and a vector DB.

  2. pgvector is sufficient. For the scale of personal agent memory (hundreds to low thousands of memories), pgvector's HNSW index provides sub-millisecond search. Dedicated vector DBs optimize for millions+ vectors.

  3. SQL for everything. Hierarchical scope filters, TTL cleanup, metadata queries, export/import — all standard SQL. No need to learn a vector DB query language.

  4. Mature ecosystem. PostgreSQL has battle-tested backup, replication, monitoring, and tooling.

  5. Operational simplicity. One container instead of two. Less memory, less disk, fewer failure modes.

The tradeoff: if the memory count grows to millions, pgvector may become a bottleneck. At that point, migrating to a dedicated vector DB is straightforward since the Embedder interface is already abstracted.

Released under the MIT License.