Skip to content
AI News HubLIVE
In-site rewrite5 min read

AegisDB – self-hosted memory for AI agents, in one C binary

Summary

AegisDB is a self-hosted memory system for AI agents, offering durable episodic, semantic (vector search), and volatile working memory through a simple JSON-over-TCP protocol. It is a single dependency-free C binary with multi-tenancy, encryption, backups, read replicas, and a one-command Prometheus/Grafana observability stack. Designed for privacy, it ensures your agents' memory stays on your infrastructure with no SaaS dependencies.

SourceHacker News AIAuthor: d4n-larsson
AegisDB – self-hosted memory for AI agents, in one C binary
Report an error

The correction channel is not available yet. You can copy the article reference below for later.

Correction instructions
Read article

Notifications You must be signed in to change notification settings

Fork 0

Star 0

BranchesTags

Open more actions menu

Folders and files

NameName

Last commit message

Last commit date

Latest commit

History

260 Commits

260 Commits

.claude

.claude

.github/workflows

.github/workflows

bench

bench

docs

docs

include/aegisdb

include/aegisdb

integrations

integrations

scripts

scripts

site

site

src

src

tests

tests

third_party

third_party

.dockerignore

.dockerignore

.env.example

.env.example

.gitignore

.gitignore

CLAUDE.md

CLAUDE.md

CMakeLists.txt

CMakeLists.txt

Dockerfile

Dockerfile

LAUNCH.md

LAUNCH.md

LICENSE

LICENSE

Makefile

Makefile

README.md

README.md

docker-compose.yml

docker-compose.yml

Repository files navigation

Self-hosted memory for your AI agents. One small C binary — multi-tenant, encrypted, with backups, read replicas, and a one-command Prometheus + Grafana stack. Your agents' memory stays on your box; nothing ships to a SaaS.

AI agents forget everything between sessions. AegisDB gives them durable, searchable long-term memory — episodic history, semantic facts with vector search, and volatile working memory — behind a dead-simple JSON-over-TCP protocol, with a first-class Claude Code integration. It's a single dependency-free binary you run yourself: your data, your box, no third party in the loop.

Quickstart

Run the server — no clone, no toolchain (prebuilt multi-arch image on GHCR):

docker run -d --name aegisdb -p 9470:9470 -v aegis-data:/data \ ghcr.io/d4n-larsson/aegisdb:latest

Talk to it — the same binary is also the client:

docker exec aegisdb aegisdb client ping docker exec aegisdb aegisdb client put --type semantic --tags user "prefers dark mode" docker exec aegisdb aegisdb client search --tags user --top-k 5

Want the whole observability stack (server + Prometheus + a pre-built Grafana dashboard) in one command? Clone this repo and:

docker compose --profile monitoring up # dashboard on http://127.0.0.1:3000

Giving Claude Code a persistent memory is a one-liner (with a server running): uvx --from aegisdb-mcp aegisdb-init — see Use as Claude Code memory.

Why AegisDB

Self-hosted & private. Your agents' memory never leaves your infrastructure — no SaaS, no per-token billing, no data-sharing. Encrypt it at rest with one flag.

One binary, no dependencies. Written in C; the only vendored code is cJSON and the crypto. No JVM, no Python runtime, no external database to babysit.

Built for teams. Multi-tenant auth (per-namespace, scoped tokens), per-tenant quotas + rate limits, online backups, read replicas, and turnkey Prometheus/Grafana observability.

Claude Code native. Ships an MCP server + hooks so Claude remembers across sessions — installable with a single command.

Production-minded. Corruption-resilient append-only log, crash recovery, a documented security review, and CI that runs ASan/UBSan/TSan plus continuous fuzzing.

Features

Durable episodic memory — append-only log with magic + CRC32 framing, corruption-resilient recovery, and legacy-log migration

Semantic facts — updateable records (latest version wins)

Working memory — volatile per-session ring buffer with TTL and promotion

Retrieval — lookup by ID, time-range search, tag search (all/any), semantic (embedding) search ranked by cosine similarity weighted by importance × confidence; count and consolidate (dedup) over the same filters

Semantic scale — exact cosine while small; past --ann-threshold an HNSW graph for sublinear approximate top-K, built off the write path and sharded so the build parallelizes (--ann-shard-target), optionally int8-quantized

