Capture thoughts like sending a WhatsApp message. AI organises them into your Obsidian vault.
A personal knowledge management system built around two interfaces:
- A PWA chat app for capturing β text, voice, images, links β from any device
- Obsidian for browsing, connecting, and visualising the graph
Between them, an AI pipeline categorises every capture into a PARA-style folder, generates tags + a one-line summary, transcribes voice, describes images, fetches links, and auto-links related notes so the Obsidian graph view becomes genuinely useful.
| Capture (PWA) | Browse / Search | Obsidian graph |
|---|---|---|
![]() |
![]() |
![]() |
- π¬ WhatsApp-style PWA β installable on iOS / Android / desktop, dark theme, offline queue
- ποΈ Voice notes β Whisper transcription in one tap
- π· Images β vision API description + OCR; image embedded in the daily note
- π Links β paste a URL, get a fetched + summarised reference note
- β Ask β start a message with
?to query your vault (semantic search β LLM answer with sources) - π Auto-organisation β every capture is categorised into a PARA folder, tagged, summarised
- π€οΈ Ambient context β current weather + reverse-geocoded location attached to daily entries
- π₯ Import history β ChatGPT, Claude, and Gemini exports (
.zipor raw JSON/HTML), with live SSE progress - π Semantic search β local ChromaDB embeddings; type/source filters
- π Auto-linking for the graph β auto-generated
Tags/pages,## Relatedsections, daily round-ups - πΊοΈ MOC builder β
python cli.py group "topic"creates a curated Map of Content hub note - π΅ Offline queue β captures while offline; service worker + IndexedDB sync when reconnected
- π Public access β Cloudflare Tunnel quick-start (ephemeral or named)
- π Pluggable LLMs β OpenAI, Anthropic, Google; swap providers + keys from the in-app Settings UI
git clone https://github.com/sasilab/second_brain.git
cd second_brain
# Install (uv recommended; falls back to plain venv)
uv venv && uv pip install -r requirements.txt
# or: python -m venv .venv && .venv/bin/pip install -r requirements.txt
# Configure
cp .env.example .env
# Edit .env. At minimum:
# OPENAI_API_KEY=... (required for voice notes β Whisper is OpenAI-only)
# VAULT_NAME=YourVault (matches the name shown in Obsidian's vault switcher)
# Run
python run.py
# Open http://localhost:8000 β set a password on first visitVault folders, ChromaDB, and .obsidian/graph.json (with sensible color groups) are created on first launch.
The composer has four buttons:
| Button | What it does |
|---|---|
| π | Attach an image β vision API describes it, file goes to 08_Attachments/, note links to it |
| ποΈ | Tap to start recording, tap again to stop. Whisper transcribes, then the same pipeline files it. |
| β¨οΈ | Free-text capture. Auto-categorised into a PARA folder. |
| β€ | Send (or hit Enter) |
Special inputs:
?your questionβ semantic search + grounded LLM answer (doesn't save anything)- A bare URL β fetched + summarised as a reference note
Topbar:
| Icon | Page |
|---|---|
| π | Semantic search with type / source filters |
| β° | Browse recent notes; filter by tag / type / source |
| β¬ | Import ChatGPT / Claude / Gemini exports (live progress) |
| β | Settings β switch provider, swap API keys, change models, edit vault name |
Click any path in a result β opens the note in Obsidian via obsidian://open?vault=β¦&file=β¦ (configure VAULT_NAME in .env so the URLs resolve).
In Chrome/Edge/Safari: open the URL β "Add to Home Screen" (iOS) / "Install app" (Chrome). You get a standalone window with no browser chrome β feels like a native app.
- ChatGPT β Settings β Data Controls β Export data
- Wait for the email, download the ZIP
- PWA β Import β ChatGPT β drop the ZIP. The progress bar shows live counts.
- Claude β Settings β Account β Export data
- Drop
claude_chat.zip(or unzippedconversations.json) into Import β Claude
- Google Takeout β "My Activity" β Gemini Apps Activity (HTML or JSON)
- Drop the ZIP into Import β Gemini
- Sidecar folders (
gemini_scheduled_actions_data,gemini_gems_data,__MACOSX) are auto-skipped
For large exports, set a small Limit first (e.g. 5) to verify everything looks right before processing the whole archive β each conversation is one LLM call for tags + summary.
ββββββββββββββββββββββββ HTTPS ββββββββββββββββββββββββ
β PWA chat (JS) βββββββββββββββββΆβ FastAPI backend β
β service worker + β β bcrypt auth β
β IndexedDB queue β β AI pipeline β
ββββββββββββββββββββββββ ββββββββββββ¬ββββββββββββ
β
ββββββββββββββββββββββββββββββββββββββββββββΌβββββββββββββββββββββββ
β β β β
βΌ βΌ βΌ βΌ
Obsidian vault ChromaDB LLM provider Open-Meteo
(.md + frontmatter) (local, file) (OpenAI/Anthropic/ + Nominatim
Google β pluggable) (weather/loc)
- Backend β Python 3.11+, FastAPI, uvicorn
- Vector DB β ChromaDB (local, file-backed, default
all-MiniLM-L6-v2embeddings) - Frontend β Vanilla JS PWA (no framework, no build step), service worker, IndexedDB
- LLMs β OpenAI (
gpt-4o-mini), Anthropic (claude-sonnet-4-β¦), Google (gemini-2.0-flash) β all pluggable - Voice β OpenAI Whisper API
- Auth β bcrypt + in-memory bearer tokens (single-user app)
- Markdown β
python-frontmatter - Public access β Cloudflare Tunnel
python cli.py status # vault path, configured providers, index size
python cli.py reindex # rebuild ChromaDB from .md files on disk
python cli.py reindex -v # ... and log each indexed file
python cli.py link # regenerate Tags/ pages + Tags/Related sections in every note
python cli.py group "topic name" # build a Map of Content hub note for a topicreindex, link, and group are all idempotent and safe to re-run.
Every standalone capture ends with two auto-managed sections:
<!-- linker:tags -->
## Tags
[[Tags/python|python]] [[Tags/web-scraping|web-scraping]]
<!-- /linker:tags -->
<!-- linker:related -->
## Related
- [[06_Chats/ChatGPT/2024-01-15-web-scraping-help-abc|Web Scraping Help]]
- [[03_Resources/2024-02-20-bs4-tips-def|BeautifulSoup Tips]]
<!-- /linker:related -->Daily notes get an extra Notes from today section. The semantic indexer strips these markers before chunking, so auto-link content never pollutes search.
vault/.obsidian/graph.json is seeded on first launch with color groups by folder (Daily=blue, ChatGPT=green, Claude=purple, Gemini=orange, Projects=red, Areas=yellow, Resources=teal, References=gray, Tags=pink). Existing files are never overwritten.
All keys load from .env first; the in-app Settings overlay can override any of them at runtime (overrides land in vault/_meta/config.json, which is gitignored).
| Key | Purpose |
|---|---|
VAULT_PATH |
Path to the Obsidian vault (default ./vault) |
VAULT_NAME |
Vault name as shown in Obsidian's vault switcher β used to build obsidian:// URLs |
OPENAI_API_KEY |
Required for voice (Whisper is OpenAI-only) |
ANTHROPIC_API_KEY |
Anthropic / Claude key |
GOOGLE_API_KEY |
Google / Gemini key |
ACTIVE_PROVIDER |
openai / anthropic / google |
OPENAI_MODEL, ANTHROPIC_MODEL, GOOGLE_MODEL |
Per-provider model name |
HOST, PORT |
Server bind address |
APP_PASSWORD |
Optional β seeds the password hash on first run if no password is set yet |
Quick start (ephemeral URL, changes per restart):
./setup_tunnel.sh # macOS/Linux
.\setup_tunnel.ps1 # WindowsFor a stable URL, use a named tunnel:
cloudflared tunnel login
cloudflared tunnel create second-brain
cloudflared tunnel route dns second-brain brain.example.com
cloudflared tunnel run --url http://localhost:8000 second-brainBrowser geolocation requires HTTPS. Cloudflare Tunnel gives you that.
http://localhostalso works because localhost is treated as a secure origin.
- Browser history import
- AI-maintained MOC pages auto-refresh on a schedule
- Calendar / timeline view
- Native Obsidian companion plugin
- Self-hosted LLM support (Ollama)
- Test suite
See SECOND_BRAIN_SPEC.md Β§15 for details.
- The settings overrides file (
vault/_meta/config.json) is plain JSON, not encrypted. Filesystem permissions are the protection. - Voice capture uses OpenAI Whisper regardless of the active text-completion provider.
- Open-Meteo has no reverse geocoding β location names come from OpenStreetMap Nominatim (free, no key, ~1 req/sec policy; the 15-min cache stays well under).
- Auto-linking on a fresh capture is fast; on a vault with thousands of notes it walks the disk once per capture (cached 30 s afterwards).
- The vector index excludes
_meta/,Templates/, andTags/; browse includesTags/so you can navigate to tag pages.
PRs welcome. See CONTRIBUTING.md for setup and guidelines.
MIT β do whatever you want with it. Attribution appreciated.


