Most "second brain" tools are SaaS-only. You hand them your notes, your half-formed ideas, your meeting fragments, and you trust them to keep it safe, available, and not training a model on the side. Eigen Mesh is different in a small but important way: the same codebase that runs the managed service is also the codebase you can run yourself. Apache 2.0, no feature flags, no "enterprise self-host tier."
This is a quick orientation for self-hosters — what the stack actually is, what you need to bring, and where to look when you want to go deeper. It's not a line-by-line runbook; the canonical runbook lives in the project repo and the operator docs. Think of this as the map.
What you're running
Two containers. That's the whole production stack.
| Service | Container | Role |
|---|---|---|
app |
eigen-app |
SvelteKit app with @sveltejs/adapter-node on port 3000 |
db |
eigen-db |
PostgreSQL 16 with pgvector + Apache AGE on port 5432 |
Both are defined in a single docker-compose.yaml and build from source in the eigen repository. There is no separate worker process, no Redis, no S3, no message queue you have to operate. Postgres does the heavy lifting for relational data, vector embeddings, and the knowledge graph — all in one instance.
That's a deliberate choice. We didn't want self-hosting to mean "first, stand up a six-service orchestration." If you have Docker and a Postgres that can load two extensions, you have an Eigen Mesh.
What you bring
The app needs an LLM endpoint for enrichment and retrieval. It speaks the OpenAI-compatible /api/v1/chat/completions and /api/v1/embeddings shape, so anything that conforms works — a hosted gateway, a local inference server, a self-hosted model behind a shim. You bring the keys; Eigen Mesh doesn't ship a model.
Two ways to wire that up:
- Platform credits — point at the default wallet-backed gateway and let users spend platform credits.
- BYOK — let users paste their own keys in Settings → LLM → BYOK. Good for self-hosters who want each tenant to pay their own inference bill.
Everything else — BETTER_AUTH_SECRET, TENANT_MASTER_KEY, AGE_GRAPH_NAME, ORIGIN — is either generated by the install script or set in .env. The install script exists because hand-rolling secrets is how people end up with changeme in production.
The five-minute version
Conceptually, the path is:
- Clone the repo.
- Run the install script with your origin and billing mode.
- Edit
.envto add LLM credentials (and PayPal if you're using platform credits). docker compose up -d --build.
The app entrypoint applies database migrations and Row Level Security policies on every container start. There is no manual npm install on the host, no separate migration step you can forget, no "did you run the RLS script?" Slack message at 2am. If the container starts, the schema is current.
Exact CLI flags, env var tables, and the bare-VPS runbook are in the eigen README and the operator docs. I'm intentionally not reproducing them here — copy-pasting flags that can drift is worse than pointing at the source of truth.
What you get that the managed users get
This is the part that surprises people. Same product. Same UI. Same MCP endpoint. Same retrieval pipeline, same consolidation, same graph. The managed plan is not a different SKU; it's the same SvelteKit app on someone else's Docker host with someone else's Postgres.
Concretely, when you self-host you get:
- The full browser UI — capture, memory graph, timeline, notes, chat, activity, settings, API keys.
- The MCP HTTP endpoint at
/api/mcpwith Bearer API key auth and the four thought tools (capture_thought,retrieve_thoughts,edit_thought,delete_thought). - The three-tier memory pipeline: hot persist → background enrich → nightly consolidation.
- Hybrid retrieval — pgvector ANN, Postgres FTS, precomputed graph artifacts, and an LLM listwise rerank.
- Row Level Security on all user data, scoped per
user_id.
What you don't get is someone else worrying about your TLS cert at 3am. That's the trade.
Where it fits in the LocalLLaMA stack
If you're already running local models — Ollama, vLLM, llama.cpp behind a shim — Eigen Mesh slots in cleanly. The OpenAI-compatible endpoint is the only LLM surface it needs. Point LLM_BASE_URL at your local server, set LLM_API_KEY to whatever your shim expects (even a dummy), and you have a fully self-hosted second brain with no outbound calls.
Embeddings stay in your Postgres. They are never returned to MCP clients, never sent to LLM prompts, never shipped to a third party. The retrieval pipeline computes query embeddings in-process for SQL distance only. If your threat model is "no vector leaves my network," Eigen Mesh satisfies that out of the box.
What to harden before you trust it
The README has a production hardening section. The short version:
- Rotate the default secrets. The install script does this; manual setups sometimes don't.
- Set
ORIGINto your real public URL. Better Auth cares. - Drop the
5432:5432port mapping on Postgres so the DB is only reachable on the internal Docker network. The app talks to it over the compose network; nothing else needs to. - Put Caddy or nginx in front of port 3000 for TLS.
- Use a real LLM gateway. The app retries three times on failure and then errors explicitly — no silent fallback — so a flaky endpoint will be visible fast.
Coolify, if that's your thing
Coolify works as a build pack if you select "Docker Compose." The standalone Dockerfile only builds the app image; it doesn't bring the database, and the database is not optional. Pick the Compose pack, add your env vars in the dashboard, deploy. Migrations and RLS run on start.
When to pick managed instead
Self-hosting is free as in software, not free as in time. If you enjoy operating Postgres and Docker, it's a fun evening. If you don't, the managed plan is €3.99/month after 100 free credits — less than the electricity bill for the VPS you'd otherwise run.
Both paths use the identical product. Pick the one that matches how you want to spend your weekends.
Try it
Clone github.com/hiku/eigen, run the install script, point it at your LLM endpoint. If you get stuck, the operator docs and troubleshooting pages live at /developers/getting-started and /developers/troubleshooting. If you'd rather not run it yourself, start on managed and migrate later — your data exports cleanly either way.