rembric
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Self-hosted memory, sessions, and dashboard for AI coding agents
Self-hosted memory, sessions, and dashboard for AI coding agents
One Docker image, one process, one SQLite file. Multi-client by construction, reversible by design.
Architecture · Dashboard · Quickstart · Supported agents · Configuration · Project status · Contributing
rembric /ˈrem.brɪk/ — coined, from remember + fabric: the woven memory and lifecycle layer beneath your agents. One brain, one dashboard, one audit trail — shared across every MCP-capable tool: Claude Code, Codex CLI, Hermes Agent, opencode, Cursor, and beyond. The MCP memory surface is the core; sessions, judgments, consolidation, and the operator dashboard come along in the same single Node process.
Supported agents
Rembric works with any agent that speaks MCP or HTTP. First-class plugins handle session lifecycle + per-project path-scoping automatically; everything else gets the same memory tools via a plain MCP URL.
![]() Claude Code native plugin · 4 hooks · MCP |
![]() opencode native plugin · MCP |
![]() Codex CLI native plugin · 4 hooks · MCP |
![]() Hermes Agent native provider · MCP |
![]() Cursor MCP server |
Windsurf MCP server |
![]() Claude Desktop MCP server |
![]() Cline MCP server |
![]() Goose MCP server |
![]() Kilo Code MCP server |
![]() Roo Code MCP server |
![]() Gemini CLI MCP server |
Works with any agent that speaks MCP. One server, memories shared across all of them.
Architecture
┌─────────────────────────────────────────────────┐
│ Agents (MCP clients) │
│ Claude Code · Codex CLI · Cursor · … │
└────────────────────────┬────────────────────────┘
│
│ HTTP(S) + Bearer token
│ URL path: /mcp/<slug> (or /mcp + project.use)
▼
┌───────────────────────────────────────────────────────────────────────┐
│ rembric (single Node process) │
│ │
│ ┌────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ /mcp /mcp/<slug> │ │ /dashboard │ │
│ │ Streamable HTTP transport │ │ SSR HTML + HTMX │ │
│ │ + initialize.instructions │ │ │ │
│ │ memory.{save,search,…} │ │ /memories /sessions │ │
│ │ memory.session_* │ │ /prompts /judgments │ │
│ │ memory.*_prompt(s) │ │ /consolidation /projects │ │
│ │ memory.judge / compare │ │ /tokens /maintenance │ │
│ │ project.{use,list,current}│ │ │ │
│ └─────────────┬──────────────┘ └─────────────┬─────────────────┘ │
│ ▼ ▼ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Service layer │ │
│ │ MemoryService · PromptsService · RelationsService │ │
│ │ ProjectsService · TokensService · AgentSessionsService │ │
│ │ SessionRouter │ │
│ └───────────────────────────────┬───────────────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ SQLite (Drizzle, append-only + tombstones) │ │
│ │ memory · projects · tokens · sessions · prompts │ │
│ │ memory_relations · consolidation_{runs,ops} │ │
│ │ + memory_fts · prompts_fts (FTS5) + memory_vec (sqlite-vec)│ │
│ └───────────────────────────────▲───────────────────────────────┘ │
│ ┌───────────────────────────────┴───────────────────────────────┐ │
│ │ Background workers │ │
│ │ EmbeddingWorker (every 30s) · ConsolidationScheduler │ │
│ │ decay (deterministic) + orphan promotion (LLM judge) │ │
│ └───────────────────────────────┬───────────────────────────────┘ │
└───────────────────────────────────┼───────────────────────────────────┘
│ OpenAI-compatible HTTP
▼
┌────────────────────────────────────────┐
│ LLM endpoint │
│ Ollama · OpenAI · LM Studio · … │
└────────────────────────────────────────┘
Single Node process, packaged as a multi-arch Docker image (linux/amd64, linux/arm64); the pnpm dlx rembric path stays available as a power-user fallback during the dual-publish window.
Four load-bearing invariants:
- Append-only: rows are never deleted;
contentnever updated. Lifecycle isstatusflips +replaceslinks. Every consolidation op is reversible. - Project scoping by construction: every memory is
globalor attached to oneproject_id. Consolidation and relations never cross scope. - Convergent topics via
topic_key: onmemory.save, the previously-active row in the same(scope, project_id, topic_key)is auto-superseded atomically. - Fresh-context judgment: candidate conflicts surface at save time (
candidates[]); the agent that produced the conflict judges it. Aged pendings re-surface inmemory.contextuntil an agent closes them. The deterministic sweep (no LLM, no cron — runs on session start) only handles decay + deadline orphaning.
See docs/relations.md for the relation taxonomy.
Dashboard
Self-hosted operator surface for every memory, session, prompt, judgment, and consolidation op. SSR HTML + HTMX, brutalist on purpose, no JS framework, no telemetry. Auth is one admin token — no onboarding flow.
Sign-in · one admin token, scope ✱.
Overview · counters, pending judgments queue, recent agent sessions.
More surfaces — overview health · memories · prompts · sessions · judgments · consolidation · projects · tokens · maintenance
Overview · health — last run, ops applied, orphan pendings, 7-day activity, system info.
Memories · append-only; filter by scope, status, type, FTS5 search.
Memory detail · status, scope, project, type, full content body.
Judgments · audit trail of every relation verdict — compatible, supersedes, not_conflict.
Consolidation run · op-by-op view with per-op undo and full-run revert. Every action journaled.
Projects · slug-keyed, archivable. Each project is an isolated scope.
Tokens · scope-bound (* or project:<slug>), revocable, expirable.
Maintenance · DB breakdown + admin-only physical purges for empty sessions and disconnected archived memories.
Quickstart (Docker)
Docker is the canonical install path. The image bundles Node 22 and the native modules (better-sqlite3, sqlite-vec) pre-built for linux/amd64 and linux/arm64, so the only requirement on your host is Docker.
mkdir rembric && cd rembric
curl -fsSLO https://raw.githubusercontent.com/susomejias/rembric/main/docker-compose.yml
curl -fsSL https://raw.githubusercontent.com/susomejias/rembric/main/.env.example -o .env
# edit .env: set REMBRIC_ADMIN_TOKEN (e.g. `openssl rand -hex 32`)
# optionally configure embeddings (OPENAI_BASE_URL / OPENAI_API_KEY)
docker compose up -d
docker compose logs -f rembric
MCP at http://<host>:8787/mcp, dashboard at http://<host>:8787/dashboard (replace <host> with 127.0.0.1 if running on the same host as your agent, or the LAN/Tailscale hostname of the box hosting Rembric otherwise).
Running on a remote host (LXC, NAS, server) — the canonical case
The compose file publishes port 8787 on all interfaces of the host so your agent on another machine can reach it. Point the plugin at http://<host-ip>:8787 (LAN) or http://rembric.tailnet:8787 (Tailscale). Don't expose port 8787 directly to the public internet — front it with Tailscale, WireGuard, or your reverse proxy of choice. The bearer token is the real security boundary; every endpoint requires Authorization: Bearer <token>.
Running on the same host as your agent — loopback override
If you want to restrict the published port to loopback (stricter posture, same-host dev only), drop a docker-compose.override.yml next to the canonical compose:
services:
rembric:
ports: !override
- '127.0.0.1:${REMBRIC_PORT:-8787}:8787'
Compose auto-merges the override on every up. Point your agent at http://127.0.0.1:8787. See docs/docker.md for the full topology guide.
Upgrading
Docker manages versions for you. With REMBRIC_VERSION unset in .env, the compose file pulls :latest:
docker compose pull
docker compose up -d
Portainer / Arcane detect the new digest automatically and offer a "Recreate container" button — one click. For reproducible deploys, pin a specific version in .env:
REMBRIC_VERSION=0.13.0
Rolling back
Bump REMBRIC_VERSION to a previous tag in .env and re-run docker compose up -d. The bind-mounted ./data/ directory is untouched, so your memory stays intact across version flips.
See docs/docker.md for the full operator guide (private GHCR auth, named-volume vs bind-mount, host-on-Linux host.docker.internal notes, troubleshooting).
Backups
# while the container is running (WAL-safe online backup):
docker compose exec rembric sqlite3 /data/data.db ".backup /data/backup-$(date +%Y%m%d).db"
mv ./data/backup-*.db ./backups/
# or stop + copy for a cold backup:
docker compose down
cp ./data/data.db ./backups/data-$(date +%Y%m%d).db
docker compose up -d
Do not bind-mount ./data/ onto NFS / SMB / network filesystems — SQLite's POSIX locking guarantees don't hold there, and you'll eventually corrupt the DB.
Operating Rembric
Day-to-day operator work lives in the dashboard at http://127.0.0.1:8787/dashboard (port 8788 in the dev stack). Mint and revoke API tokens at /dashboard/tokens, create and archive projects at /dashboard/projects, soft-delete agent sessions at /dashboard/sessions, browse and soft-delete curated user prompts at /dashboard/prompts (FTS5 search over content + tags; refined predecessors show a REFINED badge), trigger consolidation at /dashboard/consolidation, and run the operator-only purges from /dashboard/maintenance. Programmatic agents talk to the same data through the MCP project.* / memory.* tools or, for admin-only operations, through the HTTP endpoints under /admin/* (admin bearer token required — see docs/agents.md).
Dashboard maintenance (manual purges)
The dashboard exposes /dashboard/maintenance for three irreversible, operator-triggered physical purges. All are gated to dashboard sessions whose underlying token has scope * (admin):
- Purge empty sessions — removes
ended/abandonedsession rows that have no summary, no manual title, no referencing memories / non-deleted prompts / confirmations, are not operator-soft-deleted, and ended over 1 hour ago. Soft-deleted prompts no longer block purge. - Purge disconnected archived memories — removes
archivedmemory rows whose ids are referenced by NO other row in the graph (memory.replaces,consolidation_ops.affected_ids/created_id,memory_relations.{source,target}_id,confirmations.memory_id). The matchingmemory_vecandmemory_ftsshadow rows are dropped in the same transaction. - Purge deleted prompts — removes
promptsrows whosedeleted_at IS NOT NULL. Covers both operator soft-deletes (from/dashboard/prompts) and refine supersedes (frommemory.save_prompt({ replaces })). The matchingprompts_ftsshadow row is dropped in the same transaction.
Each click shows a count and a confirmation modal. The deletion is journaled in consolidation_ops (op_type = 'session_purge', 'archived_memory_purge', or 'prompt_purge') so the operator can audit what was removed even after the rows are gone. Consolidation undo on operations whose rows have been purged returns a structured error — the dashboard surfaces it inline naming the missing ids.
To reclaim file-level disk after a large purge, run VACUUM against the SQLite file. The maintenance page surfaces the freelist size so you know how much would be reclaimed.
Configuration
All config via environment variables. With Docker, these live in .env and are loaded automatically by docker compose up. Required: REMBRIC_ADMIN_TOKEN (used to log into the dashboard and mint other tokens).
Server
| Variable | Default | Description |
|---|---|---|
REMBRIC_HOST |
127.0.0.1 (0.0.0.0 in Docker) |
Bind address. Pinned to 0.0.0.0 inside the container so the published port works; never override in Docker. |
REMBRIC_PORT |
8787 |
Bind port. |
REMBRIC_DATA_DIR |
~/.rembric (/data in Docker) |
Where the SQLite file lives. Pinned to /data inside the container; bind-mount ./data:/data in compose. |
LOG_LEVEL |
info |
debug / info / warn / error. |
Embeddings (optional)
The server performs no LLM reasoning — there is no chat model and no API key requirement. Embeddings are the only optional external dependency: they power semantic candidate detection in memory.save. Any OpenAI-compatible /v1 endpoint works (OpenAI, Ollama, LM Studio, vLLM, …).
| Variable | Default | Description |
|---|---|---|
OPENAI_BASE_URL |
http://localhost:11434/v1 |
Endpoint URL including /v1. |
OPENAI_API_KEY |
(empty) | Required for OpenAI proper; Ollama ignores it. |
OPENAI_EMBEDDING_MODEL |
nomic-embed-text |
Embedding model (768 dims). |
EMBEDDING_ENABLED |
true |
If false, candidates fall back to FTS5 only. |
Consolidation sweep
Deterministic — decay + deadline orphaning, no LLM, no cron. Runs on session start (throttled to one run per scope per 6h) and on demand via the dashboard or POST /admin/consolidation/run. Pre-0.21 vars (CONSOLIDATION_ENABLED / CONSOLIDATION_CRON / CONSOLIDATION_BATCH_SIZE / OPENAI_MODEL / LLM_PROVIDER) are ignored with a boot warning.
| Variable | Default | Description |
|---|---|---|
JUDGMENT_ORPHAN_AFTER_MS |
86400000 |
Age (ms) past which pending judgments surface in memory.context for the agent to close. 24h. |
JUDGMENT_ORPHAN_DEADLINE_MS |
1209600000 |
Age (ms) past which unjudged pendings are orphaned by the sweep (journaled, undoable). 14 days. |
Rate limiting
Per-token token-bucket limiter on /mcp requests. Disabled by default — single-user localhost deployments don't need it. Enable when exposing the server to multiple agents that might burst-call.
| Variable | Default | Description |
|---|---|---|
RATE_LIMIT_ENABLED |
false |
Master toggle. true activates the limiter; misbehaving tokens get 429 rate_limited with Retry-After. |
RATE_LIMIT_RPS |
10 |
Refill rate per token, in requests per second. |
RATE_LIMIT_BURST |
30 |
Burst capacity per token. The first N requests after a quiet period are free; beyond that, RPS applies. |
Sessions
| Variable | Default | Description |
|---|---|---|
SESSION_ABANDON_AFTER_MS |
86400000 |
At server startup, sessions with status='active' whose started_at is older than this are flipped to abandoned. Default 24h; floor 1min, ceiling 30 days. |
Candidate detection (save-time judgment)
Controls how memory.save surfaces conflict candidates to the agent for fresh-context judgment.
| Variable | Default | Description |
|---|---|---|
CANDIDATES_PER_SAVE_MAX |
5 |
Max number of similar memories surfaced per save. 0 disables surfacing (pending rows are still inserted and re-surface via memory.context). |
CANDIDATE_VEC_THRESHOLD |
0.85 |
Cosine-similarity floor on the embedding match. Range 0..1. Lower = more candidates, more noise. |
CANDIDATE_FTS_THRESHOLD |
0.4 |
BM25-derived score floor on the FTS5 match. Range 0..1. |
Development
Hacking on Rembric itself
pnpm install
pnpm run dev # tsc --watch
pnpm test # full vitest suite + Hermes Python tests
pnpm run typecheck # tsc --noEmit
pnpm run lint
For a clean Docker build from source:
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build
More docs
- docs/docker.md — Docker operator guide (topologies, GHCR auth, upgrade/rollback, troubleshooting).
- docs/agents.md — per-client MCP config (Codex, Cursor, Windsurf, VS Code, Gemini, …).
- docs/backup.md — backup strategies and restore recipes for the SQLite data file.
- docs/troubleshooting.md — common errors and recovery.
Project status
Rembric is open-source under the MIT License — as-is, no warranty. The maintainers do not accept responsibility for operator data loss, deployment downtime, or any other operational consequence of running the software.
- Security: vulnerability reports go through SECURITY.md. Preferred channel is GitHub Security Advisories.
- Backups: the entire server state lives in one SQLite file. Operators are responsible for backing it up; see docs/backup.md for
sqlite3 .backupcron, manual snapshots, and litestream. - Versioning: SemVer, driven by release-please. Pre-1.0 means the wire and HTTP contracts may shift across minors; check release notes before upgrading.
Contributing
See CONTRIBUTING.md. Commits follow Conventional Commits; pre-commit lints and typechecks; pre-push runs the full test suite.
License
MIT — see LICENSE.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found










