KOPENG
Persistent, self-curating memory for coding agents. It enables local, zero-cost context recall through MCP tools with hybrid retrieval and autonomous consolidation.
README
KOPENG
Persistent, self-curating memory for coding agents — it doesn't just remember what you've done, it cleans up after itself, fully local.
Renamed 2026-07 to its current codename. Everything now uses
kopeng— hook env vars areKOPENG_*and the client data directory is~/.kopeng/.
KOPENG is a memory and context layer for coding agents (Claude Code, Codex CLI), exposed as MCP tools plus a REST API. It learns from observed tool-use — passively turning repeated tool calls, error-then-fix patterns, hot files, and cross-session sequences into confidence-scored memories with no LLM cost — and serves them back through a hybrid retrieval pipeline (RRF fusion of semantic + keyword, optional cross-encoder rerank, confidence-blended ranking), all running on local quantized ONNX models so there is no per-query API cost or data egress. Its distinguishing layer is autonomous nightly consolidation (the "dreaming Librarian"): a deterministic-first engine that collapses duplicate memories, decays stale ones, and routes contradictions and supersessions — every mutation snapshot-first, audited, and reversible. An optional local LLM (Ollama) is used only as a pair classifier; it never touches the write path.
Memory that curates itself instead of growing into landfill.
Why KOPENG is different
Most "agent memory" is append-only store-and-retrieve RAG: it remembers, it never prunes. The corpus drifts — duplicates pile up, stale facts outrank current ones, contradictory memories ("we use X" / "we switched to Y") both keep surfacing — and the operator becomes the garbage collector. KOPENG adds the missing half: curation.
- It curates, not just recalls — the dreaming Librarian. An autonomous nightly consolidation pass collapses duplicate memories, decays stale ones, and routes contradictions/supersessions for review. The engine is deterministic-first: routing, supersession direction, and every mutation are deterministic code — the optional LLM only classifies a pair (duplicate / preference-change / conditional / contested / unrelated) and is structurally locked out of the write path (
apply.ts, invariant #3). Every consolidation write that changes an existing memory (archive, merge, supersede, contradiction-mark) is snapshot-first and audited — snapshot to revisions → mutate → append-only audit log, with a compensation path that unrolls the mutation if the audit append fails ("no unaudited change survives", invariant #11) — reversible viaPOST /api/memories/:id/rollback; memories the pass creates are undone by archiving them through the same endpoint. Supersession is a temporal chain (deprecated_at/valid_from), not a deletion: both the old and new statement stay active and direction is timestamp-deterministic. This layer is feature-flagged (DREAMING_ENABLED, default OFF); auto-apply is hard-restricted in code to exactly two change classes (exact duplicates and decay), both shipping OFF by default — everything else queues for operator review. - Learns passively from real tool-use, at zero LLM cost. Six template-based heuristic detectors turn observed behavior — repeated tool+input, error-then-fix, hot files, repeated commands, recurring errors, A→B sequences — into confidence-scored memories. The operator never has to remember to save anything, and the replay harness asserts the detection loop makes zero model calls.
- Fully local, no per-query cost, no data egress. Embeddings (
all-MiniLM-L6-v2) and the reranker (ms-marco-MiniLM-L-6-v2) are quantized ONNX run in-process; the optional reasoner is local Ollama on your own GPU. No cloud LLM sits in the retrieval path or the consolidation path — your codebase context never leaves the box. - Observable. A live SSE event stream and a six-tab web viz (graph / live / ops / replay / review / slots) expose what the system is doing: real-time observation events, operational panels (confidence distribution, decay, dream history, corpus health), dream review controls, and historical session playback.
The honest framing: this is a single-operator, self-hosted system. Advanced features ship behind flags and GATE reviews. What backs reliability is engineering rigor, not scale — a zero-LLM pinned-clock replay regression net, adversarial GATE reviews run against a copy of real data, idempotent locked consolidation passes, and fail-open/fail-silent behavior everywhere a hook or service could stall.
Capability map
| Layer | What it does |
|---|---|
| Retrieval | Hybrid search — Reciprocal Rank Fusion (k=60) over semantic (cosine) + keyword (FTS5/tsvector), optional ms-marco cross-encoder rerank, confidence-blended ranking. Fast hook-optimized recall path skips reranking. |
| Dreaming / consolidation | Deterministic-first nightly Librarian: duplicate collapse, durability-scaled decay, contradiction routing, supersession chains. Snapshot-first, audited, reversible. Feature-flagged, auto-apply off by default. |
| Auto-discovery | Observation ingestion → 6 zero-cost heuristic detectors → synthesizer → confidence scoring → semantic dedup → memory creation. Recurring-error classification and tiering. |
| Static surfacing | Per-prompt injection of relevant tools, skills, and project conventions from the operator's ~/.claude indexes, with a causal acceptance metric. |
| Optional reasoner | Local Ollama pair classifier (qwen3:8b), classify/extract only — never writes. Off or provider-down degrades byte-for-byte to deterministic-only behavior. |
| Storage backends | Dual: SQLite (better-sqlite3 + in-memory vector index) or PostgreSQL (pg + pgvector), selected by DATABASE_TYPE. Both implement the same backend-agnostic store interfaces. |
| Optional services | Neo4j (graph/entity traversal), Redis (ephemeral context), MinIO (S3 artifact storage) — each feature-flagged, gracefully degrades if absent. |
| Observability | SSE observation stream + six-tab viz (graph, live events, ops panels, session replay, dream review, slots). |
| Interfaces | 19 MCP tools (thin stdio HTTP clients) + Fastify REST API on port 3200. |
Two entry points, one backend
src/server.ts— Fastify REST API (port 3200). The real server: owns the database, embedding index, and all optional services.src/index.ts— MCP stdio server. A thin client that proxies tool calls to the REST API viaMEMORY_API_URL; it never touches the database directly.
Setup
git clone https://github.com/djy89/kopeng.git
cd kopeng
npm install
cp .env.example .env # then edit — see below
npm run build
First boot downloads the embedding model (~30 MB) into models/ and auto-creates data/ and logs/ — no seed step. Full walkthrough — service install, Claude Code / Codex CLI wiring, hooks, API keys, and troubleshooting — is in SETUP.md.
Environment (.env)
.env.example is the complete, commented server configuration reference (hook/client-side variables like KOPENG_API_URL are documented in SETUP.md); these are the ones you'll touch first:
PORT=3200
HOST=127.0.0.1
DATABASE_TYPE=sqlite
DATABASE_PATH=./data/memory.db
EMBEDDING_MODEL=Xenova/all-MiniLM-L6-v2
LOG_LEVEL=info
MEMORY_API_URL=http://localhost:3200
Before you change
HOST. KOPENG binds loopback by default and expects to stay there. Every auth gate is optional — with noADMIN_API_KEYset, memory create/update/archive, slots, context, and artifacts are all open, and with noOBSERVATION_API_KEYset, observation ingest is too. That's deliberate for a single-operator local install, but it means a wildcard bind on an untrusted network hands over full read and write access to your memory corpus. Since memories are recalled into a model's context on later prompts, a write there is a persistent prompt-injection channel.To reach it from another machine: set both keys, and put it behind a VPN or an authenticating reverse proxy. Setting the keys alone is not a substitute for network placement — see SECURITY.md.
Optional layers are off by default and gated by their own flags (each degrades gracefully if its backing service is unavailable). Set a flag to true to enable that layer:
# Auto-discovery
OBSERVATION_INGESTION_ENABLED=true
DISCOVERY_DETECTION_ENABLED=true
# Dreaming Librarian (consolidation) + optional local reasoner
DREAMING_ENABLED=false
DREAM_REASONER_ENABLED=false
# Optional services
NEO4J_ENABLED=false
REDIS_ENABLED=false
MINIO_ENABLED=false
For PostgreSQL, set DATABASE_TYPE=postgres and provide the pg/pgvector connection settings (see src/config/config.ts).
Running
npm start # Production REST API server (node dist/server.js)
npm run dev # REST server, watch mode (tsx watch src/server.ts)
npm run start:mcp # Production MCP stdio server (used by Claude Code, not run directly)
npm run dev:mcp # MCP server, watch mode
npm run viz # Observability viz proxy (serves viz/ + proxies the API/SSE)
REST API
Successful responses use the envelope { data: T, meta?: { ... } }; errors return { error, details? }. Input is Zod-validated; the API is rate-limited.
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/health |
Health + readiness probe |
| GET | /api/stats |
Counts, DB size, index status |
| POST | /api/memories |
Store memory (auto-embeds) |
| POST | /api/memories/batch |
Bulk store (max 100) |
| GET | /api/memories/:id |
Get by ID |
| GET | /api/memories/:id/related |
Semantically similar |
| PUT | /api/memories/:id |
Update (re-embeds if content changes) |
| PATCH | /api/memories/:id |
Archive/unarchive |
| POST | /api/memories/recall |
Fast semantic recall (hook-optimized, no rerank) |
| POST | /api/memories/search |
Hybrid search |
| GET | /api/memories |
List with filters |
| POST | /api/memories/:id/rollback |
Restore a memory from a snapshot revision |
| GET | /api/memories/:id/revisions |
List snapshot revisions |
| POST | /api/surface |
Static surfacing — relevant tools/skills/conventions |
| GET | /api/observations/stream |
Live SSE observation event feed |
| GET | /api/ops/* |
Read-only operational snapshots (8 endpoints) |
| POST | /api/dreams/trigger |
Manually trigger a consolidation pass |
| GET | /api/dreams/pending |
Pending dream review queue |
| POST | /api/dreams/:id/resolve |
Accept/reject dream entries |
| POST | /api/admin/backup |
Trigger SQLite backup |
| POST | /api/admin/reindex |
Rebuild FTS5 + embedding index |
| POST | /api/admin/promote |
Run the promotion pipeline |
Optional services add their own routes (/api/memories/traverse, /api/graph/*, /api/context*, /api/artifacts*) when enabled.
Search modes
hybrid(default) — reciprocal rank fusion of semantic + keywordsemantic— cosine similarity onlykeyword— FTS5/tsvector keyword only
Reranking
Search results are reranked by default using a cross-encoder (ms-marco-MiniLM-L-6-v2, local ONNX), lazy-loaded on first search (no startup cost). Rerank logits are sigmoid-normalized and confidence-blended for final ordering.
# Reranked search (default)
curl -X POST http://localhost:3200/api/memories/search \
-H "Content-Type: application/json" \
-d '{"query":"coding preferences","mode":"hybrid","rerank":true}'
# Disable reranking
curl -X POST http://localhost:3200/api/memories/search \
-H "Content-Type: application/json" \
-d '{"query":"coding preferences","rerank":false}'
# Control candidate pool size (default 20)
curl -X POST http://localhost:3200/api/memories/search \
-H "Content-Type: application/json" \
-d '{"query":"coding preferences","rerank":true,"rerank_candidates":30}'
Response includes rerank_score per result and meta.reranked: true when active.
Store a memory
curl -X POST http://localhost:3200/api/memories \
-H "Content-Type: application/json" \
-d '{"content":"...","type":"feedback","scope":"global","tags":["testing"]}'
Memory types: user, feedback, project, reference, discovery. Scopes: global, project:<name>, client:<name>.
MCP Tools
19 tools registered in src/index.ts, each a thin HTTP client over the REST API. Core retrieval/CRUD:
| Tool | Description |
|---|---|
store_memory |
Store new memory with auto-embedding |
search_memories |
Hybrid semantic + keyword search |
get_memory |
Get memory by ID |
update_memory |
Update memory (re-embeds if content changes) |
list_memories |
List/filter memories with pagination |
archive_memory |
Archive or unarchive a memory |
eval_retrieval |
Ad-hoc retrieval eval with precision/recall |
Plus context/artifact/graph tools (set_context, get_context, store_artifact, get_artifact, traverse_memory), discovery (trigger_discovery), and the dream review + operator-config surface (trigger_dream, list_pending_dreams, get_dream_diff, resolve_dream, get_operator_config, set_operator_config). The auto_accept_* flags exposed by the config tools ship OFF — flipping them is a deliberate operator decision.
Claude Code registration
Add to Claude Code user settings (~/.claude.json or the settings UI):
{
"mcpServers": {
"kopeng": {
"command": "node",
"args": ["/absolute/path/to/kopeng/dist/index.js"],
"env": {
"MEMORY_API_URL": "http://localhost:3200"
}
}
}
}
Observation + recall hooks
The passive-learning and proactive-surfacing layers run as Claude Code / Codex CLI hooks (scripts/hooks/). The observe hook appends tool-use events to a local JSONL buffer and batch-flushes to the server; the recall hooks inject relevant memory, tools, skills, and conventions before each prompt. See SETUP.md and docs/codex-setup.md for wiring details.
Migration
# Import existing file-based memories (dry-run first)
npx tsx scripts/migrate-from-files.ts --dry-run
npm run migrate
# SQLite → PostgreSQL
npm run migrate:postgres
npm run migrate:verify
Running as a service
KOPENG is a plain Node process — run it under any process manager. Both recipes below (and more detail) are in SETUP.md.
Linux (systemd):
# /etc/systemd/system/kopeng.service
[Unit]
Description=KOPENG memory server
After=network.target
[Service]
User=youruser
WorkingDirectory=/opt/kopeng
ExecStart=/usr/bin/node /opt/kopeng/dist/server.js
Environment=NODE_ENV=production
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now kopeng
WorkingDirectory should be the repo root: the app finds .env next to its install automatically, but relative path values inside it (./data/memory.db, ./models) resolve against the working directory. nvm users: point ExecStart at the absolute node path from which node.
Windows (NSSM):
nssm install kopeng "C:\Program Files\nodejs\node.exe" "C:\path\to\kopeng\dist\server.js"
nssm set kopeng AppDirectory "C:\path\to\kopeng"
nssm set kopeng AppEnvironmentExtra "PORT=3200" "NODE_ENV=production"
nssm set kopeng AppStdout "C:\path\to\kopeng\logs\service.log"
nssm set kopeng AppStderr "C:\path\to\kopeng\logs\error.log"
nssm set kopeng AppRotateFiles 1
nssm set kopeng AppRotateBytes 10485760
nssm start kopeng
Network Access
The server binds 127.0.0.1:3200 by default. To let other machines reach it (e.g. peers on a private VPN such as WireGuard or Tailscale) set HOST=0.0.0.0 — but set ADMIN_API_KEY and OBSERVATION_API_KEY first, and read the warning under Environment: with no keys configured every write endpoint is open. On Windows, also allow the port through the firewall (run as admin; scope -InterfaceAlias to your VPN interface if you have one):
New-NetFirewallRule -DisplayName "KOPENG API" `
-Direction Inbound -Protocol TCP -LocalPort 3200 `
-Action Allow -Profile Any
Eval Harness
Lightweight retrieval evaluation to measure search quality.
# Generate eval dataset from existing memories (requires ANTHROPIC_API_KEY)
# ⚠ This command SENDS SELECTED MEMORY CONTENT to the Anthropic API to draft
# eval queries — the only shipped command that egresses corpus data. The
# retrieval/consolidation runtime itself never does.
ANTHROPIC_API_KEY=sk-... npm run eval:seed
# Full eval (hybrid + reranking, default)
npm run eval
# Compare baseline vs reranked
npm run eval:baseline # hybrid without reranking
npm run eval:reranked # hybrid with reranking
# Custom settings
npx tsx scripts/run-eval.ts --mode semantic --rerank false --k 10
Metrics: P@K, R@K, MRR, NDCG@K. Results saved to data/eval_results/[timestamp].json. The eval_retrieval MCP tool runs ad-hoc single-query evals from within Claude Code.
Dreaming harnesses
The consolidation layer has its own zero-LLM regression and effectiveness harnesses (no server required):
npm run dream:replay # Zero-LLM regression net: real pass over a synthetic gold corpus,
# pinned clock, asserts per-class precision/recall + llm_calls == 0
npm run dream:effectiveness # Before/after corpus-health + retrieval over a synthetic corpus
Reasoner-classifier evals (require local Ollama; not part of the test suite):
npm run eval:reasoner # Live classify/extract eval, per-class precision/recall
npm run eval:adversarial # GATE-2 hostile pairs
npm run eval:nli # Local ONNX NLI baseline
Tests
npm test # Vitest, all tests (in-memory SQLite — no server needed)
npm run test:watch
npm run test:coverage
Unit tests run against in-memory SQLite; integration tests build an in-process Fastify app (app.inject) — no running server needed. Backend coverage is asymmetric: SQLite is exercised for real, PostgreSQL has adapter-level coverage against a mocked pool (see CONTRIBUTING.md).
Design docs
The dreaming layer's design brief lives at docs/i-have-a-dream.md, and its reasoner provider setup at docs/dreaming/reasoner-setup.md. The behavioral guarantees those docs describe are enforced by the shipped test suite (replay harness, adversarial GATE 2 regression net, auth/contract tests). The REST API contract never changes across backend swaps.
License
KOPENG is source-available under the Business Source License 1.1: you can read, run, modify, and self-host it freely (including production use), but you may not offer it to third parties as a commercial hosted memory service. On 2030-07-05 the license automatically converts to Apache 2.0.
Contact
Built by djy89 — a single-maintainer project.
- Bugs, questions, design discussion: open a GitHub issue. Public discussion is preferred; it helps the next person with the same question.
- Anything else:
hello@kopeng.net - Security vulnerabilities: neither of the above — use GitHub's private vulnerability reporting, per SECURITY.md. Please don't put exploitable details in a public issue or in email.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.