Relationships — directed edges between records, graph traversal, and agent-namespace isolation

Multi-tenant auth — optional bearer tokens (constant-time check; ping exempt), each bound to a namespace + scope (ro/rw/admin) so one server safely isolates many tenants

Per-tenant limits — optional storage quotas (records/bytes) and a request rate limit per namespace, so one team member's runaway agent can't fill the disk or monopolize the shared server

Encryption at rest — optional XChaCha20-Poly1305 (vendored, no crypto dependency) over the log + checkpoints; opt-in via --encryption-key-file, with an offline migrator and encrypted backups/replicas

Observability — stats op plus a drop-in Prometheus exporter + Grafana dashboard (docker compose --profile monitoring up)

Operations — online snapshot/restore backups and read replicas

Concurrency — sharded poll() event-loop threads (--io-threads); selectable fsync durability (sync / batch / interval)

Requirements

Linux (primary target) with GCC 11+ or Clang 14+

One of: CMake 3.20+ or GNU Make

Python 3.8+ (optional, for the example client below)

Build

With CMake (canonical)

cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build ctest --test-dir build --output-on-failure # runs the unit test suite

With Make (no CMake required)

make # builds build/aegisdb make test # builds and runs the C unit tests make integration # wire-protocol contract tests (launches the server) make check # unit + integration make clean

The server binary is produced at build/aegisdb.

With Docker

Prebuilt multi-arch images (linux/amd64, linux/arm64) are published to GitHub Container Registry on every push to main and every release tag — no clone or toolchain needed:

docker run -p 9470:9470 -v aegis-data:/data ghcr.io/d4n-larsson/aegisdb:latest

or pin a release: ghcr.io/d4n-larsson/aegisdb:0.1.0

To build it yourself instead, a multi-stage Dockerfile (Debian-slim) compiles the server and ships a minimal runtime image. Data persists in a named volume at /data.

Build and run with Docker Compose

docker compose up --build # serves on localhost:9470

Or build and run the image directly

docker build -t aegisdb . docker run -p 127.0.0.1:9470:9470 -v aegis-data:/data aegisdb

Compose is configured by an optional .env file — copy the template and edit:

cp .env.example .env # then tweak port, durability, tenant limits, … docker compose up --build

Every setting has a default, so .env is optional. It exposes the common flags as named vars (AEGIS_PORT, AEGIS_EMBEDDING_DIM, AEGIS_DURABILITY, AEGIS_TENANT_MAX_RECORDS, …) plus AEGIS_EXTRA_ARGS for anything else (--auth-token-file, --io-threads, ANN tuning, …). See .env.example for the full list.

To skip building, point docker-compose.yml at the published image: replace build: . with image: ghcr.io/d4n-larsson/aegisdb:latest.

The image ships a HEALTHCHECK that uses the binary's built-in --health-check probe (no extra tooling in the image), so docker ps and Compose depends_on: condition: service_healthy reflect real server liveness.

The container runs as an unprivileged user. The server listens on 0.0.0.0:9470 inside the container, but Compose publishes that port on the host's loopback (127.0.0.1) only by default — because the wire protocol is unauthenticated and plaintext out of the box, it must not be reachable off-box until you secure it. To expose it deliberately, set AEGIS_BIND=0.0.0.0 (or a specific host IP) in .env, and first enable authentication: mount a token file into /data and add --auth-token-file /data/tokens.txt (to AEGIS_EXTRA_ARGS under Compose; see Authentication). Even with auth, tokens travel in plaintext, so terminate TLS at a trusted proxy for any non-loopback exposure. Override other flags by appending them to the run command, e.g. docker run aegisdb --embedding-dim 1024, or (with Compose) via .env.

Run

./build/aegisdb --data-dir ./data --port 9470

Expected startup output:

2026-06-28 12:00:00.000 INFO [aegisdb] AegisDB 0.1.0 starting (log level: info) 2026-06-28 12:00:00.000 WARN [aegisdb] no auth tokens configured; ... 2026-06-28 12:00:00.000 INFO [aegisdb] recovery complete: N records loaded 2026-06-28 12:00:00.000 INFO [aegisdb] listening on 0.0.0.0:9470 2026-06-28 12:00:00.000 INFO [aegisdb] data directory: ./data

