obsidian-second-brain
v0.2.1
Published
Turn an Obsidian vault into a self-maintaining second brain for AI coding sessions
Readme
second-brain
Give your AI coding sessions a long-term memory — an Obsidian vault that maintains itself.
Every Claude Code session ends the same way: the context dies with it. The transcript lands in a folder nobody reads back, and the next session starts cold. second-brain closes that loop:
- Capture — session transcripts mirror into your vault automatically; ending a task with
/wrapdistills it into a small, curated plan + output artifact. - Synthesize — an hourly job (Claude Haiku, a fast model) turns new artifacts into dated episode notes; a weekly job (Claude Sonnet, a stronger one) consolidates episodes into stable per-project wiki pages — what the project is, what was decided and why, how projects relate.
- Recall — init adds a section to your
CLAUDE.mdinstructing sessions to consultwiki/index.mdwhenever the repository alone can't answer. Sessions start light and find context instead of being fed giant dumps.
No manual curation. Idle hours cost $0 — a content-hash manifest skips runs with nothing new. And every run that did work leaves a human-readable report in wiki/reports/, so the system is never a black box.
You work in Claude Code
├─ transcripts mirror into the vault (archive, $0)
└─ /wrap on finishing a task → curated artifact
│
▼ hourly · Haiku
wiki/episodes/ — dated episode notes per project
│
▼ weekly · Sonnet
wiki/<project>.md — per-project wiki pages: decisions, rationale, relations
│
▼
your next session reads wiki/index.md when it lacks context — and just knowsRequirements
| Requirement | Notes |
|---|---|
| macOS | scheduling uses launchd (Windows/Linux not yet supported) |
| Node >= 20 | the build runs automatically on install |
| Obsidian | the vault folder must contain .obsidian/ — open it in Obsidian once, or let init create a fresh vault with --new-vault |
| Claude Code | used at least once, so ~/.claude/projects/ exists; its claude CLI also powers synthesis — without it everything still works except episode/wiki generation |
Install
npm install -g obsidian-second-brain
second-brain initAfter upgrading (
npm update -g obsidian-second-brain), runsecond-brain initagain: npm replaces the package folder, which holds the generated config. Re-running is idempotent and never touches your vault content.
git clone https://github.com/minhnhat08/second-brain.git ~/tools/second-brain
cd ~/tools/second-brain
npm install # installs dependencies and builds (via the prepare hook — if it fails, run `npm run build`)
npm link # puts the `second-brain` command on your PATH
second-brain initThe clone is the install: the scheduled jobs run out of this folder, so don't park it somewhere temporary. If you move it later, run second-brain init again from the new location. Prefer not to touch your global npm? Skip npm link and use node dist/cli.js wherever you see second-brain below.
init asks two questions — Enter accepts the defaults shown in brackets:
Claude folder [/Users/you/.claude]
Obsidian vault [/Users/you/Documents/Obsidian Vault]It refuses to continue if the Claude folder has no projects/ (run Claude Code once first) or the vault has no .obsidian/ (open it in Obsidian once, or pass --new-vault). Then it sets up the whole loop:
- scaffolds the vault as an LLM wiki (
raw/,wiki/,AGENTS.md, its own git repo for history) - installs the
/wrapcommand and adds a marker-fenced section to your~/.claude/CLAUDE.md: the/wraphabit plus the retrieval policy - generates
config/projects.jsonand loads the hourly + weekly launchd jobs
Your files are safe. Nothing is silently overwritten: conflicts prompt (or use --force / --keep-existing), every override is backed up next to the original, a symlinked CLAUDE.md is followed to its target and edited additively, and init prints a review: line whenever it touches an instruction file — read what it added.
Unattended install: second-brain init --claude <dir> --vault <dir> --new-vault --keep-existing [--skip-launchd]. Without a terminal attached, unspecified paths take the defaults and any file conflict aborts unless --force or --keep-existing is given.
Daily use
There is none — that's the point. Two habits make the wiki good:
- End meaningful tasks with
/wrap. Curated artifacts are far better synthesis input than raw transcripts, and the installed CLAUDE.md section reminds the agent to offer it. - Browse
wiki/index.mdin Obsidian now and then;wiki/reports/shows exactly what any run did.
Is it working?
launchctl list | grep second-brain # hourly + weekly jobs loaded
tail -5 /tmp/second-brain.stdout.log # last run summary
ls -t "<vault>/wiki/reports/" | head -3 # recent run reports — <vault> is the path you chose in initIf init warned claude CLI preflight failed, synthesis fell back to noop (mirror + reports only). Confirm claude --version works in a plain terminal, then set synthesis.backend to cli-claude in config/projects.json. A second concurrent run exiting with Another instance holds the lock is by design.
Configuration
config/projects.json — in the install folder, not the vault:
| Field | Meaning |
|---|---|
| vaultRoot | <vault>/raw/projects — where transcripts mirror to (must end in raw/projects) |
| providers[] | one entry per source; all four fields required: name (claude / codex / gemini), sourceRoot, destinationPath, enabled |
| synthesis.backend | noop ($0: mirror + reports only) · cli-claude (Haiku hourly, Sonnet weekly) · ollama (local hourly; weekly stays on cli-claude) |
| synthesis.claudeBin | absolute path to the claude binary — init records the one it verified; scheduled jobs never see your shell PATH |
| logsRoot | run logs directory |
Paths support ${ENV_VAR} expansion; the file is validated with clear errors. Edit it and the next run picks it up — no reload step.
Code maps
second-brain map <repoPath> captures a repository's structure as
deterministic evidence under raw/code/<project>/ ($0 — no LLM in capture)
and renders wiki pages under wiki/code/<project>/: one architecture
overview (with a Mermaid component diagram) plus one page per module.
Registered repos are re-captured by the hourly job; only changed evidence
re-renders (content-hash manifest), so idle repos cost nothing.
second-brain map <repoPath> [--project <name>] [--path <subdir>]
[--max-modules N] [--force]--pathscopes a monorepo package; register each package as its own project.--forceclears the project's code manifest entries and re-renders every page.- Module boundaries are deterministic (top-level directories, with descent
into a dominant directory); override per repo via
codeMap.repos[].modulesinconfig/projects.jsonwhen directories do not reflect architecture. - Page bodies are generated artifacts — manual edits are overwritten. Evidence
under
raw/code/is the LLM-readable source of truth for structure.
Uninstall
second-brain uninstall
npm uninstall -g obsidian-second-brainRemoves the launchd jobs, the managed CLAUDE.md section, /wrap, and generated files it installed — skipping any you modified. Your vault content is never touched: it is your data and your audit trail.
Development
npm run typecheck
npm test # 172 unit/integration tests
npm run coverage # per-file line/branch coverage
npm run e2e # drives the real built binary against temp worlds ($0)
SB_E2E_CLAUDE=1 npx tsx --test tests/e2e/claude-smoke.e2e.ts # paid smoke (one haiku call)The E2E suites spawn dist/cli.js as a child process against disposable worlds (vault paths deliberately contain spaces): ingest/consolidation with reports and idle skips, init/uninstall lifecycle (PATH shims keep your real launchd untouched), lock contention, crash redo, timezone pinning, and backend degradation. The release bar lives in docs/publish-readiness.md; the architecture in docs/design.md.
Status
Running live against a real vault — 900+ sessions, idempotent re-runs, a report per run. Public release is pending a short observation window. Next on the roadmap: local semantic search over the mirrored transcripts.
