Files
dotfiles/claude-obsidian/README.md
T
noconnorandClaude Opus 5 6df2acfe24 claude-obsidian: summarize Claude conversations into Obsidian notes
One note per Claude Code session (incremental, hourly user timer) and a
claude.ai data-export importer, written through the Obsidian Local REST API
plugin -- whose built-in /mcp/ server is also how Claude reads them back.

Transcripts are condensed (tool output dropped, one line per tool call,
~60x smaller), redacted, then summarized by headless `claude -p` on the
user's own plan. Three things learned the hard way are encoded here:

- --no-session-persistence, or every summary becomes a transcript that
  the next run summarizes.
- A LiteLLM gateway passing through the caller's Claude subscription has
  no key of its own, so a background job cannot use its claude-* models.
- Summaries share the plan's usage limits. A parallel ~100-session
  backfill exhausted a session limit in minutes. So one job, a per-run
  cap, and the run stops at the first usage-limit error (exit 75) instead
  of failing the whole queue; a stop flag, because Future.cancel() cannot
  stop work a thread already picked up. Covered by an offline test of
  stop / resume / idempotent rerun.

Nothing environment-specific is committed: hosts, keys and paths live in
~/.config/claude-obsidian/ (this repo is public).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KF322NzozeaFjpgWvh4F4g
2026-09-13 08:51:28 -04:00

92 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](https://github.com/coddingtonbear/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
1. 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`).
2. `./install.sh` — links the binary into `~/.local/bin`, enables the hourly user timer, and
creates `~/.config/claude-obsidian/config.env` from `config.env.example` if absent.
3. Edit `config.env` (at minimum `OBSIDIAN_API_URL`), then preview one note:
```bash
claude-obsidian-sync stats # sizes, no network
claude-obsidian-sync sync --dry-run --limit 1 # prints the note, writes nothing
```
## Use
```bash
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 reads the vault through the plugin's MCP server:
```bash
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 its `claude-*` models.
- **`--no-session-persistence` is load-bearing.** Without it every summary writes a new
transcript into `~/.claude/projects`, and the next run summarizes its own summarizing.
- **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_RUN` sessions 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.
- **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 for `SETTLE_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
```yaml
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.