6.7 KiB
claude-obsidian — Claude conversations → Obsidian notes
Summarizes every Claude conversation into one searchable Obsidian note: what happened, what was decided and why, the facts and gotchas worth remembering, and what was left open.
- Claude Code sessions sync automatically and incrementally (hourly timer).
- claude.ai chats import from a data export (claude.ai has no API, so each export is manual).
Notes are written through the Obsidian Local REST API
plugin, so the vault can live anywhere the plugin is reachable. The same plugin exposes a
built-in MCP server (/mcp/), which is how Claude reads the notes back — no separate MCP
process.
~/.claude/projects/*/*.jsonl ─┐ ┌─ Claude/Code/2026/…md
claude.ai export .zip ────────┼─ condense → redact → summarize → PUT ────┼─ Claude/Web/2026/…md
└─ (headless claude -p, no transcript) └─ Claude/Index.md
Install
-
In Obsidian, install Local REST API, enable its HTTP server, and make it reachable from this machine. Put the API key in
~/.config/claude-obsidian/api-key(chmod 600). -
./install.sh— links the binary into~/.local/bin, enables the hourly user timer, and creates~/.config/claude-obsidian/config.envfromconfig.env.exampleif absent. -
Edit
config.env(at minimumOBSIDIAN_API_URL), then preview one note:claude-obsidian-sync stats # sizes, no network claude-obsidian-sync sync --dry-run --limit 1 # prints the note, writes nothing
Use
claude-obsidian-sync sync # what the timer runs
claude-obsidian-sync sync --session <session-id> # one session, now, ignoring the settle window
claude-obsidian-sync import-claude-ai ~/Downloads/data-2026-09-13.zip
claude-obsidian-sync sync --prefetch --limit 3 # summarize into the local cache, vault untouched
claude-obsidian-sync usage # calls, billed tokens, spend: last 5h / 24h / 7d
Claude reads the vault through the plugin's MCP server:
claude mcp add --scope user --transport http obsidian http://<host>:27123/mcp/ \
--header "Authorization: Bearer $(cat ~/.config/claude-obsidian/api-key)"
How it behaves — and why
- Summaries run on your own Claude plan via headless
claude -p(LLM_BACKEND=claude-cli). No API key to manage. An OpenAI-compatible backend (LLM_BACKEND=openai) exists for local models. Note a LiteLLM gateway that fronts Claude by passing through the caller's subscription has no key of its own, so a background job cannot use itsclaude-*models. --no-session-persistenceis load-bearing. Without it every summary writes a new transcript into~/.claude/projects, and the next run summarizes its own summarizing.- Usage is metered and capped. Every model call is appended to
~/.local/state/claude-obsidian/usage.jsonlwith billed tokens (the CLI'smodelUsage, not the visible turn) andtotal_cost_usd— API list-price equivalent, a faithful proxy for how much was consumed; the plan's own meter is only visible in Claude Code's/usage. Before each call its cost is estimated (+20% margin) and the call is refused if it would crossBUDGET_USD_PER_RUNor the rollingBUDGET_USD_PER_DAY— so budgets are never overshot. Notclaude -p --max-budget-usd: that aborts after the tokens are spent and discards the result (measured: $0.26 for nothing). Every run ends with a one-line usage report. - Three cost levers, measured on one session — $0.057 → $0.010, same summary content:
alwaysThinkingEnabled=false(extended thinking was ~85% of output tokens),DISABLE_PROMPT_CACHING=1(the CLI writes each prompt to the 1-hour cache at 2× input price, and a one-shot call never reads it back), andCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1(otherwise a hidden side request re-reads the entire prompt, doubling billed input). A whole ~110-session backlog is about $2 at list price with all three. - Summaries are cached until their note is written, so a vault outage never pays for the same
summary twice, and
--prefetchcan do the summarizing while the vault is unreachable. - It shares your plan's usage limits. A first backfill of ~100 sessions in parallel hit a
session limit within minutes — which also limits interactive use. So: one job at a time,
MAX_PER_RUNsessions per run (newest first), and the run stops at the first usage-limit error (exit 75, which the systemd unit treats as success) instead of failing the rest of the queue. The next hourly run resumes. A 100-session backlog drains in about ten hours. - Secrets are redacted before anything leaves the machine, and again in the note: private
keys, bearer tokens,
password=-style assignments, JWTs, provider tokens, ≥48-char hex, and random mixed-case strings. It over-redacts on purpose; git SHAs, md5s and paths survive. The summarizer is also told never to reproduce secrets. - One run at a time (a
flockonrun.lock): an hourly timer firing during a long manual run exits immediately instead of racing it on the state and ledger files. - Several vault URLs can be listed; the first that answers wins, so one config covers both a
permanent address and a temporary
kubectl port-forward. - Incremental and idempotent. State (
~/.local/state/claude-obsidian/state.json) records each session's size+mtime. A resumed session is re-summarized into the same note path. A session is left alone until idle forSETTLE_MINUTES, so a live conversation isn't summarized mid-flight. Empty sessions are recorded and skipped. - Condensed, not truncated. Tool output is dropped and each tool call becomes one line; prose is kept. Typical compression is ~60× (271 MB of transcripts → 4.4 MB). Sessions over 300 KB condensed are summarized in parts, then combined.
- Subagent transcripts (
<session>/subagents/**) are part of their parent session and are not synced separately.
Note format
type: claude-conversation
source: claude-code # or claude-ai
session_id: 3f9c2a1e-…
title: Fix flaky CI cache after runner upgrade
project: my-service # basename of the working directory
branch: …
started / ended: …
prompts: 1 # user prompts, not tool-loop records
summarized_by: claude-haiku-4-5-20251001
tags: [claude, claude-code, ci, caching, …]
followed by a summary callout and Outcomes / Decisions / Facts & gotchas / Open threads,
and a claude --resume <id> line. Claude/Index.md lists every note, newest first.