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, runsCREATE 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-resolvesDATA_DIRto 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
adminbinary
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.modData 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 contextWhy PostgreSQL Over a Dedicated Vector DB
mememory uses PostgreSQL with pgvector instead of a dedicated vector database (Qdrant, Pinecone, Weaviate). Reasons:
Single dependency. One database for both metadata and vectors. No need to synchronize between a relational DB and a vector DB.
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.
SQL for everything. Hierarchical scope filters, TTL cleanup, metadata queries, export/import — all standard SQL. No need to learn a vector DB query language.
Mature ecosystem. PostgreSQL has battle-tested backup, replication, monitoring, and tooling.
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.