Skip to main content

System Overview

Engram is built as an agent-agnostic Go binary with thin adapter plugins per-agent. The Go binary is the brain — plugins just translate agent-specific events into Engram API calls.
┌─────────────────────────────────────────────────────────────┐
│  Agent (OpenCode / Claude Code / Cursor / Windsurf / etc.)  │
└─────────────┬───────────────────────────────────────────────┘

              ├─ Plugin (TypeScript adapter) ──────────────────┐
              │  • Session tracking                            │
              │  • Auto-start server                           │
              │  • Memory Protocol injection                   │
              │  • Compaction recovery                         │
              └────────────────────────────────────────────────┘

              ├─ MCP stdio (13 memory tools)
              ├─ HTTP API (port 7437)

┌─────────────▼───────────────────────────────────────────────┐
│              Engram Go Binary (single executable)           │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  internal/store/   — Core: SQLite + FTS5 + data ops │   │
│  │  internal/server/  — HTTP REST API (port 7437)      │   │
│  │  internal/mcp/     — MCP stdio server (13 tools)    │   │
│  │  internal/sync/    — Git sync: manifest + chunks    │   │
│  │  internal/tui/     — Bubbletea terminal UI          │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────┬───────────────────────────────────────────────┘

┌─────────────▼───────────────────────────────────────────────┐
│         SQLite + FTS5 (~/.engram/engram.db)                 │
│  • sessions                                                  │
│  • observations + observations_fts                           │
│  • user_prompts + prompts_fts                                │
│  • sync_chunks                                               │
└──────────────────────────────────────────────────────────────┘

Core Components

1. Store (internal/store/store.go)

The heart of Engram — all data operations go through this.
  • SQLite connection management (WAL mode, busy timeout, foreign keys)
  • Schema creation and migration
  • FTS5 index management (synced via triggers)
  • Session CRUD (create, end, list)
  • Observation CRUD (add, update, delete, soft-delete)
  • Full-text search with query sanitization
  • Timeline generation (before/after an observation)
  • Deduplication (normalized hash + rolling window)
  • Topic upserts (same project + scope + topic_key updates existing)
  • Privacy tag stripping (<private>[REDACTED])
  • Export/import (JSON dump of all data)
  • Git sync chunk tracking
The store uses pure Go SQLite (modernc.org/sqlite) — no CGO, no external dependencies. This enables true cross-platform single binary distribution.

2. HTTP Server (internal/server/server.go)

REST API on port 7437 for plugins and integrations.

Endpoints

  • GET /health — Health check ({"status": "ok", "service": "engram", "version": "0.1.0"})
  • GET /stats — Memory statistics (sessions, observations, prompts, projects)
  • POST /sessions — Create session ({id, project, directory})
  • POST /sessions/{id}/end — End session ({summary})
  • GET /sessions/recent — Recent sessions (?project=X&limit=N)
  • POST /observations — Add observation
  • GET /observations/recent — Recent observations (?project=X&scope=project|personal&limit=N)
  • GET /observations/{id} — Get single observation
  • PATCH /observations/{id} — Update fields (partial updates)
  • DELETE /observations/{id} — Delete (?hard=true for permanent)
  • GET /search — FTS5 search (?q=QUERY&type=TYPE&project=PROJECT&scope=SCOPE&limit=N)
  • GET /timeline — Chronological context (?observation_id=N&before=5&after=5)
  • POST /prompts — Save user prompt
  • GET /prompts/recent — Recent prompts
  • GET /prompts/search — Search prompts
  • GET /context — Formatted context from previous sessions (?project=X&scope=project|personal)
  • GET /export — Export all data as JSON
  • POST /import — Import data from JSON
The HTTP server listens on 127.0.0.1:7437 (localhost only). Override with ENGRAM_PORT environment variable.

3. MCP Server (internal/mcp/mcp.go)

Model Context Protocol server (stdio transport) that exposes 13 memory tools to any MCP-compatible agent.

Tool Profiles

Engram supports tool profiles to reduce context usage:
engram mcp
engram mcp --tools=all
The agent profile is recommended for production use — it excludes rarely-used admin tools, saving ~800 tokens per context window.

Server Instructions

The MCP server includes instructions for Claude Code’s Tool Search:
Engram provides persistent memory that survives across sessions and context 
compactions. Search these tools when you need to: save decisions, bugs, 
architecture choices, or discoveries to memory; recall or search past work 
from previous sessions; manage coding session lifecycle (start, end, 
summarize); recover context after compaction. Key tools: mem_save, 
mem_search, mem_context, mem_session_summary, mem_get_observation, 
mem_suggest_topic_key.

4. Sync (internal/sync/sync.go)

Git-based memory sharing using compressed chunks.

Architecture

.engram/
├── manifest.json          ← index of all chunks (small, git-mergeable)
├── chunks/
│   ├── a3f8c1d2.jsonl.gz ← chunk 1 (gzipped JSONL)
│   ├── b7d2e4f1.jsonl.gz ← chunk 2
│   └── c9f1a2b3.jsonl.gz ← chunk 3
└── engram.db              ← local working DB (gitignored)

Workflow

# Export new memories as a chunk
engram sync
# Creates .engram/chunks/{hash}.jsonl.gz + updates manifest.json

# Commit to git
git add .engram/ && git commit -m "sync engram memories"

# On another machine: import new chunks
engram sync --import
# Reads manifest.json, imports chunks not in sync_chunks table

