Adds claude-obsidian/ — summarizes Claude conversations into one Obsidian note each.
Claude Code sessions: incremental, hourly systemd user timer.
claude.ai: import-claude-ai <export.zip> (no API exists, so exports are manual).
Written via the Obsidian Local REST API plugin, whose built-in /mcp/ server is also how Claude reads the notes back — verified end-to-end with Claude Code (16 vault tools, read + list).
Design points worth reviewing
Summarizer = headless claude -p on your own plan, with --no-session-persistence (otherwise summaries become transcripts the next run re-summarizes — confirmed the transcript count is unchanged after a call). The LiteLLM gateway can't be used: its claude-* models pass through the caller's subscription and it has no Anthropic key.
Usage limits are shared with interactive use. A parallel ~100-session backfill hit a session limit within minutes. Now: JOBS=1, MAX_PER_RUN=10 newest-first, and the run stops at the first usage-limit error with exit 75 (SuccessExitStatus=75) — using a stop flag, since Future.cancel() can't stop a job a worker already started. Offline test covers stop (JOBS=1 and 3 → exactly 2 model calls), resume after reset, empty sessions, and idempotent rerun.
Redaction before anything leaves the machine and again in the note. Tested against the three real secrets present in local transcripts in six contexts each — all redacted — while git SHAs, md5s, paths and hostnames survive.
~60× condensation: 271 MB of transcripts → 4.4 MB; one session needs map-reduce.
Public repo: nothing environment-specific is committed; scanned for internal names, IPs, paths and secrets. Hosts and keys live in ~/.config/claude-obsidian/.
Heads-up
install.sh symlinks the binary from this checkout, so it currently points at this branch. It stays correct once merged.
Adds `claude-obsidian/` — summarizes Claude conversations into one Obsidian note each.
- **Claude Code** sessions: incremental, hourly systemd user timer.
- **claude.ai**: `import-claude-ai <export.zip>` (no API exists, so exports are manual).
- Written via the **Obsidian Local REST API** plugin, whose built-in `/mcp/` server is also how Claude reads the notes back — verified end-to-end with Claude Code (16 vault tools, read + list).
### Design points worth reviewing
- **Summarizer = headless `claude -p`** on your own plan, with `--no-session-persistence` (otherwise summaries become transcripts the next run re-summarizes — confirmed the transcript count is unchanged after a call). The LiteLLM gateway can't be used: its `claude-*` models pass through the *caller's* subscription and it has no Anthropic key.
- **Usage limits are shared with interactive use.** A parallel ~100-session backfill hit a session limit within minutes. Now: `JOBS=1`, `MAX_PER_RUN=10` newest-first, and the run stops at the first usage-limit error with exit 75 (`SuccessExitStatus=75`) — using a stop flag, since `Future.cancel()` can't stop a job a worker already started. Offline test covers stop (JOBS=1 and 3 → exactly 2 model calls), resume after reset, empty sessions, and idempotent rerun.
- **Redaction before anything leaves the machine** and again in the note. Tested against the three real secrets present in local transcripts in six contexts each — all redacted — while git SHAs, md5s, paths and hostnames survive.
- **~60× condensation**: 271 MB of transcripts → 4.4 MB; one session needs map-reduce.
- **Public repo**: nothing environment-specific is committed; scanned for internal names, IPs, paths and secrets. Hosts and keys live in `~/.config/claude-obsidian/`.
### Heads-up
`install.sh` symlinks the binary from this checkout, so it currently points at this branch. It stays correct once merged.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01KF322NzozeaFjpgWvh4F4g
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
The user asked for usage to be monitored closely, and measuring it turned
up that most of the spend was avoidable.
Metering: every model call is appended to usage.jsonl with BILLED tokens
(modelUsage -- the visible `usage` turn undercounted by half) and the
CLI's list-price cost. `usage` reports 5h/24h/7d. Each call's cost is
estimated first and refused if it would cross the per-run or rolling 24h
budget, so budgets cannot be overshot. Removed --max-budget-usd: it
aborts after spending and discards the result ($0.26 lost in one call).
Cost, measured on one session ($0.057 -> $0.010, same summary content):
- alwaysThinkingEnabled=false: extended thinking was ~85% of output.
- DISABLE_PROMPT_CACHING=1: one-shot prompts were being written to the
1h cache at 2x input price.
- CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1: a hidden side request
re-read the whole prompt, doubling billed input (9,638 vs 4,663).
Summaries are cached until their note is written, so a vault failure
never re-pays; --prefetch summarizes while the vault is unreachable.
Offline tests (fake claude binary): budget refusal pre-flight, cache
reuse with zero calls, map-reduce, env/argv levers, billed-token ledger.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KF322NzozeaFjpgWvh4F4g
Needed to leave a full backlog drain running unattended:
- Run lock (flock): enabling the timer fired an immediate catch-up run
(Persistent=true) while a manual run was about to start; without a
lock the two would race on state.json and usage.jsonl.
- OBSIDIAN_API_URL accepts a comma-separated list, first reachable wins,
so the permanent address and an interim port-forward share one config.
- Fix: inline "# comments" in config.env were parsed into values, so
BUDGET_USD_PER_RUN=0.50 # ... crashed float(). The shipped
config.env.example had exactly that shape on several lines -- anyone
copying it would have hit the crash. A '#' inside a value (URL fragment)
still survives. Tested against both the example and a real config.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KF322NzozeaFjpgWvh4F4g
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds
claude-obsidian/— summarizes Claude conversations into one Obsidian note each.import-claude-ai <export.zip>(no API exists, so exports are manual)./mcp/server is also how Claude reads the notes back — verified end-to-end with Claude Code (16 vault tools, read + list).Design points worth reviewing
claude -pon your own plan, with--no-session-persistence(otherwise summaries become transcripts the next run re-summarizes — confirmed the transcript count is unchanged after a call). The LiteLLM gateway can't be used: itsclaude-*models pass through the caller's subscription and it has no Anthropic key.JOBS=1,MAX_PER_RUN=10newest-first, and the run stops at the first usage-limit error with exit 75 (SuccessExitStatus=75) — using a stop flag, sinceFuture.cancel()can't stop a job a worker already started. Offline test covers stop (JOBS=1 and 3 → exactly 2 model calls), resume after reset, empty sessions, and idempotent rerun.~/.config/claude-obsidian/.Heads-up
install.shsymlinks the binary from this checkout, so it currently points at this branch. It stays correct once merged.🤖 Generated with Claude Code
https://claude.ai/code/session_01KF322NzozeaFjpgWvh4F4g
154dc18eb9todb3a3e6e82