Are you the author? Sign in to claim
Self-hosted memory for Claude — markdown knowledge base with wikilink graph, hybrid semantic search (pgvector + Ollama),
Your AI agent forgets everything between sessions. Kybase fixes that: a
self-hosted Markdown knowledge base you browse and edit in the browser,
that Claude uses as persistent memory over MCP. The agent writes notes as
you work, links them with [[wikilinks]], and finds them again next session —
no re-onboarding, no lost decisions.
Everything runs on your machine via Docker: PostgreSQL for notes, pgvector + Ollama for embeddings. No SaaS, no accounts, 100% private.
Giving an agent persistent memory usually means assembling it yourself:
a notes app, an MCP bridge, an embedding pipeline, and sync between them.
Kybase is that whole stack as one docker compose up:
search_notes, get_note_with_links, get_graph, get_backlinks, CRUD for notes/folders) over Streamable HTTP, with instructions that teach the agent to interlink notes properlygit clone https://github.com/Kyrzin/kybase.git
cd kybase
cp .env.example .env
# edit .env: set KYBASE_SECRET (openssl rand -hex 32)
docker compose pull && docker compose up -d
This pulls the prebuilt multi-arch image
(ghcr.io/kyrzin/kybase,
linux/amd64 + linux/arm64) from GitHub Packages. To build from source instead,
run docker compose up -d --build. Pin a specific version with KYBASE_TAG in
.env (e.g. KYBASE_TAG=v1.0.0); the default is latest.
Open http://localhost:3000 and log in with your KYBASE_SECRET.
That's it. On startup the app applies db/migrations/*.sql automatically
(tracked in the schema_migrations table) and Ollama downloads the
embedding model (embeddinggemma, ~620 MB, one time).
Change the host port with KYBASE_PORT in .env.
Note on embeddings: notes and text search work immediately. Semantic search and semantic graph edges activate once Ollama finishes pulling the model and notes get indexed (automatic, in the background).
The app exposes a Streamable HTTP MCP endpoint at /api/mcp.
Claude Code — add to .mcp.json (or claude mcp add):
{
"mcpServers": {
"kybase": {
"type": "http",
"url": "https://your-domain/api/mcp",
"headers": {
"Authorization": "Bearer <KYBASE_SECRET>"
}
}
}
}
claude.ai — Settings → Connectors → Add custom connector, same URL (requires the instance to be reachable over HTTPS). Each client gets its own revocable OAuth token — see Settings → Connected clients in the web UI.
Available tools: list_notes, get_note, get_note_with_links,
create_note, update_note, delete_note, search_notes, list_folders,
create_folder, update_folder, delete_folder, get_backlinks, get_graph.
The server ships with MCP instructions that teach the agent to search before
writing and to add [[wikilinks]] to related notes — so the knowledge graph
grows as the agent uses it, instead of accumulating orphan notes.
| Layer | Tech |
|---|---|
| Frontend | Next.js App Router, React 19 |
| Database | PostgreSQL 16 + pgvector (direct pg connection) |
| Embeddings | Ollama embeddinggemma (default, multilingual) / Google / OpenAI |
| Search | RRF hybrid: pgvector HNSW cosine + bilingual FTS |
| MCP | @modelcontextprotocol/sdk Streamable HTTP |
| Auth | Single KYBASE_SECRET env var |
You can switch the embedding provider (between local Ollama, Google, or OpenAI) and trigger re-indexing directly in the browser:
All supported providers use 768-dimensional embeddings, so switching does not require any database schema changes.
Local model choice. The default local model is embeddinggemma (Google,
multilingual) — for multilingual vaults (e.g. Russian/German) set the Ollama
model to embeddinggemma; it separates relevant from irrelevant notes far
better than English-centric models. nomic-embed-text is a smaller,
English-leaning alternative. The semantic-similarity threshold adapts to the
model automatically (see getMinSimilarity in lib/embeddings.ts), so no
manual tuning is needed when you switch.
CLI Alternative: If you prefer using the terminal, you can trigger re-indexing by calling the admin endpoint:
hljs language-bashdocker compose exec kybase node -e " fetch('http://localhost:3000/api/admin/reindex', { method: 'POST', headers: { Authorization: 'Bearer <KYBASE_SECRET>' } }).then(r => r.json()).then(console.log) "
Your notes are never locked in. Settings → Export .zip downloads the whole vault as plain markdown files with frontmatter (title, tags, dates), folders as directories — readable by any editor, Obsidian included. Import .zip merges a vault back; notes whose titles already exist are skipped. Imported notes are re-embedded automatically in the background.
The same via API:
curl -H "Authorization: Bearer <KYBASE_SECRET>" -o vault.zip \
http://localhost:3000/api/export
# mode=skip (default) keeps existing notes; mode=overwrite replaces them
curl -X POST -H "Authorization: Bearer <KYBASE_SECRET>" \
--data-binary @vault.zip \
"http://localhost:3000/api/import?mode=skip"
The Share button on a note creates a public read-only link
(/share/<token>) — rendered markdown, no login, wikilinks shown as plain
text so nothing else in your vault is reachable. The threat model in one
sentence: the link is the access — revoke links you no longer need
(Settings → Active share links shows everything that is currently public).
Everything lives in one Postgres volume — a nightly pg_dump is one line.
Full recipe including cron and restore: docs/backup.md.
git pull && docker compose up -d --build
Migrations apply automatically on startup. Details: docs/upgrading.md.
# Postgres only (app runs on the host)
docker compose up -d db
cp .env.example .env.local
# in .env.local: set KYBASE_SECRET and uncomment DATABASE_URL
npm install
npm run dev # http://localhost:3000
npm test # Vitest unit tests
npm run build # Production build check
npx tsc --noEmit # Type check
AGPL-3.0 — free to use, modify, and self-host. If you run a modified version as a network service, you must make its source available to your users under the same license.
For a commercial license (e.g. embedding Kybase in a closed-source product or service), contact the author.
Copyright © Denis Kurzin (https://github.com/Kyrzin)
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases
Official GitHub integration for repos, issues, PRs, and CI/CD workflows