# Check status
engram sync --status
# Shows: 3 chunks in manifest, 2 imported, 1 pending
Why chunks? Each engram sync creates a NEW file — old chunks are never modified. No merge conflicts, just append-only git history.

5. TUI (internal/tui/)

Interactive terminal UI built with Bubbletea.

Structure (Gentleman Bubbletea Patterns)

  • Screen constants (Screen int iota)
  • Single Model struct holds ALL state
  • Init() function
  • Custom messages for async operations

Screens

  • Dashboard: Stats overview + menu
  • Search: FTS5 text search with text input
  • Search Results: Browsable results list
  • Recent Observations: All observations, newest first
  • Observation Detail: Full content, scrollable
  • Timeline: Chronological context (before/after)
  • Sessions: All sessions list
  • Session Detail: Observations within a session
TUI uses dedicated store methods (AllSessions, AllObservations) that don’t filter by session status, unlike MCP context methods which only show completed sessions.

Data Flow

Observation Creation

Search Flow

Plugin Architecture

OpenCode Plugin

TypeScript adapter in ~/.config/opencode/plugins/engram.ts:
1

Auto-start server

Checks if http://127.0.0.1:7437/health responds. If not, spawns engram serve in background.
2

Auto-import git chunks

Detects .engram/manifest.json in project directory, runs engram sync --import.
3

Session management

ensureSession() creates session on-demand via HTTP API (idempotent, survives plugin reloads).
4

Memory Protocol injection

chat.system.transform hook concatenates Memory Protocol into system prompt (compatible with single-system-message models like Qwen, Ministral).
5

Compaction recovery

experimental.session.compacting hook injects previous context + instructs compressor to call mem_session_summary.
6

Privacy stripping

Strips <private> tags before sending to HTTP API (defense layer 1).

Claude Code Plugin

Bash scripts + skill system in ~/.claude/plugins/engram/:
  • startup (session-start.sh): Ensures server, creates session, imports chunks, injects context
  • compact (post-compaction.sh): Injects context + recovery instructions
  • stop (session-stop.sh): Logs session end
Claude Code plugin hooks use bash scripts. On Windows, requires Git Bash or WSL. Use bare MCP (Option C in setup) for native Windows support.

Design Decisions

  • Single binary: No Node.js, no Bun, no runtime dependencies
  • Cross-platform: Works natively on macOS, Linux, Windows (x86_64 and ARM64)
  • Pure Go SQLite: modernc.org/sqlite has no CGO — true single binary distribution
  • Fast startup: Go binary starts in milliseconds vs Node.js ~100ms
  • FTS5 covers 95% of use cases: Full-text search with BM25 ranking is sufficient for code memory
  • No separate process: No ChromaDB, no Pinecone, no vector service to manage
  • Single file: ~/.engram/engram.db is portable, backupable, debuggable with sqlite3 CLI
  • Simpler: Zero configuration, zero network calls
  • Agent already has the LLM: No need for separate API calls
  • Agent has context: It knows what just happened better than a background service
  • No extra cost: No additional API usage beyond the agent’s work
  • No latency: Compression happens inline during the agent’s response
  • Raw tool calls are noisy: edit: {file: "foo.go"} pollutes search results
  • Low signal-to-noise ratio: Shell history and git already provide the audit trail
  • Bloats database: Thousands of low-value observations vs dozens of curated summaries
  • Agent curates better: Structured mem_save summaries are higher quality and more searchable

Project Structure

engram/
├── cmd/engram/main.go              # CLI entrypoint — all commands
├── internal/
│   ├── store/store.go              # Core: SQLite + FTS5 + all data operations
│   ├── server/server.go            # HTTP REST API server (port 7437)
│   ├── mcp/mcp.go                  # MCP stdio server (13 tools)
│   ├── setup/setup.go              # Agent plugin installer (go:embed)
│   ├── sync/sync.go                # Git sync: manifest + chunks (gzipped JSONL)
│   └── tui/                        # Bubbletea terminal UI
│       ├── model.go                # Screen constants, Model struct, Init()
│       ├── styles.go               # Lipgloss styles (Catppuccin Mocha palette)
│       ├── update.go               # Update(), handleKeyPress(), per-screen handlers
│       └── view.go                 # View(), per-screen renderers
├── plugin/
│   ├── opencode/engram.ts          # OpenCode adapter plugin
│   └── claude-code/                # Claude Code plugin (hooks + skill)
│       ├── .claude-plugin/plugin.json
│       ├── .mcp.json
│       ├── hooks/hooks.json
│       ├── scripts/                # Bash scripts for lifecycle hooks
│       └── skills/memory/SKILL.md  # Memory Protocol skill
├── DOCS.md
├── README.md
├── go.mod
└── go.sum

Dependencies

Go Dependencies

  • modernc.org/sqlite — Pure Go SQLite (no CGO)
  • github.com/mark3labs/mcp-go — MCP protocol implementation
  • github.com/charmbracelet/bubbletea — Terminal UI framework
  • github.com/charmbracelet/lipgloss — Terminal styling
  • github.com/charmbracelet/bubbles — TUI components

Plugin Dependencies

  • @opencode-ai/plugin — OpenCode plugin types
  • Runtime: Bun (built into OpenCode)
  • Claude Code plugin: bash (for hooks)

Next Steps

How It Works

Memory system, session lifecycle, and 3-layer pattern

Memory Protocol

When to save, when to search, and session close protocol

Build docs developers (and LLMs) love