✦ H3LL0 W0RLD - HACK THE PLANET - FOLLOW THE WHITE RABBIT ✦
← back to blog
IT

Claude Code, wired into Obsidian

Claude forgets everything when the session ends. The usual fix is to paste context back in at the start of every conversation, which works until the context is three months of notes across forty files.

The fix I actually run is an Obsidian vault that Claude reads and writes directly, under rules strict enough that I'll let it near notes I can't afford to lose. Sources get archived before they're summarized, claims carry a ledger entry pointing back at where they came from, and every write goes through one inspectable transaction that can be rolled back. This is how it's put together, and how to build the same thing.

The three layers

It helps to be precise about what's doing what, because only one of these three pieces is mine.

The vault is just a directory of Markdown. Mine is called War_Machine and holds around 170 files: project notes, a glossary, a task dashboard, security research, and a wiki/ subtree the agent maintains. Obsidian is the editor on top of it. Delete every tool below and the vault is still a folder of plain text I can read in less.

The plugin is claude-obsidian by Daniel Agrici — MIT licensed, about 11k stars, and the reason any of this is safe. It's 15 Agent Skills plus a Python core that owns every write. I run a fork with one small fix for unattended runs; the architecture is entirely upstream's.

The glue is mine: a handful of personal Claude Code skills that know my vault's conventions, plus a capture pipeline that gets things into the inbox without opening an agent at all.

Take the plugin first, because the design decision it makes is the one that matters.

One operation, one transaction

An agent editing your notes has an obvious failure mode: it half-finishes. It rewrites three of five files, hits an error, and now the vault is in a state nobody designed. Worse — a parallel agent overwrites a file another one read thirty seconds ago, and the change vanishes without an error anywhere.

claude-obsidian makes one logical knowledge operation into one recoverable transaction. Read every target and record its SHA-256. Let parallel workers return drafts only. Merge the whole change into one bundle. Inspect the bundle. Apply it once. A real one from my vault:

json
{
  "schema": "claude-obsidian.transaction.v1",
  "operation_id": "lint-fix-20260815-vault-accuracy",
  "operation_type": "lint-fix",
  "expected_hashes": {
    "wiki/overview.md": "3fa5c684df0f25987458847d04ac81f558d78a5b826ab79539fd38735f4b783f",
    "wiki/hot.md": "2274a5af36d2dddc1d32ed3291c792c00c178f6ad7c3c30a70552be43a730a21"
  },
  "writes": [
    { "path": "wiki/overview.md", "mode": "replace", "sha256": "9fe658fd74e5..." }
  ]
}

expected_hashes is the whole trick. If a file changed between read and apply — because I edited it in Obsidian while the agent was thinking — the hash no longer matches and the operation fails as a conflict instead of overwriting me. Alongside it the core writes a journal.json and a backups/ directory holding the original bytes, so an interrupted apply can be restored:

bash
python3 scripts/claude-obsidian.py transaction recover --vault ~/War_Machine

The same paranoia governs which directory gets written at all. A vault is selected explicitly — from CLAUDE_OBSIDIAN_VAULT, from the nearest .claude-obsidian.json, or from one unambiguous initialized ancestor. If selection is uncertain, the command exits without writing. It will never decide that the plugin's own cache directory is your vault.

Sources survive the summary

The second thing that makes this more than a note-taker: an ingested source is archived as immutable bytes before anything is written about it, and the resulting page cites that archive.

Ingest a URL and you get a page in wiki/sources/ with real frontmatter, prose that stays close to what the source actually claimed, and a pointer to the content-addressed copy:

markdown
---
type: source
title: KRACK key reinstallation attacks against WPA2
status: developing
created: 2026-08-14
tags: [source, security-research, wifi, wpa2]
---