Logs go to stderr as [aegisdb] . Control the verbosity with --log-level error|warn|info|debug (default info) or the AEGISDB_LOG_LEVEL environment variable — the flag takes precedence. At debug, the server logs every accepted connection and dispatched operation.

The WARN line appears only when the server is started without --auth-token/--auth-token-file (see Authentication).

Talk to it

The same binary is also a client — no nc, no hand-written JSON:

aegisdb client ping aegisdb client put --type semantic --tags user "prefers dark mode" aegisdb client get 1 aegisdb client search --tags user --top-k 5 aegisdb client stats

Host, port, and token default to $AEGIS_HOST / $AEGIS_PORT / $AEGIS_TOKEN (127.0.0.1 / 9470 / none) or --host/--port/--token. The exit code is 0 on an ok response, so it scripts cleanly. Inside Docker: docker exec aegisdb aegisdb client stats.

To create a tenant token, gen-token prints a ready token-file line (hashed) and the one-time plaintext token:

$ aegisdb gen-token --namespace acme --scope rw sha256$… acme rw # paste into your --auth-token-file token: 9f3c… # give to the client (AEGIS_TOKEN); not recoverable

Configuration flags

Flag Default Description

--data-dir ./data Persistence directory

--port 9470 TCP listen port

--phase 4 Highest enabled feature phase (gates operations)

--io-threads 2× CPUs (8–64) poll() event-loop threads for dispatch parallelism (does not cap concurrent connections). Alias: --workers

--max-payload 1048576 Max data size (1 MiB)

--embedding-dim 384 Expected embedding vector length

--ann-threshold 10000 Live vectors before semantic search switches from exact scan to the HNSW graph

--ann-ef-search HNSW default HNSW query beam width (recall/latency knob)

--ann-shard-target 25000 Target vectors per HNSW shard; the graph splits into ~count/n shards (capped by CPUs) so the build parallelizes

--ann-quantize off Store HNSW vectors as int8 (~4× less memory, small recall cost)

--durability interval sync (fsync per write), batch (per --fsync-batch records), or interval (per --fsync-interval-ms)

--fsync-batch 1000 Records between fsync calls in batch mode

--fsync-interval-ms 1000 Flush cadence in interval mode (floored at the ~1s maintenance tick)

--checkpoint-sec 60 Index checkpoint cadence so recovery replays only the tail; 0 disables

--compact-sec 300 Log-compaction check cadence; compacts only when enough of the log is dead; 0 disables

--tenant-max-records 0 Per-namespace live-record cap (0 = unlimited); enforced only when auth is enabled

--tenant-max-bytes 0 Per-namespace live-byte cap (0 = unlimited)

--tenant-rate-qps 0 Per-namespace request rate limit in req/s, burst = 1s (0 = unlimited)

--max-index-bytes 0 Soft cap on in-RAM index size; inserts return MEMORY_LIMIT past it so a growing dataset backpressures instead of getting OOM-killed (accepts K/M/G; 0 = unlimited). Watch stats.memory.

--replication-port — Serve the read-replica log stream on this port (primary; requires --replication-token)

--replication-token — Token to subscribe to / follow the replication stream

--replicate-from — Follow this primary's replication port as a read-only replica (implies --read-only)

--read-only off Refuse client writes (READ_ONLY)

--working-capacity 256 Working-memory ring buffer size

--restore — One-shot: install the snapshot at into an empty --data-dir, then exit

--log-level info error, warn, info, or debug (also $AEGISDB_LOG_LEVEL)

--auth-token — Accept this global admin token (repeatable)

--auth-token-file — Accept tokens, one per line: [namespace] [ro|rw|admin]; a token may be sha256$ (hashed at rest)

--hash-token

Print the token's sha256$ form and exit (paste into the token file)

--encryption-key-file — Encrypt the log + checkpoints at rest with the 32-byte key (64 hex chars) in (Encryption at rest)

--encrypt-migrate

Rewrite -

[truncated for AI cost control]

Key points and analysis

Article intelligence

EngineersAdvanced

Key points

  • Single C binary with zero external dependencies, deployable via Docker
  • Provides episodic, semantic (with vector search), and working memory types
  • Multi-tenant authentication, per-tenant quotas, and rate limiting
  • Built-in Prometheus/Grafana observability stack via Docker Compose

Highlights and analysis are generated automatically and may contain errors. Check the original source.