Building a Knowledge Management System with Obsidian and Claude Code
Every time I finish a Claude Code session, useful stuff disappears. Blog drafts scroll past. Security audit results vanish into terminal history. Generated images sit in /tmp/ until the next reboot wipes them. I'd built 29 blog posts, 8 projects, and 59 skills — but my actual knowledge about all of it was scattered across hidden folders, terminal scrollback, and my own memory.
I needed a system where everything Claude Code produces is browsable, searchable, and backed up. Not a new tool — just a better way to see what I already had.
The answer was embarrassingly simple: point Obsidian at Claude Code's memory folder.
The Problem: Terminal-Shaped Knowledge
Claude Code has a built-in memory system. It writes markdown files to ~/.claude/projects/ — notes about your projects, preferences, lessons learned. It's genuinely useful. But there are two problems.
First, the memory folder is hidden. You never browse it. You never read it unless Claude Code reads it for you. It's knowledge locked behind a CLI.
Second, everything else Claude Code produces — blog drafts, generated images, security reports, architecture decisions, debugging write-ups — has no home at all. It renders in your terminal, you nod, and it's gone.
I was losing knowledge faster than I was creating it.
The Fix: One Folder, Two Interfaces
An Obsidian vault is just a folder of markdown files with a .obsidian config directory. Claude Code's memory is just a folder of markdown files. The realization: they're the same thing.
# Install Obsidian brew install --cask obsidian # The memory folder IS the vault — just register it # Obsidian stores vault configs in ~/Library/Application Support/obsidian/obsidian.json
No migration. No export/import. No sync tool. Obsidian opens the folder directly. Now the same files are accessible two ways:
| Interface | When to use | Strengths |
|---|---|---|
| Claude Code | During sessions — reading/writing memory, generating outputs | Instant filesystem access, bulk operations, automation |
| Obsidian | Between sessions — browsing, reviewing, editing | Visual UI, graph view, search, image previews |
Edits flow both ways. Update a note in Obsidian, Claude Code sees it next session. Claude Code writes a blog draft, it appears in Obsidian immediately.
The Vault Structure
I reorganized the flat memory folder into a structure that makes sense in Obsidian's sidebar:
memory/
├── MEMORY.md ← index (38 lines, was 304)
├── personal/ ← accounts, Google, Notion
├── projects/ ← 8 project knowledge files
├── project-docs/ ← symlinked READMEs + CLAUDE.md
├── skills/ ← 59 symlinked SKILL.md files
├── tools/ ← n8n, status line, GIF recording
├── workflows/ ← feedback, processes, reminders
├── review/ ← approval inbox
│ ├── blog-drafts/
│ ├── content-plans/
│ ├── images/ ← 41 images + Gallery.md
│ ├── reports/
│ └── screenshots/
└── logs/ ← session history
├── sessions/
├── debugging/
└── architecture-decisions/
A few design decisions worth explaining.
Symlinks for Live Docs
Skills and project docs already live in their own locations (~/.claude/skills/ and each project's repo). Instead of copying, I symlinked them into the vault:
# Symlink all 59 skills for skill_dir in ~/.claude/skills/*/; do skill_name=$(basename "$skill_dir") ln -sf "$skill_dir/SKILL.md" memory/skills/${skill_name}.md done # Symlink project docs ln -sf ~/ai-journey/CLAUDE.md memory/project-docs/ai-journey-CLAUDE.md ln -sf ~/pantry-app/README.md memory/project-docs/pantry-app-README.md
One source of truth. Edit a skill in Obsidian, it updates in ~/.claude/skills/. Push a README change from your repo, it shows up in Obsidian.
The Review Inbox
This is the folder that changes everything. Instead of outputs vanishing into the terminal, Claude Code now drops them here:
| Output type | Goes to | Reviewed in |
|---|---|---|
| Blog drafts | review/blog-drafts/{slug}.md | Obsidian — read, edit, approve |
| Generated images | review/images/ | Obsidian — inline image preview |
| Security audits | review/reports/{type}-{date}.md | Obsidian — browse findings |
| Content plans | review/content-plans/ | Obsidian — review schedule |
| QA screenshots | review/screenshots/ | Obsidian — visual comparison |
The key insight: review/ is an approval queue. Nothing goes live until I've seen it in Obsidian and said "ship it." This turned Claude Code from a tool that does things for me into one that does things with me.
The Image Gallery
Obsidian renders images inline. I created a Gallery.md that embeds every generated image using Obsidian's wiki-link syntax:
### ai-journey-tech-stack ![[blog/ai-journey-tech-stack.png]] ### building-pantry-app ![[blog/building-pantry-app.png]]
Scrolling through 41 images in one view beats hunting through Finder. This alone made the whole setup worth it.
Session Logs
The logs/ folder captures knowledge that would otherwise exist only in my memory:
- Session summaries — what was built, what tools were used, gotchas found
- Debugging write-ups — root cause analysis for tricky bugs
- Architecture decisions — what was chosen, what was rejected, and why
These accumulate over time into a searchable history. Three months from now, when I hit a similar bug, I can search my vault instead of re-debugging from scratch.
Context Window Benefits
The reorganization had an unexpected technical benefit. Before, Claude Code loaded a 304-line MEMORY.md into every conversation — project details for 8 projects, API keys, gotchas, everything. Even when I was only working on one project.
After splitting into individual files, the index dropped to 38 lines. Claude Code loads only the relevant project file on demand. That's roughly 270 fewer lines of context consumed by default, leaving more room for actual work.
Backing It Up
The vault lives in a hidden folder (~/.claude/projects/). If my machine dies, everything dies with it. Same problem with skills — 59 skill definitions, local only.
I created two private GitHub repos with simple backup scripts:
# Skills backup ~/.claude/skills-backup/backup.sh # → pushes to github.com/carlfung1003/claude-skills (private) # Memory/vault backup ~/.claude/memory-backup/backup.sh # → pushes to github.com/carlfung1003/claude-memory (private)
Each script rsyncs the current state, commits with a timestamp, and pushes. Run them weekly or after significant changes. The memory backup excludes .obsidian/ config (machine-specific), skills/ (symlinks, backed up separately), and project-docs/ (symlinks to repos already in git).
The Full Storage Picture
After setting this up, I mapped where all my data actually lives. Five layers, each with a distinct purpose:
| Layer | What lives there | Backup strategy |
|---|---|---|
| GitHub (8 repos) | Source code, deployed content | Git itself — push = backed up |
| Obsidian vault | Project knowledge, review inbox, session logs | claude-memory private repo |
| Claude Code skills | 59 skill definitions | claude-skills private repo |
| Notion (5 hubs) | Rich notes, databases, mobile-accessible planning | Cloud (Notion's infrastructure) |
| Google Drive | Work exports, shared spreadsheets | Cloud (Google's infrastructure) |
The rule of thumb: if Claude Code needs to read/write it fast, it goes in Obsidian. If it needs rich editing or mobile access, it goes in Notion. If it's code, it goes in Git. No overlap, no orphans.
What I'd Do Differently
Honestly, not much. The whole setup took about 30 minutes because the foundational insight is so simple: Obsidian vaults are folders, Claude Code memory is a folder, make them the same folder.
If I were starting over, I'd set this up on day one. Every session summary, every debugging write-up, every generated image from the past month is gone — lost to terminal history and /tmp/ cleanups. The vault only captures what happens after you set it up.
The one thing I'd add is a daily note template that auto-creates a session log file. Right now it depends on Claude Code remembering to write one at session end. Automating that with Obsidian's Daily Notes plugin would close the last gap.
If you're using Claude Code for anything more than one-off questions, give this a try. The setup is trivial. The payoff compounds with every session.