Source: [KRACK Attacks: Breaking WPA2](https://www.krackattacks.com/)
Archived at `.raw/captured/a77824f5ec123cc9...cc1cdfe64.md`.

Behind that sits a source ledger — one JSON file, one entry per source:

json
"src-caa5a29dce9972224b0d": {
  "origin": { "kind": "url", "locator": "https://learn.microsoft.com/..." },
  "authority": "official",
  "review_status": "active",
  "content_sha256": "66f65be9211131b57140bceee316800aa208779ced29b8634a1cc765e79ada68",
  "ingested_at": "2026-08-14",
  "refresh_due": "2026-11-14",
  "pages": ["wiki/sources/Microsoft Entra authentication overview.md"]
}

authority separates a vendor's own documentation from a blog post. refresh_due marks when a claim should be re-checked. pages is the reverse index: which notes would be wrong if this source turned out to be wrong. A companion claim ledger tracks support, contradiction and confidence, and high-risk accepted claims require two independent sources. Contradictory evidence stays visible in the vault rather than being averaged away.

That's the part I'd point at. Most AI note workflows stop at "it wrote a summary". The summary is the least durable thing in the system.

Set it up

Roughly fifteen minutes. Python 3.11+ is the only hard dependency; Obsidian itself is optional, since the output is Markdown either way.

Install the plugin from the marketplace:

bash
claude plugin marketplace add AgriciDaniel/claude-obsidian
claude plugin install claude-obsidian@agricidaniel-claude-obsidian
claude plugin list

Now create a vault — and note that this is not the plugin checkout. Every mutating setup command previews itself first and refuses to run until you approve that exact plan:

bash
export GENERATED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

python3 scripts/claude-obsidian.py init "$HOME/MyVault" \
  --generated-at "$GENERATED_AT" --operation-id init-reviewed

That prints a JSON plan containing an approved_plan_sha256. Read the plan, confirm the destination and the paths it intends to create, then hand that exact hash back:

bash
python3 scripts/claude-obsidian.py init "$HOME/MyVault" \
  --generated-at "$GENERATED_AT" --operation-id init-reviewed \
  --approved-plan-sha256 "<sha256-from-the-plan>" --apply

The hash binds to the plan you actually reviewed. If the filesystem drifted in between, the apply fails instead of doing something you didn't read. Already have an Obsidian vault? Use adopt in place of init — same two-step, and it's non-destructive; it adds configuration and ledgers without touching your existing notes.

You end up with inbox/ for source intake, .raw/ for immutable captures, wiki/ for generated notes, .vault-meta/ for runtime state, and .claude-obsidian.json marking the directory as a vault.

Then run Claude from inside the vault — that's what makes vault selection unambiguous:

bash
cd ~/MyVault
claude

Start with /claude-obsidian:wiki, which diagnoses readiness and routes you. Drop a file in inbox/ and run /claude-obsidian:wiki-ingest. Ask questions with /claude-obsidian:wiki-query. Check health with /claude-obsidian:wiki-lint, which reports dead links, orphans, frontmatter gaps and stale indexes deterministically — same vault, same date, same findings.

Two habits worth forming immediately. Put the vault in git, because the plugin's transactions protect against a bad write and not against a bad decision. And run wiki-lint weekly; a knowledge base rots quietly.

Capture is a separate problem

Ingestion is the interesting half, but it's not the half that decides whether the system gets used. What decides that is whether saving something costs you a context switch. If capturing an article means opening a terminal, starting an agent and describing what you want, you will not do it at 11pm.

So capture in my setup never involves an agent at all. It's a file append:

bash
#!/bin/bash
set -euo pipefail
VAULT="$HOME/War_Machine"
TS="$(date '+%Y-%m-%d %H:%M')"
printf -- "- [ ] %s %s\n" "$TS" "$1" >> "$VAULT/inbox/quick-capture.md"

That's the entire script. It's wired to two macOS Shortcuts — a Share Sheet action for URLs and a global-hotkey "Quick Note" — and to a small unpacked Chrome extension that adds right-click "Add to inbox" items for selected text or a link. The extension talks to a native messaging host that writes the same line. No browser-visible network call, no API key in the browser, no daemon.

Filing happens later, on a schedule. A LaunchAgent runs a script at 8am that starts Claude headless against whatever's queued:

bash
"$CLAUDE_BIN" -p "$PROMPT" \
  --plugin-dir "$PRODUCT" \
  --add-dir "$PRODUCT" \
  --allowedTools "Bash(python3 $PRODUCT/scripts/claude-obsidian.py *) Read Write Edit" \
  --permission-mode acceptEdits \
  --output-format text

The unattended run is not allowed to fetch

Here's the design decision in that pipeline, and the one I'd keep in any agent I build.

Network egress requires consent, and consent requires a human. At 8am there isn't one. So the scheduled run is deliberately crippled: a queued line with no URL gets filed into the wiki, and a queued line with a URL gets moved to wiki/queue-urls.md under "Pending review" — parked, not fetched. An empty inbox exits before it makes a single API call.

The fetching happens in a second runner, /process-inbox, which I invoke when I'm actually sitting there. It reads the inbox and the parked queue, files everything local, then groups the URLs by domain and asks once: fetch and ingest these N URLs across these domains — all, some, or none? Anything I decline stays queued for next time.

Splitting one job across two runners looked like duplication when I built it. It isn't. It's the only way to have both an automatic pipeline and a real consent gate, instead of an automatic pipeline that quietly grants itself permission every morning because nobody's watching.

Teach a skill your vault's dialect

The plugin governs wiki/. The rest of my vault — projects, glossary, tasks, people — predates it and follows my own conventions. So /note is a personal skill whose actual content is a description of those conventions: project notes carry created and updated frontmatter, running logs use ### YYYY-MM-DD — short title entries, the glossary is one Markdown table cross-linked with wikilinks, and new entries are appended, never rewritten.

The skill's most useful line is the one telling the model not to trust itself:

This skill runs cold each time — it has no memory of past invocations — so re-derive everything from the vault's current contents, not from assumptions.

It also ranks its own sources. There's an optional Notes/Instructions.md for aliases and preferences, and the skill says explicitly that if it contradicts what a live file shows, the file wins and the mismatch gets flagged. Stale documentation about a vault is more dangerous than none.

The result is that "log this session" produces something a stranger could act on in a week — decisions, commands, blockers, next steps — instead of a transcript.

Prompts worth stealing

These work with Claude Code and with any agent that has filesystem access. Use them as written; they're shaped to fail safe.

Audit before you let anything write. Point an agent at a vault you care about and get a map first:

Read my Obsidian vault at ~/MyVault without writing anything. Report: the directory structure, the frontmatter fields actually in use and how consistently, the naming conventions for files and links, any orphan notes nothing links to, and the three conventions you'd have to follow to add a note that looks native. Do not create, edit or move any file. End with the questions you'd need answered before writing.

Generate your own conventions skill. The output of the audit above is the input here:

Based on that audit, write a Claude Code skill at ~/.claude/skills/note/SKILL.md that logs a session into this vault. It must: re-derive structure from the live files every run rather than assuming, append to logs and never rewrite prior entries, bump updated frontmatter on every file it touches, and state plainly what it will not do. Frontmatter needs name and description — write the description so it triggers on "log this session" and on /note.

Force grounded answers. The failure mode of a vault-aware agent is confident synthesis of things you never wrote:

Answer this from my vault only: <question>. Cite the file path for every claim. If the vault doesn't contain the answer, say so and name the notes that came closest — do not fill the gap from your own knowledge, and do not merge two notes into a claim neither of them makes.

Make research file itself. Deep-dive a topic and leave something behind:

Research <topic>. Before you summarize anything, save each source's raw content to .raw/ and record its URL, retrieval date and how authoritative it is. Then write one note per distinct concept, linked to each other, each citing which sources support it. Where sources disagree, say so in the note instead of picking a winner. Ask me before fetching anything — list the domains first.

Find what your vault forgot. Best prompt I run monthly:

Look at the last 30 days of notes. What did I start and never finish? What questions did I write down and never answer? What terms show up repeatedly with no note defining them? List them as concrete next actions, ordered by how much of the surrounding work is blocked on them.

What it doesn't do

Honesty about the edges, because the README is honest about them and I've hit most personally.

There's no built-in semantic extraction for PDF or EPUB — you get metadata, hash and size. URL and YouTube capture produce a validated consent plan but need an external runner configured. Retrieval is BM25 by default, local and deterministic; contextual prefixes and cosine reranking are optional and gated behind explicit egress consent, and an untrustworthy embedding stage falls back to plain BM25 rather than guessing. On Windows, read-only inspection and dry runs work natively but vault writes require WSL and fail closed otherwise.

And the thing itself is not a backup, not a sync service, and not an oracle. It's a filing system with good manners. Put the vault in version control.

Links

If you build one of these, the measure of success isn't how clever the agent is. It's whether you still trust the vault after six months of the agent writing to it.