claude-obsidian: unattended overnight runs -- lock, URL fallback, config fix

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
This commit is contained in:
2026-09-17 16:14:45 -04:00
co-authored by Claude Opus 5
parent 2bfa7e9a2d
commit 376ec03428
4 changed files with 43 additions and 9 deletions
+4
View File
@@ -80,6 +80,10 @@ claude mcp add --scope user --transport http obsidian http://<host>:27123/mcp/ \
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 `flock` on `run.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 for `SETTLE_MINUTES`, so a live conversation isn't