A self-maintaining personal knowledge database β powered by MCP, DuckDB, and biological memory models.
For anyone who saves more papers, notes, and figures than they could ever re-read.second-brain turns everything you capture into a database thatmaintains itselfβ auto-linking related notes, compressing what you stop reading, and keeping every figure searchable by its content. What you saved a year ago is still one query away, at a fraction of the token cost.
| Problem | Solution |
|---|---|
| π You save dozens of papers but can never find the right figure | search_figures("UMAP melanocyte") β returns the exact panel, across every paper you've saved |
| π arXiv gives you the abstract; you need the full paper | Auto-upgrades /abs/ β /html/ β fetches the complete paper with all sections, not just the abstract |
| π Notes pile up; older ones never get cleaned up | Vault Sleep: low-access notes compress automatically every Sunday while you sleep (60β90% token reduction) |
| π New notes stay isolated; you forget what's connected | Auto-wikilinks: every saved note is automatically linked to semantically related notes already in your vault |
| π Semantic search needs a cloud API or Docker stack | Self-hosted nomic-embed-text via llama-server; BM25 fallback when offline |
| π Every AI memory tool locks you into their format | Pure Markdown vault β sync with Google Drive, iCloud, or git; switch agents anytime |
| πΌ Figure context is lost when you read a paper | Every figure is downloaded, OCR'd by Claude Vision, and stored in DuckDB β searchable by gene name, p-value, axis label |
save_article("https://arxiv.org/abs/2405.01234")
β
β’ /abs/ auto-upgraded to /html/ β full paper, not just abstract
β’ Full text converted to Markdown
β’ All figures downloaded + OCR'd by Claude Vision
β’ Semantic embeddings computed
β’ Auto-linked to related notes already in your vault β auto-wikilinks
β’ Stored in 30-resources/ β queryable immediately
search_figures("UMAP cluster batch correction")
β
β’ Returns the exact figure from the exact paper
β’ Works across your entire saved literature library
flowchart LR
subgraph input["π₯ Any Content Source"]
A1["arXiv / PubMed paper"]
A2["Web article / blog"]
A3["Local PDF / DOCX"]
A4["Personal note"]
end
subgraph core["βοΈ second-brain-mcp"]
B1["Markdown note<br/>30-resources/"]
B2["Figure OCR<br/>+ VLM description"]
B3["Semantic embedding<br/>+ auto-wikilinks"]
B4["Ebbinghaus score<br/>ranking"]
B5["PNG snapshots<br/>60β90% token reduction"]
end
subgraph query["π Queryable Knowledge"]
C1["search_figures<br/>'UMAP melanocyte'"]
C2["search_notes<br/>'batch correction scRNA'"]
C3["get_context<br/>top-20 relevant notes"]
end
input --> core
B1 --> B2
B1 --> B3
B3 --> B4
B4 --> B5
B2 --> C1
B3 --> C2
B4 --> C3
Eight things most self-hosted memory tools can't do β combined in one:
| Most memory tools⦠| second-brain |
|---|---|
| Save a link or PDF, then leave you to read and tag it | π¬ One command builds the database β save_article fetches any URL/PDF, converts to Markdown, downloads & OCRs every figure with Claude Vision, then semantic-indexes it |
| Store the arXiv abstract you pasted | |
π Full text, not abstracts β /abs/ URLs auto-upgrade to /html/ for the complete paper: methods, results, discussion |
|
| Leave new notes isolated until you tag them | π The knowledge graph builds itself β every note is auto-linked to semantically related notes already in your vault |
| Cost the same whether a note is read daily or never | π§ Memory that forgets like a brain β Ebbinghaus score ranks by recency Γ frequency; stale notes compress while you sleep |
| Search documents, not what's inside the figures | |
πΌ Figure-level search across your whole library β search_figures("p < 0.001") returns the exact panel from the exact paper |
|
| Forget your project decisions between sessions | π The AI learns your rules β hot notes auto-extract constraints into memory/rules.md , injected at every session start |
| Grow more expensive as the vault grows | π Token cost shrinks with age β PNG snapshots replace old text at 60β90% compression; frequently-read papers stay full-fidelity |
| Lock you into their database format | π Zero lock-in β pure Markdown, any MCP agent, sync via any cloud drive or git |
Every project you work on can be resumed in a new session with full context β no re-explaining, no lost progress.
flowchart LR
A["π’ Session Start<br/>get_context()"] --> B["AI receives:<br/>β’ goals.md β current priorities<br/>β’ Top-20 recent notes<br/>β’ Extracted rules"]
B --> C["Work on project<br/>new_note / search / read"]
C --> D["π΄ Before ending session<br/>update_goals(...)"]
D --> E["New session<br/>get_context() again"]
E --> B
End of session β tell the agent to save state:
Update goals: currently working on the scRNA batch correction pipeline.
Completed: harmony integration. Blocked on: choosing n_components for PCA.
Next session: start from the PCA parameter sweep in 20-areas/research/harmony-notes.md
The agent calls update_goals()
and optionally new_note("project", ...)
for detailed progress.
Start of next session β just say:
Get context and continue where we left off.
The agent calls get_context()
and immediately sees:
goals.md
with the state you saved- The harmony-notes.md surfaced at the top (recently accessed, high Ebbinghaus score)
- Rules auto-extracted from that note, e.g.:
RULE: use n_components=30 for this dataset β tested 20/30/50, 30 minimises batch effect without losing resolution
RULE: exclude sample CRC_04 β library size outlier confirmed by QC
These rules live in memory/rules.md
and are injected at every get_context()
call β the AI carries your hard-won decisions forward automatically, without you having to repeat them.
| What | Where | Always in context? |
|---|---|---|
| Current priorities / blocked items | memory/goals.md |
|
| β every session | ||
| Project progress notes | 10-projects/ or 20-areas/ |
|
| β if recently accessed | ||
| Decisions and rationale | decisions/ |
|
via get_decisions() |
||
| Extracted rules from notes | memory/rules.md |
|
| β every session | ||
| Saved papers and figures | 30-resources/ |
|
via search_notes/figures |
This works across any projectβ bioinformatics analysis, coding, writing, research. Save state with one sentence at the end of a session; resume instantly at the start of the next.
get_context() # β goals + recent notes + rules loaded automatically
search_figures("p < 0.001 UMAP cluster")
search_notes("single cell integration batch correction")
get_decisions("MyProject")
| Biological Brain | This System |
|---|---|
| Hippocampal consolidation during sleep | Vault Sleep: weekly LLM-compression of old low-access notes |
| Ebbinghaus forgetting curve | Score-based ranking: access_count / ln(age_days) |
| Visual long-term memory | PNG snapshots β resolution degrades gracefully with age |
| Associative recall | Semantic search + auto-generated [[wikilinks]] |
| Sleep-dependent consolidation | launchd cron, runs Sunday 02:00 while you sleep |
Memory that gets cheaper over time β unlike flat-file systems where old notes cost the same forever.
Note age β fresh (0β3 mo) 3β6 months 6β12 months 1 year+
ββββββββββββββ ββββββββββ βββββββββββ βββββββ
token cost: ββββββββββββββ ββββββ ββββ ββ
~1,000 tokens ~400 tokens ~256 tokens ~100 tokens
βΌ 60% βΌ 74% βΌ 90%
Tier assigned by
score Γ age(adaptive). Frequently-accessed notes stay full-text regardless of age.
Measured on Apple Silicon MacBook (20-rep average, BM25-only mode).
Vault BM25-only p50 Hybrid BM25+semantic p50
ββββββ βββββββββββββββββ ββββββββββββββββββββββββ
10 n βββββββββ 21 ms ββββββββββββ 37 ms
50 n βββββββββ 25 ms βββββββββββββ 39 ms
100 n βββββββββ 27 ms ββββββββββββββ 45 ms
| Vault Size | BM25 p50 | Hybrid p50 | Recall@1 | Recall@5 | MRR |
|---|---|---|---|---|---|
| 10 notes | 21 ms | 37 ms | 30% | 60% | 0.42 |
| 50 notes | 25 ms | 39 ms | 70% | 90% | 0.78 |
| 100 notes | 27 ms | 45 ms | 70% | 80% | 0.73 |
Hybrid mode adds ~18 ms for embedding lookup. Both modes scale sub-linearly with vault size.
Recall figures at this scale (10β100 notes) carry high sample variance β a single ambiguous query shifts Recall@1 by 10%. Treat them as directional, not as benchmarks against large corpora; the takeaway is that hybrid consistently beats BM25-only on relevance for a fixed query set.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AI Agent Layer β
β Claude Code Β· Gemini CLI Β· Any MCP β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β MCP Protocol (19 tools)
ββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββ
β Layer 2 β MCP Server β
β server.py β
β get_context Β· search_notes Β· save_article Β· β¦ β
ββββββββ¬ββββββββββββββββ¬βββββββββββββββββ¬ββββββββββββββ
β β β
ββββββββΌβββββββ ββββββββΌβββββββ ββββββββΌβββββββ
β vault_sleepβ β vault_db β β figures β
β compress β β DuckDB FTS β β PNG snap β
β Phase 3β9 β β + semantic β β OCR Β· VLM β
ββββββββ¬βββββββ ββββββββ¬βββββββ βββββββββββββββ
β β
ββββββββΌββββββββββββββββΌβββββββββββββββββββββββββββββββ
β Layer 0 β Markdown Vault β
β 00-inbox Β· 10-projects Β· 20-areas Β· 30-resources β
β 40-archive Β· decisions Β· memory Β· templates β
β (syncs via Google Drive / iCloud / git) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Every Sunday 02:00 (launchd, no interaction needed)
β
βΌ
sync_index + embeddings
β
βΌ age > 90d AND Ebbinghaus score β€ 0.5
ββββββββββββββββββββββββββββββββββββββββ
β Adaptive Tier Selection β
β score > 1.5 β text (keep full) β β frequently-read: never compressed
β score > 0.8 β large ~400 tokens β
β score > 0.3 β base ~256 tokens β
β otherwise β small ~100 tokens β
ββββββββββββββββββ¬ββββββββββββββββββββββ
β
Gemini CLI β Claude CLI β naive (auto-fallback, no LLM required)
β
compressed β vault / original β 40-archive/ / snapshot β .png
| Tool | Description |
|---|---|
get_context |
|
| Session start: goals + top-20 Ebbinghaus-ranked notes + auto-rules | |
save_article |
|
| Fetch URL/PDF β Markdown + auto-extract figures | |
search_notes |
|
| Hybrid BM25 + semantic search across all notes | |
search_figures |
|
| Search figure OCR text / VLM descriptions | |
extract_figures_for |
|
| Manually trigger figure extraction for a saved article | |
read_note |
|
| Read note + record access (updates Ebbinghaus score) | |
read_note_as_image |
|
| Return PNG snapshot for token-efficient reading | |
new_note |
|
| Create note with correct template and folder by type | |
get_decisions |
|
| List ADR decision records, optionally filtered by project | |
update_goals |
|
Update memory/goals.md |
|
sync_index |
|
| Rebuild DuckDB index from vault files | |
index_stats |
|
| Show note counts by type | |
vault_sleep |
|
| Compress old low-activity notes (dry_run=True by default) | |
sleep_status |
|
| Show compression candidates without acting | |
snapshot_note_tool |
|
| Render note to PNG at chosen resolution tier | |
extract_rules_tool |
|
| Extract L3 rules from frequently-accessed notes | |
consolidate_tool |
|
| Merge semantically similar notes into one abstract note | |
update_links_tool |
|
Refresh auto-generated [[wikilinks]] |
|
prune_archive_tool |
|
| Delete archived originals that have a PNG snapshot |
tests/test_figures.py 19 passed (OCR, snapshots, VLM)
tests/test_server.py 13 passed (MCP tools, path safety)
tests/test_vault_db.py 39 passed (FTS, semantic search, embeddings)
tests/test_vault_sleep.py 44 passed (compression, consolidation, rules, prune)
ββββββββββββββββββββββββββββββββββββββββ
115 passed in 3.37s
| Dependency | Required | Notes |
|---|---|---|
| Python 3.11+ | β | |
Playwrightllama-servernomic-embed-text-v1.5.Q8_0.ggufANTHROPIC_API_KEY
pip install mcp-second-brain
playwright install chromium
mkdir -p ~/second-brain/{00-inbox,10-projects,20-areas,30-resources,40-archive,decisions,memory,templates}
Option A: Claude Code (CLI)
claude mcp add --scope user second-brain \
--env SECOND_BRAIN_PATH=~/second-brain \
-- python -m mcp_second_brain
Option B: Claude Desktop β add to ~/Library/Application Support/Claude/claude_desktop_config.json
:
{
"mcpServers": {
"second-brain": {
"command": "python",
"args": ["-m", "mcp_second_brain"],
"env": { "SECOND_BRAIN_PATH": "/path/to/your/vault" }
}
}
}
In Claude Code or Claude Desktop, tell the agent:
Run sync_index to build the initial index.
git clone https://github.com/ddmanyes/second-brain-mcp
cd second-brain-mcp
uv sync
uv run playwright install chromium
Then register with Claude Code:
claude mcp add --scope user second-brain \
--env SECOND_BRAIN_PATH=~/second-brain \
-- uv run --project /path/to/second-brain-mcp python server.py
| Variable | Default | Description |
|---|---|---|
SECOND_BRAIN_PATH |
||
~/second-brain |
||
| Path to your vault directory | ||
EMBED_URL |
||
http://localhost:11435/v1/embeddings |
||
| Embedding server endpoint | ||
EMBED_MODEL |
||
nomic-embed-text |
||
| Embedding model name | ||
EMBED_PORT |
||
11435 |
||
| llama-server port |
cp examples/launchd/com.yourname.llama-embed.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.yourname.llama-embed.plist
cp examples/launchd/com.yourname.vault-sleep.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.yourname.vault-sleep.plist
| Symptom | Likely cause | Fix |
|---|---|---|
| Semantic search silently falls back to BM25 | llama-server not running on EMBED_PORT |
|
| Start the embedding server (see | ||
curl localhost:11435/v1/embeddings |
read_note_as_image
/ snapshots failuv run playwright install chromium
vault_sleep
never compresses anythingANTHROPIC_API_KEY
β naive fallback, or no eligible notesANTHROPIC_API_KEY
; remember only notes >90 days old with Ebbinghaus score β€ 0.5 are candidates (sleep_status
shows them)sync_index
once after install (and after bulk file changes)SECOND_BRAIN_PATH
unset or wrongenv
block; defaults to ~/second-brain
vault/
βββ 00-inbox/ # Unprocessed captures β clear daily
βββ 10-projects/ # Active projects
βββ 20-areas/
β βββ research/ # Ongoing research domains
β βββ coding/ # Dev tools and workflows
β βββ consolidated/ # Auto-merged similar notes (Phase 8)
βββ 30-resources/ # β Papers and articles (save_article writes here)
βββ 40-archive/ # Compressed originals (auto-managed by vault_sleep)
βββ decisions/ # Architecture Decision Records (ADR format)
βββ memory/
β βββ goals.md # Current priorities β injected at every session start
β βββ index.md # Vault map
β βββ rules.md # Auto-extracted L3 rules β injected at every session start
βββ templates/ # Note templates (note, decision, project, research)
uv run pytest tests/ -v
uv run python benchmark.py --quick --markdown # search latency + accuracy report
| Paper | Where Used |
|---|---|
Experience Compression Spectrum: Unifying Memory, Skills, and Rules in LLM Agents (2026)DeepSeek-OCR: Contexts Optical Compression (2025)MemOCR: Layout-Aware Visual Memory for Efficient Long-Horizon Reasoning (2026)Active Context Compression: Autonomous Memory Management in LLM Agents (2026)SimpleMem: Efficient Lifelong Memory for LLM Agents (2026)Memory for Autonomous LLM Agents: Mechanisms, Evaluation, and Emerging Frontiers (2026)- Ebbinghaus, H. (1885).
Γber das GedΓ€chtnis. β forgetting curve; basis foraccess_count / ln(age_days + 1)
Stickgold, R. (2005).β sleep-dependent memory consolidationNature, 437, 1272β1278.
MarkItDown Β· DuckDB Β· llama.cpp Β· nomic-embed-text Β· FastMCP Β· Playwright Β· Anthropic Claude API
PRs and Issues welcome. Please open an issue first to discuss significant changes.
MIT License β Β© 2026 Chan Chi Ru. See LICENSE.