46 KiB
Changelog
All notable changes to claude-obsidian. Format: Keep a Changelog. Versioning: SemVer.
[1.9.2] - 2026-05-27 (prompt-cache hardening + path-handling robustness)
Ports Anthropic prompt-caching best practices into the one place the plugin calls the Anthropic API directly: tier-1 contextual-prefix generation in scripts/contextual-prefix.py. Verified by full-repo sweep that cache_control and the Anthropic API surface exist nowhere else (incl. claude-canvas/). No change to retrieval output — API payload shape + observability only.
Changed
- Cache only above the Haiku floor (
scripts/contextual-prefix.py). The page-bodycache_controlmarker is now attached only when the body clears the Haiku 4.5 minimum cacheable size (HAIKU_CACHE_MIN_CHARS = 16384, ~4096 tokens × 4 chars/token). Below the floor the Anthropic API silently ignores the marker, so the prior unconditional marker was a no-op that misled the reader. Extracted as the pure, unit-testedcache_control_for(). .claude-plugin/plugin.json+marketplace.jsonversion 1.9.1 → 1.9.2.
Added
- Cache telemetry (
scripts/contextual-prefix.py). The tier-1 path now logscache: wrote=<N> read=<N> tokfrom the responseusagefields — integers only, never page content, preserving the v1.7.1 data-egress posture. Implements the docs' "monitor cache hit rates" guidance and reveals whether the body cache is actually firing given the floor. - Sequential-invariant note at the chunk loop (
process_page), documenting that cache reads depend on chunk 0's response landing before chunk 1 is sent (Anthropic prompt-caching concurrency rule). Guards against a future parallelization silently zeroing every cache read. tests/test_contextual_prefix.py— hermetic coverage of thecache_control_for()floor decision (below / at / above floor, empty body, floor constant matches the documented Haiku minimum). Wired intomake test(now 9 suites) +make test-contextual.
Documented
- Tier-1 "prompt-cached" claim now states the ~16 KB Haiku floor in the
contextual-prefix.pymodule docstring and the ingest diagrams indocs/compound-vault-guide.mdandskills/wiki-retrieve/SKILL.md, so docs match runtime behavior.
Fixed
- Explicit missing or out-of-vault page paths now fail cleanly (
scripts/contextual-prefix.py). A single explicit path that does not exist exits 3 (was: silent exit 0, swallowed by theis_file()filter inmain()); a path resolving outside the vault exits 2 with a message (was: a rawValueErrortraceback fromrelative_to()).--allruns are unaffected. - Removed the dead
EXIT_NO_ADDRESS(exit 5) constant and its docstring entry — it was defined and documented but never raised. Renamed the shadowedprefixprogress-label variable inprocess_pagetoprogress.
Verification
make test: 9 hermetic suites green; the contextual suite now mocks the API payload to assertcache_controlattaches only above the floor and the model reply is truncated to one line. No regressions.- Explicit-path exit codes confirmed by run: missing in-vault path → 3, out-of-vault path → 2, valid page → 0,
--allunaffected. python3 scripts/contextual-prefix.py wiki/getting-started.md --peek: tier selection unchanged (synthetic without--allow-egress).- Live tier-1 telemetry leg (sends page bodies off-machine) requires explicit
--allow-egressand is left to operator verification per the repo's consent design.
[1.9.1] - 2026-05-18 (v1.9.0 audit hardening)
Patch release closing 6 of 6 remaining HIGH/MEDIUM findings from the v1.9.0 pre-public-promotion audit (docs/audits/v1.9.0-pre-public-promotion-audit-2026-05-18.md) plus 3 LOW hardening items. Composite score moves from 91.6 to ~94 raw average. Public-promotion ship verdict remains GREEN.
Fixed (defensive hardening)
- H4 — stale-lock reaper wiring (
hooks/hooks.json). New SessionStart command runsbash scripts/wiki-lock.sh clear-stale --max-age 3600at every session resume/startup. Locks orphaned by a crashed batch ingest get reaped automatically on the next session, not just on operator demand. - S2 — opt-out gate for PostToolUse auto-commit (
hooks/hooks.json). Hook now exits early if.vault-meta/auto-commit.disabledexists. Default behavior unchanged for existing users; per-vault opt-out is onetouchaway. Useful for shared repos, CI runs, or any scenario where the operator wants to commit manually. - Data M3 — symlink canonicalization (
scripts/wiki-lock.sh:110-142).validate_path()previously rejected literal..segments but did not canonicalize symlinks. A symlink insidewiki/resolving outsideVAULT_ROOTcould escape. Now resolves viapython3 os.path.realpathand rejects any path whose canonical form is outsidecommonpath(VAULT_ROOT, target). Cross-platform (GNU coreutils + macOS BSD); no realpath flag dependency. - Data M4 —
.vault-meta/locks/.gitkeep+ gitignore pattern change..vault-meta/locks/*(not the dir itself) is now ignored;.gitkeepis whitelisted so the directory ships on fresh clone. Runtime behavior unchanged (ensure_dirs()always created it lazily); this just removes the first-acquire side-effect on directory presence. - Data M1 — rerank.py warning routes to hook.log (
scripts/rerank.py:158-176). When the embed-cache lock is unavailable after 3 tries, the WARN line now also appends to.vault-meta/hook.logwith a timestamp, so users see the event viawiki lintor by tailing the log. stderr-only was invisible to most callers. - S4 — ollama-localhost assert (
bin/setup-retrieve.sh:97-117). IfOLLAMA_URLenv var points off-localhost, refuse to probe unless--allow-remote-ollamais passed. Mirrors the existingscripts/tiling-check.py:351gate. Closes a defense-in-depth gap where a malicious env var could redirect probes to an attacker-controlled endpoint.
Documented
- H2 + S3 — multi-tenant threat model (
SECURITY.md). New "Threat model: single-tenant vault" section documents three intentional design choices (cross-process lock release, auto-commit hook scope, filesystem-permission trust boundary) and the mitigations for shared-host deployments. Closes the documentation gap the audit flagged: the design choices are correct for single-tenant, but operators in shared-host scenarios deserve to know what changes for them.
Changed
.claude-plugin/plugin.json+marketplace.jsonversion 1.9.0 → 1.9.1.
Deferred to v1.9.2 (not in this release)
- Data M2 — embed-cache + chunk-orphan GC: new
--gcsubcommand forbm25-index.py+contextual-prefix.pythat prunes entries whose backing pages no longer exist. Requires hermetic tests covering edge cases; scoped for a dedicated release. - W1 — wiki/meta/ release-session note relocation: 12 files with incoming wikilinks need a coordinated graph update. Bundled with References M1+M2 (17 dead wikilink targets) for one-pass wiki cleanup.
- Security S1 — Excalidraw checksum pin: requires upstream release hash verification + maintenance burden for future releases. Tracked separately.
- GROW note from v1.9.0 audit — 7th always-check cut in
agents/verifier.md: cross-file string consistency check (catches the class of bug where a single-file fix should have been a multi-file cascade, like the 548d294 + F1-F5 sequence).
Verification
make test: 8 hermetic suites green (~1234 assertions). No regressions.- Live symlink-escape test on
wiki-lock.sh validate_path:ln -s /tmp/foo ./escape && bash scripts/wiki-lock.sh acquire escape/x.mdcorrectly rejects with "path resolves outside vault via symlink". - Both plugin manifests parse as JSON.
- Pre-push verifier agent dispatch on staged diff: SHIP, 0 BLOCKER, 0 HIGH.
[1.9.0] - 2026-05-18 (10-principle thinking framework)
Minor release adding the 10-principle thinking framework as a first-class layer of the plugin. The framework (OBSERVE-OBSERVE-LISTEN-THINK-CONNECT-CONNECT-FEEL-ACCEPT-CREATE-GROW) is integrated at three levels: as the new /think skill, as an appendix on every existing SKILL.md, and as the methodology spine for the v1.8.0 pre-push audit (which used it as its phase structure). Skill count: 14 → 15.
Added
skills/think/SKILL.md— new skill #15. Canonical source for the 10-principle thinking loop. Walks Claude through external observation, metacognition (the often-skipped one), active listening, first-principles analysis (six-cut kernel lives here), lateral connection, system orchestration, intuition, intellectual humility (anti-sycophancy enforcement), generative output, and iterative growth. Triggers on "think this through", "10-principle review", "/think", "OBSERVE LISTEN THINK", "deep think", "systematic thinking", "structured reasoning". Allowed tools:Read, Grep, Glob, Bash(read-only; loads structure and discipline, not mutation). ~250 lines covering the 10 principles with one-paragraph definitions, when-to-invoke guidance, stage-by-stage prompts (5 questions per stage), anti-patterns (the common skips), and composition notes with/best-practices,/save,/wiki-lint,agents/verifier.md, and/autoresearch.
Changed
-
All 14 existing SKILL.md files — each receives a unique "## How to think (10-principle mapping)" appendix at the end. Per-skill 10-row table mapping each principle to that skill's specific work. Examples: wiki-mode's OBSERVE-internal is "audit the assumption that mode=generic is the default"; autoresearch's OBSERVE-internal is "am I steering the search toward what I already expect to find? confirmation bias kills research"; wiki-lint's FEEL is "a lint report should empower, not shame". Each appendix is non-trivial and skill-specific (not a template stub), satisfying the plan's verification rule #12.
-
.claude-plugin/plugin.json+marketplace.json— version 1.8.2 → 1.9.0. Description unchanged (the framework is additive to the v1.8.0 + v1.8.2 surface).
Repo hygiene (first-public-release prep)
CONTRIBUTING.md(NEW) — workflow, six-cut self-review checklist, commit conventions, test requirements.CODE_OF_CONDUCT.md(NEW) — adopts Contributor Covenant v2.1 by reference.SECURITY.md(NEW) — private disclosure policy, response SLA, scope, credit policy..github/ISSUE_TEMPLATE/bug_report.md(NEW) — reproduction + environment + skill-affected fields..github/ISSUE_TEMPLATE/feature_request.md(NEW) — scope + compatibility + testing fields..github/pull_request_template.md(NEW) — six-cut self-review + test results + verifier verdict + CHANGELOG reminder..github/workflows/test.yml(NEW) — CI runsmake teston push/PR + validates SKILL.md frontmatter + agentstools:declaration + plugin manifest JSON validity.- Manifest + doc URL updates —
plugin.json,marketplace.json, and 18 other files updated to reference the canonical repository URL.
Why this release
Per the v1.8.0 pre-push audit's GROW notes (docs/audits/v1.8.0-pre-push-audit-2026-05-18.md §10), the 10-principle framework proved its value as the AUDIT's mental spine — OBSERVE-internal forced explicit bias documentation; GROW forced a feedback-loop section. Shipping it as a first-class skill (and as appendices on all existing skills) makes the discipline available to every future invocation, not just to one-off audits. This is the GROW step of the audit itself, embodied in code.
Compass axis status after v1.9.0
| Axis | v1.8.0 | v1.9.0 |
|---|---|---|
| Compounding wiki primitive | #1 | #1 |
| Multi-writer safety | #1 | #1 |
| Retrieval architecture (free tier) | #1 | #1 |
| License / openness | #1 | #1 |
| Methodology support | #1 | #1 (deepened by framework integration) |
| Derivative outputs | NO | NO (v2.0 scope) |
| GUI / install ergonomics | NO | NO (v2.5+ scope) |
5 of 7 axes #1 (unchanged count, but methodology axis deepens — claude-obsidian is now the only Claude+Obsidian plugin shipping methodology modes AND a first-class thinking-loop framework AND per-skill thinking guidance).
Migration notes
- v1.8.x vaults: no action needed. All existing skills work identically; the "How to think" appendix is additive guidance, not behavioral change.
/thinkis invocable from any project that has this plugin installed; it does not require a vault.- The framework can be invoked explicitly (
/think <problem>) or applied implicitly when an existing skill's appendix references it.
Composition
/think+/save= the canonical compounding loop. Apply the 10 principles to a problem; when done, save the insights worth not re-deriving./think+/best-practices= engineering discipline at the THINK stage of the framework. The six-cut kernel IS the inside of stage 4./think+agents/verifier.md= an OBSERVE-internal substitute for solo work — fresh-context reviewer that catches biases the chair missed.
[1.8.2] - 2026-05-18 (pre-push audit closure)
Patch release closing all 4 HIGH findings + 1 leaked BLOCKER-class hardening from the v1.8.0 pre-push audit. Audit: docs/audits/v1.8.0-pre-push-audit-2026-05-18.md. Per the audit's strict push gate (any BLOCKER halts), v1.8.2 takes the release from YELLOW (0 BLOCKER / 4 HIGH) to GREEN (0 BLOCKER / 0 HIGH).
Fixed
- H1 —
scripts/detect-transport.sh: implementmanual_override. The documented escape hatch for MCP-only users ("manual_override": trueintransport.json) was documented atwiki/references/transport-fallback.mdbut never honored by the script. v1.8.2 parses the existing snapshot BEFORE auto-detection; whenmanual_override: true, the user'spreferredandfallback_chainare preserved across normal cycles AND--forcerefreshes. Auto-detection still runs to refresh theavailable.cli.*informational fields. Field round-trips through the JSON schema (new"manual_override": <bool>in every snapshot). Verified by smoke test: a pinned"preferred": "mcp-obsidian"survived a--forcerefresh. - H2 —
agents/wiki-ingest.md: addBashto tools + add## Mode awareness (v1.8+)section. The parallel batch-ingest sub-agent was missingBashin itstools:frontmatter despite mandatingbash scripts/wiki-lock.sh acquire/releasein its body — this defeated the v1.7 multi-writer safety guarantee. Sub-agent was also missing v1.8 mode-routing awareness, so batch-ingest in LYT/PARA/Zettelkasten vaults filed to v1.7 generic paths. Both gaps closed. - H3 —
skills/autoresearch/SKILL.md: new## Web egress hygiene (v1.8.2+)section. Four sub-policies: (1) URL validation (rejectfile://,javascript:, RFC1918), (2) content sanitization before write (strip<script>/<iframe>, escape[[/]]injections, reject embedded frontmatter delimiters, 50KB truncation), (3) per-loop cost expectation (~45 WebFetch calls per run), (4) failure mode (log towiki/log.md, never silently swallow). The router'ssafe_name()is the FILENAME guard; this is the BODY-content guard. - H4 —
skills/save/SKILL.md: prependStep 0: Decide the destination root. The skill body assumed project-localwiki/filing while the global~/.claude/CLAUDE.md/saverule mandates personal-vault filing for cross-project saves. Step 0 makes the routing decision explicit with three rules in order: user-explicit override → project/global CLAUDE.md/saveoverride → project-localwiki/default. Path sanitization still applies regardless of destination root. Workflow step 5 now requires a collision check (ASK before overwrite). - wiki/references/transport-fallback.md: §Manual override now describes the actual v1.8.2 behavior (preserves
preferred+fallback_chainwhile still refreshingavailable.cli.*; field round-trips through snapshot).
Changed
.claude-plugin/plugin.json+marketplace.json: version 1.8.0 → 1.8.2.docs/audits/v1.8.0-pre-push-audit-2026-05-18.md(NEW): full pre-push audit report. 14 per-skill scores (average 84.6/100), per-tier finding ledger, v1.8.2 fix replay, hook safety, manifest accuracy, push-gate decision tree. Audit methodology used the 10-principle thinking spine (OBSERVE-OBSERVE-LISTEN-THINK-CONNECT-CONNECT-FEEL-ACCEPT-CREATE-GROW) as audit phases.
Verification
- All 8 hermetic test suites green (~1234 assertions): allocate-address, tiling-check, boundary-score, bm25-index, retrieve, wiki-lock, concurrent-write, wiki-mode.
- v1.8.2 manual_override smoke test: pinned
preferred="mcp-obsidian"survived--forcerefresh. - All path-traversal attack vectors against
route_path()confirmed sanitized inside vault root (6 dedicated assertions). - mkstemp atomic write yields 0600 perms (verified via
stat). --modepreview is non-mutating (verified via mtime).
Known issues at v1.8.2 (deferred to v1.9 or later)
The pre-push audit also surfaced 14 MEDIUM and 45 LOW findings. None block release. Triage in audit §12. Highlights:
wiki-climcp-obsidian + mcpvault tiers documented as fallback positions 2/3 but unreachable from auto-detection (deferred — manual_override is the workaround until MCP auto-detect ships in v1.7.x patch).- No
tests/test_detect_transport.shyet for v1.7+ transport script (planned v1.8.3). - 7 skills declare incomplete
allowed-toolslists (missingBashdespite shelling out) — works in practice (harness default-allows), but convention violation (planned v1.8.3). tests/__init__.pymissing →python3 -m unittest tests.Xform fails (direct invocation works) (planned v1.8.3).- Various doc/reality drift around the v1.8 ID format change (14-digit → 20-digit), v1.8
--modeflag not yet referenced in consumer docs (deferred LOW polish PR).
[1.8.0] - 2026-05-17 (methodology modes — closes compass priority gap 5)
Minor release closing the 5th and final priority gap from the May 2026 compass artifact: methodology support. Adds the wiki-mode skill with first-class support for four organizational styles (LYT / PARA / Zettelkasten / Generic). After this release, claude-obsidian is #1 on 5 of 7 axes per compass framework — up from 4/7 in v1.7. Full guide: docs/methodology-modes-guide.md.
Added
skills/wiki-mode/SKILL.md— new skill (skill #14). Reads.vault-meta/mode.json; defaults togeneric(v1.7 behavior) when absent. Triggers on "set vault mode", "switch to PARA", "use LYT", "zettelkasten setup", etc.scripts/wiki-mode.py— pure-stdlib router + config helper. Subcommands:get(current mode),config(full JSON),route <type> <name>(suggested path),set <mode>(write mode.json),id(mint Zettel timestamp ID),templates(list per-mode templates).bin/setup-mode.sh— interactive setup with--mode <name>non-interactive flag. Idempotent; safe to re-run to switch modes. Optionally seeds template folders for the chosen mode.- 6 per-mode templates under
skills/wiki-mode/templates/:lyt/moc-template.md,lyt/atomic-template.mdpara/project-template.md,para/area-template.md,para/resource-template.mdzettel/atomic-template.md
tests/test_wiki_mode.py— hermetic test suite (15 assertions covering load/save round-trip, all 4 modes' routing, slugify Unicode handling, Zettel ID format, corrupted-config fallback, CLI subprocess paths).make testis now 8 suites.docs/methodology-modes-guide.md— narrative guide; when-to-use-which decision tree per mode; full schema documentation; migration guidance.
Changed
skills/wiki-ingest/SKILL.md— new "## Mode awareness (v1.8+)" section. Skill now consultswiki-mode.py routebefore filing new source/entity/concept pages. mode=generic preserves v1.7 behavior byte-for-byte.skills/save/SKILL.md— new "## Mode awareness (v1.8+)" section. Session notes now route per active mode (with explicit note that the global~/Documents/Obsidian Vault/sessions/rule still applies to cross-project saves).skills/autoresearch/SKILL.md— new "## Mode awareness (v1.8+)" section. Research synthesis output routes per active mode; every new entity/concept page in the research loop also routes via the router.Makefile— newtest-modeandsetup-modetargets;testaggregate now runs 8 suites;clean-test-stateremoves.vault-meta/mode.json+.vault-meta/hook.log..gitignore—.vault-meta/mode.json+.vault-meta/mode.*.tmpadded. Host-specific runtime config by default;git add -fto commit if the user wants the mode choice to follow the repo.CLAUDE.md— new "## Methodology Modes (v1.8+)" section + skill table row + plugin-name header reference..claude-plugin/plugin.json+marketplace.json— version 1.7.2 → 1.8.0; descriptions refreshed to mention methodology modes and "5 of 5 priority gaps closed."
Compass axis status after v1.8.0
| Axis (compass §1 + audit §9) | v1.7.2 | v1.8.0 |
|---|---|---|
| Compounding wiki primitive | #1 | #1 |
| Multi-writer safety | #1 | #1 |
| Retrieval architecture (free tier) | #1 | #1 |
| License / openness | #1 | #1 |
| Methodology support | TIE | #1 ← v1.8.0 |
| Derivative outputs | NO | NO (v2.0 scope) |
| GUI / install ergonomics | NO | NO (v2.5+ scope) |
5 of 7 axes #1. Remaining 2 axes require multi-release effort.
Honest scope acknowledgment
- "Best ever obsidian skill per the priority research" = the 5 priority gaps closed. v1.8.0 reaches this milestone.
- "Best ever in the market" requires v2.0 (derive — audio/quiz/study) + v2.5+ (Community Plugin GUI fork). These are weeks of work per release; v1.8.0 is the foundation, not the substitute.
- The v1.7.0 audit's 24 findings (1 BLOCKER + 6 HIGH + 10 MEDIUM + 7 LOW) are fully CLOSED-or-DEFERRED as of v1.7.2; v1.8.0 inherits a clean audit ledger.
Migration notes
- v1.7.x vaults: no action needed.
wiki-modedefaults togenericwhen.vault-meta/mode.jsonis absent, which is identical to v1.7 behavior. The mode-awareness sections in wiki-ingest/save/autoresearch are no-ops in generic mode. - To adopt a non-default mode:
bash bin/setup-mode.sh(orbash bin/setup-mode.sh --mode <name>). Interactive prompt picks one of LYT/PARA/Zettelkasten/Generic; optionally seeds template folders. - Switching modes does NOT auto-migrate existing files. Manual migration via file manager or
git mv.
[1.7.2] - 2026-05-17 (SSS+ convergence — closes every audit finding)
Patch release closing every remaining MEDIUM (M1-M10) and LOW (L1-L7) finding from the v1.7.0 audit. Combined with v1.7.1 (which closed the 1 BLOCKER + 6 HIGH), this means the v1.7.0 audit's full 24-finding ledger is now CLOSED or formally DEFERRED-with-rationale. Plan: docs/audits/v1.7.2-sss-plus-plan.md.
Added
agents/verifier.mdtwo new "always check" cuts (83d18ea): #5 Git hygiene (any new written path NOT in .gitignore → HIGH; would have caught the v1.7.1.vault-meta/hook.logself-pollution bug mechanically); #6 Additive-without-pruning (ifgit diff --shortstat main..HEADshows >+500 LOC with <50 deletions, flag MEDIUM). Verifier learns from what its prior dispatches missed.- Unicode multilingual test (
8c219fb):tests/test_bm25_index.py::test_tokenize_unicode_multilingualcovers Cyrillic, CJK, accented Latin, pure-emoji skip, mixed ASCII+non-ASCII. --explain+--no-reranktest coverage (a80ae61):tests/test_retrieve.pynow exercises both flags hermetically (test_explain_flag_adds_diagnostics_block + test_no_rerank_flag_strategy_bm25_only). +6 assertions.- Newline + carriage-return path rejection tests (
d0db354):tests/test_wiki_lock.sh+2 assertions for the new validate_path rejections. [i/total]progress prefix on contextual-prefix.py per-page logs (59cd7c8): Stage 1 over 47 pages with tier-2 (claude-cli) takes 5+ min; user now sees position, not just opaque per-page lines.
Changed (defensive-input + correctness fixes)
- M2 — Unicode-aware BM25 tokenizer (
8c219fb):[A-Za-z][A-Za-z0-9'\-]*→\w[\w'\-]*withre.UNICODE. CJK / Cyrillic / Devanagari / accented Latin vaults previously had content silently dropped at index time. Same regex mirrored inscripts/baseline-v16.pyso v1.6/v1.7 retrieval comparisons stay apples-to-apples for non-ASCII corpora. - M3 —
scripts/rerank.pyoff-localhost error rewritten (d0db354): from "pass --allow-remote-ollama" to a 3-option breakdown citing the actual host, concrete recovery steps for each option, and the canonical paths. - M4 —
scripts/wiki-lock.sh validate_path()rejects newlines + carriage returns (d0db354): would have silently corrupted the meta-lock line format. - M5 —
scripts/retrieve.py import_sibling()wraps in try/except (d0db354): ImportError / SyntaxError / AttributeError now produce friendly diagnostics with recovery hints (bash bin/setup-retrieve.sh --check) instead of bare Python tracebacks. Pre-checks target file existence. - M6 —
scripts/contextual-prefix.pyempty-body WARN (d0db354): frontmatter-only pages now produce explicitWARN: ... has no chunkable body contentinstead of silentchunks=0. - M7 —
scripts/rerank.py save_cache()non-blocking lock + 3-attempt retry (d0db354): replaces blockingfcntl.LOCK_EX(no timeout) withLOCK_NB+ 100ms retry; falls back to unlocked write with WARN if all 3 attempts fail. Prevents indefinite hang on NFS / FUSE mounts without lock support. The temp+rename pattern provides write atomicity even unlocked. - L2 — Stage 1 progress indicator (
59cd7c8): per-page log lines now carry[i/total]prefix. - L6 —
scripts/wiki-lock.shheader doc (59cd7c8): explicit distinction betweenSTALE_AFTER_SEC(per-acquire, default 60s) andclear-stale --max-age(admin reaper, default 3600s). Both time-since-acquire but distinct scopes. - L7 —
scripts/bm25-index.pyBM25 divide guard (59cd7c8):avg_dl_safe = avg_dl or 1.0. Currently unreachable but invariant-by-construction now rather than emergent-from-reachability.
Removed (kernel: "delete more than you add")
- L3 — dead
bm25_score()function (eafd449): 28 lines, never called, self-documented as "placeholder; real score computed in query()". Removed. - L4 —
--rebuildflag stub onscripts/bm25-index.py build(eafd449): declared but never read; was reserved for incremental mode not in v1.7. Per kernel: no abstraction without 3 real callers. - L5 —
--no-bm25flag stub onscripts/retrieve.py(eafd449): returnedEXIT_USAGEwith "reserved for v1.7.x vector-only mode." Same kernel principle.
Honest accounting
- Net LOC delta
main..HEADis+6009 / -30, NOT meeting the plan §1 acceptance criterion (≤+5000 OR ≥-200). Per plan §4 failure clause: "Do not invent prunes to game the metric." Honest decomposition: ~5500 LOC across new files alone (4 new scripts + 4 new tests + 2 new skills + 1 new agent + 1 new bin + ~2200 LOC docs). The v1.7 line was net-new feature substrate, not a refactor; v1.6 had no equivalent of a retrieval pipeline, lock primitive, transport detector, or contextual prefix generator to delete. Kernel-application axis ceilings at ~92-95 for the v1.7 line; the deduction is structural to building substrate, not negligence. Documented indocs/audits/v1.7.0-audit-2026-05-17.md§10.2. - M9 (bounded-slices: 4 skills touched by both §3.2 and §3.4) is documented as a process note in audit §10.3; not a code-level fix.
- M11 (synonym category benchmark tied 60%/60%) persists post-tokenizer-change; v1.7 hybrid neither helps nor hurts on this category. Filed for v1.7.x rerank threshold tuning.
- M12 (negative-query precision) was tied at 40%/40% in v1.7.0; post-Unicode-tokenizer it's 40%/20% (+20pp). Empirically closed by the tokenizer change.
- L1 (§3.1 substrate +17/-5 no deletion) documented as defensible process note in audit §10.3.
Benchmark refresh (full 50-query corpus, v1.7.2 measurement)
Run via python3 scripts/benchmark-runner.py:
| Category | N | v17 top-1 | v17 top-5 | v16 top-1 | v16 top-5 | Δ top-1 |
|---|---|---|---|---|---|---|
| cross-page | 10 | 20.0% | 80.0% | 30.0% | 40.0% | -10.0pp |
| derived | 25 | 68.0% | 88.0% | 12.0% | 24.0% | +56.0pp |
| negative | 5 | 40.0% | 80.0% | 20.0% | 80.0% | +20.0pp |
| partial-recall | 5 | 60.0% | 100.0% | 20.0% | 60.0% | +40.0pp |
| synonym | 5 | 60.0% | 100.0% | 60.0% | 100.0% | +0.0pp |
| TOTAL | 50 | 54.0% | 88.0% | 22.0% | 44.0% | +32.0pp |
Error reduction: +41.0% vs the ≥30% ship gate — PASS.
The +32pp/41% slightly beats the v1.7.0 audit's reported +30pp/+39.5%; the Unicode tokenizer change made baseline-v16.py marginally weaker (−2pp on its top-1) which counts as a delta improvement for v1.7. cross-page top-1 regression vs audit (was +0pp, now −10pp) is within benchmark noise on N=10; cross-page top-5 stayed at 80% which is the synthesis-relevant metric.
Migration notes
- v1.7.1 vaults: no action needed. All v1.7.2 changes are backward-compatible behavior improvements.
- Re-running
bash bin/setup-retrieve.shis recommended (rebuilds BM25 index with the new Unicode tokenizer; multilingual content that was silently dropped will now be indexed). - The v1.7.0 audit's full 24-finding ledger is now CLOSED-or-formally-DEFERRED. v1.7.2 marks the end of the v1.7 line's audit-debt remediation cycle.
[1.7.1] - 2026-05-17 (audit-driven patch)
Patch release closing the 1 BLOCKER + 6 HIGH findings from the v1.7.0 audit (docs/audits/v1.7.0-audit-2026-05-17.md). All v1.7.0 features remain available; the changes are guard-rails and one new agent.
Fixed
- BLOCKER B1 — Data egress without consent (
ca68bb6).scripts/contextual-prefix.pynow requires an explicit--allow-egressflag (default off) before selecting tier-1 (Anthropic API) or tier-2 (claude CLI subprocess). Without the flag,pick_prefix_tier()returns"synthetic"regardless ofANTHROPIC_API_KEYorclaudebinary presence.bin/setup-retrieve.shadds a y/N consent prompt before any non-synthetic Stage 1 run.skills/wiki-retrieve/SKILL.mdadds a Data Privacy callout (also closes H6). Mirror of the existingscripts/tiling-check.py:351--allow-remote-ollamaprecedent. - H1 — Stage 1 failure had no rollback path (
4837d4f).bin/setup-retrieve.shnow captures Stage 1's exit code, exits 5 on non-zero, and prints a 3-option recovery hint (incremental resume, full wipe, single-page re-process). Stage 2 only runs after Stage 1 success. - H2 —
make clean-test-statedidn't remove v1.7 artifacts (7e1f187). Extended the target to remove.vault-meta/chunks/,.vault-meta/bm25/,.vault-meta/locks/,.vault-meta/transport.json,.vault-meta/.wiki-lock.meta, and the related.tmpfiles. The Makefile target now matches the v1.7.gitignoreset. - H3 — PostToolUse hook swallowed lock-check errors (
7120970). Restructuredhooks/hooks.jsonto capture the wiki-lock script's exit code directly (not via a pipeline), defer the auto-commit on any non-zero rc, and only rungit addafter both the rc check and the non-empty-list check pass. - H4 — No verifier-agent pass at workstream gates (
3ea443f). Addedagents/verifier.md— a read-only (Read/Grep/Glob/Bashonly; noWrite/Edit) pre-commit specialist that reads the staged diff, applies the /best-practices six-cut + agent kernel, and returns findings in four tiers (BLOCKER/HIGH/MEDIUM/LOW). CLAUDE.md "Pre-commit verifier (v1.7.1+)" section references it as the recommended pre-commit step. - H5 —
detect-transport.shJSON escaping was shell-only (722ac97). Added ajson_escape()helper that pipes throughpython3 -c json.dumps, applied toCLI_VERSION(bothobsidian-cliandobsidian-binary paths). The heredoc now emits${CLI_VERSION}without surrounding quotes since the helper produces a pre-quoted JSON string. Defense in depth against pathological upstream version output (backslashes, tabs, newlines, control chars). - H6 —
skills/wiki-retrieve/SKILL.mdhad no Data Privacy section (bundled with B1 inca68bb6). New section at the top of the skill body documents the two-layer egress guard (--allow-egressflag + setup-retrieve prompt) and points back to thetiling-check.pyprecedent.
Added
agents/verifier.md— pre-commit specialist; see H4 above.scripts/baseline-v16.py+scripts/benchmark-runner.py— audit instrumentation that ran the 50-query retrieval benchmark documented inwiki/meta/retrieval-benchmark-v1.7.md. Result: v1.7 top-1 54.0% vs v1.6 baseline 24.0% (+30pp); error reduction +39.5% vs the ≥30% gate. Future audits can re-run withpython3 scripts/benchmark-runner.py.docs/audits/v1.7.0-audit-2026-05-17.md(481 lines) — the full audit report.docs/audits/v1.7.1-fixes-plan.md— the sequenced 6-commit roadmap this release executes.
Changed
- Versions bumped to 1.7.1 in
.claude-plugin/plugin.jsonand.claude-plugin/marketplace.json(description fields refreshed to mention the verifier agent and the egress-consent guard). CLAUDE.md"Pre-commit verifier (v1.7.1+)" section added; "Concurrency (v1.7+)" section retained verbatim.
Polish (post-fix self-audit refinements)
After the 7 v1.7.1 commits landed, a re-pass with agents/verifier.md against the slice surfaced 2 MEDIUM + 3 LOW polish items. All closed in one follow-up commit:
scripts/detect-transport.sh— splitCLI_VERSION_RAW(human log line) fromCLI_VERSION(pre-quoted JSON for the heredoc). The JSON-escape fix from H5 made the log lineCLI: obsidian-cli ("1.12.0")carry visible quotes; the split keeps both paths clean. Also:CLI_VERSION_RAW=""initialized in the top-of-script init block alongsideCLI_PRESENT,CLI_BINARY,CLI_VERSION(defense in depth underset -euo pipefail; closes a latent unbound-variable risk that worked today only by bash short-circuit semantics).agents/verifier.md—tools:field kept as CSV (Read, Grep, Glob, Bash) to match in-repo precedent (wiki-ingest.md,wiki-lint.md). Both CSV and YAML list are accepted forms across~/.claude/agents/(audit-* use CSV, blog-* and challenge-auditor-* use YAML list), but the three local repo agents are CSV, so consistency-with-siblings is the deciding factor. The polish commit initially converted to YAML list per a prior verifier recommendation that didn't cross-check sibling files; reverted in the follow-up after deeper chair probe.bin/setup-retrieve.sh— refreshed the header docstring (lines 13-26) to mention--allow-egressand the consent gate. Inline comments at line 121 were already correct; the file-top doc was the stale one.scripts/contextual-prefix.py— docstring ongenerate_prefix()explaining the deliberate asymmetric fallback (api→cli→synthetic, but cli→synthetic only — climbing from cli to api would silently spend money the user did not authorize).hooks/hooks.json— breadcrumb log to.vault-meta/hook.logon the rare non-zeroLOCK_RCdefer path. Verified with concurrency (10 parallel hook fires → 10 atomic lines, no interleaving; line length <PIPE_BUF), no format-string injection (printf uses literal format with %s placeholders), filesystem-failure edge cases preserveexit 0(defer behavior intact)..vault-meta/hook.logadded to.gitignoreso the breadcrumb file is never auto-staged by the same PostToolUse hook (closes a self-pollution loop that would have surfaced on the first non-zeroLOCK_RCevent).
Migration notes
- v1.6 vaults: no action needed. The new components are opt-in or read-only.
- v1.7.0 adopters who provisioned
bin/setup-retrieve.shand hadANTHROPIC_API_KEYset: the nextbin/setup-retrieve.shrun will prompt for consent before proceeding with the non-synthetic tier. Decline to keep all data on-machine (tier-3 synthetic), accept to preserve the prior behavior. Existing chunks/ data is unaffected either way. - Test suite:
make testcontinues to run 7 hermetic suites (~1162 assertions). Zero ollama, zero network dependency.
[1.7.0] - 2026-05-17 (Compound Vault refoundation)
The v1.7 line, codenamed Compound Vault, refoundations the plugin around four pillars from the May 2026 gap analysis: substrate alignment with kepano/obsidian-skills, Obsidian-CLI-native transport, contextual + hybrid retrieval, and safe multi-writer ingest. v1.6 vaults that never install the new opt-in components see no behavior change. Full design rationale in docs/compound-vault-guide.md.
Added
- §3.2 Default transport —
skills/wiki-cli/SKILL.md(recipe reference for Obsidian CLI),scripts/detect-transport.sh(writes.vault-meta/transport.jsonsnapshot; auto-stale at 7d),wiki/references/transport-fallback.md(canonical decision tree). 5 transport-aware skills (wiki-ingest, wiki-query, save, autoresearch, wiki-lint) gained "## Transport (v1.7+)" sections. - §3.3 Hybrid retrieval pipeline (wiki-retrieve, opt-in) — implements Anthropic's Sept 2024 Contextual Retrieval pattern as agent-skill plumbing. 4 new scripts:
scripts/contextual-prefix.py(3-tier auto: Anthropic API → claude CLI subprocess → synthetic),scripts/bm25-index.py(Okapi BM25, k1=1.5 b=0.75, pure stdlib, flock-guarded),scripts/rerank.py(cosine on nomic-embed-text via ollama, embed-cache),scripts/retrieve.py(orchestrator: BM25 top-20 → rerank top-5 → page dedupe).bin/setup-retrieve.shopt-in bootstrap.skills/wiki-retrieve/SKILL.mddocuments the architecture and cost ceiling (~$12/1000 docs per Anthropic). Wired intoskills/wiki-query/SKILL.mdvia "## Retrieval (v1.7+)" section with graceful exit-10 fallback to the v1.6 hot→index→drill read order. - §3.4 Multi-writer safety (wiki-lock, core) —
scripts/wiki-lock.shper-file advisory locking. Age-based staleness (defaultSTALE_AFTER_SEC=60), cross-process release allowed by design. 4 skills (wiki-ingest, wiki-fold, save, autoresearch) gained "## Concurrency (v1.7+)" sections with concrete acquire/release recipes. The latent corruption bug from v1.6 — documented but unenforced inskills/wiki-ingest/SKILL.md:259-264— is now closed. - New skills (2):
wiki-cli(§3.2) andwiki-retrieve(§3.3). Total skill count is now 13. - New scripts (6):
detect-transport.sh,contextual-prefix.py,bm25-index.py,rerank.py,retrieve.py,wiki-lock.sh. - New tests (4):
tests/test_bm25_index.py(~30 hermetic assertions including BM25 monotonicity and IDF positivity),tests/test_retrieve.py(22 hermetic assertions including end-to-end subprocess test),tests/test_wiki_lock.sh(14 hermetic assertions including age-based stale reap),tests/test_concurrent_write.sh(6 hermetic assertions; the critical multi-writer correctness gate — 10 parallel workers, no losses, no garbled lines).make testnow runs 7 suites with zero network and zero ollama dependency. - New docs:
docs/compound-vault-guide.md(omnibus v1.7 guide),wiki/references/transport-fallback.md(transport decision tree). - Makefile targets:
test-bm25,test-retrieve,test-lock,test-concurrent,setup-retrieve.
Changed
- §3.1 Substrate hard-prefer on
kepano/obsidian-skills—skills/obsidian-markdown/SKILL.md,skills/obsidian-bases/SKILL.md, andskills/canvas/SKILL.mdupgraded from soft-defer ("if kepano installed, prefer it") to hard-prefer ("this is a fallback; prefer kepano"). Architectural behavior unchanged; signal sharpened.skills/defuddle/SKILL.mddocumented as canonical (kepano does not ship a defuddle skill)..claude-plugin/marketplace.jsondeclaresrecommendedCompanions: [kepano/obsidian-skills]with install hint. hooks/hooks.jsonPostToolUse — added a lock-in-flight check beforegit add. Whenbash scripts/wiki-lock.sh listreturns non-zero count, the auto-commit defers. Prevents torn commits during multi-agent ingest. Falls through gracefully ifwiki-lock.shis absent.agents/wiki-ingest.md— rewrote the "Sub-agents MUST NOT" section. The prohibition on callingallocate-address.shfrom sub-agents is preserved (counter monotonicity). A NEW rule is added: sub-agents MAY now write pages, but MUST acquire locks first.- Versions synced to 1.7.0 across
plugin.jsonandmarketplace.json.
Migration notes
- v1.6 vaults need no action. The new components are opt-in (
bash bin/setup-retrieve.shfor hybrid retrieval) or universally beneficial (wiki-lock is core; no setup needed). The plugin remains MIT-licensed; no paid tier introduced. - To install the recommended companion:
claude plugin marketplace add kepano/obsidian-skills. Existing local fallbacks remain functional without it. - Estimated upgrade time: 5 minutes (substrate auto-detected; transport auto-detected on first session; retrieval requires explicit
bash bin/setup-retrieve.sh).
Out of scope for v1.7 (deferred to v1.8+)
- Methodology modes (LYT / PARA / Zettelkasten / Generic via
wiki-modeskill) — planned for v1.8. - NotebookLM-class derivative outputs (audio, quiz, flashcards, study guide via
wiki-derive) — planned for v1.9 or v2.0. - Multimodal ingest adapters (YouTube, PDF, EPUB, image OCR via
wiki-ingest-multimodal) — planned for v1.9. - Periodic review artifacts (
wiki-review) — planned for v1.8.
[1.6.0] - 2026-04-24
Added (DragonScale Mechanism 4, opt-in)
- Boundary-first autoresearch:
scripts/boundary-score.pycomputes(out_degree - in_degree) * recency_weightacross the wikilink graph and emits top-K frontier pages./autoresearchinvoked without a topic now offers the top-5 frontier pages as research candidates when the vault has adopted DragonScale. tests/test_boundary_score.py— 35 unit tests covering frontmatter parsing, recency weight, wikilink extraction (with code-block guard), graph construction, scoring, CLI interface.make test-boundarytarget + integration intomake test.
Changed
skills/autoresearch/SKILL.md— new Topic Selection section with three paths: explicit (A), boundary-first (B, opt-in), user-ask (C, default without DragonScale).commands/autoresearch.md— no-topic usage documented for both modes.wiki/concepts/DragonScale Memory.md— Mechanism 4 flipped from NOT IMPLEMENTED to shipped; exact scoring formula and "what is NOT included" callout added. Version bumped to v0.4.- Version synced to 1.6.0 across plugin.json and marketplace.json.
[1.5.1] - 2026-04-24 (Phase 3.6 hardening)
Fixed
scripts/tiling-check.py:--report PATHnow resolved against VAULT_ROOT and rejected if it escapes (security: prevents hostile or accidental writes outside the vault)..vault-meta/legacy-pages.txt: rollout baseline corrected from 2026-04-24 to 2026-04-23 (matches earliest addressed page in the seed vault).AGENTS.md: wiki-fold listed in the skills table; stale claim that "all skills use only name/description" narrowed to newer skills (older skills still carry allowed-tools for Claude Code compatibility).skills/wiki-ingest/SKILL.md: resolves the internal contradiction between "immutable .raw/" and "maintain .raw/.manifest.json" — user-dropped source documents remain immutable; only the manifest is wiki-ingest-maintained.docs/install-guide.md: version 1.2.0 -> 1.5.0 with a DragonScale optional-install callout.
[1.5.0] - 2026-04-24
Added (DragonScale Memory extension, opt-in)
- Mechanism 1 — Fold operator (
skills/wiki-fold/): extractive, structurally-idempotent rollups ofwiki/log.mdentries into per-batch meta-pages underwiki/folds/. Dry-run via stdout by default (does not trigger PostToolUse auto-commit hook); commit mode explicit. - Mechanism 2 — Deterministic page addresses (opt-in):
scripts/allocate-address.shflock-guarded atomic allocator; newaddress: c-NNNNNNfrontmatter convention; re-ingest idempotency via.raw/.manifest.json address_map.wiki-ingestandwiki-lintskills feature-detect DragonScale setup. - Mechanism 3 — Semantic tiling lint (opt-in):
scripts/tiling-check.pyuses localnomic-embed-textvia ollama to flag candidate duplicate pages by cosine similarity. Banded thresholds (error/review/pass) documented as conservative seeds with manual calibration procedure. wiki/concepts/DragonScale Memory.md— full design spec (v0.3) with four mechanisms, scope boundary, and primary-source citations.bin/setup-dragonscale.sh— idempotent installer that provisions.vault-meta/counter, thresholds, and legacy-pages manifest.tests/— shell + python test suite for the allocator and tiling-check. Run viamake test.Makefile— developer targets (test,setup-dragonscale,clean-test-state).
Changed
hooks/hooks.jsonPostToolUse now stages.vault-meta/in addition towiki/and.raw/so DragonScale runtime state is captured by the auto-commit hook.skills/wiki-ingest/SKILL.mdandskills/wiki-lint/SKILL.mdgained opt-in DragonScale sections behind feature-detection guards; original behavior unchanged for vaults that have not runsetup-dragonscale.sh.agents/wiki-ingest.mdexplicitly forbids parallel sub-agents from calling the allocator (single-writer rule for address assignment).agents/wiki-lint.mdextended to describe Address Validation and Semantic Tiling checks.- Stale
allowed-toolsfrontmatter removed fromwiki-ingestandwiki-lintSKILL.md (kepano convention: onlynameanddescription). - Version strings synced across
.claude-plugin/plugin.json,.claude-plugin/marketplace.json, and documentation.
Security
scripts/tiling-check.pylocksOLLAMA_URLto localhost by default. Remote endpoints require--allow-remote-ollama. Symlinks and vault-root escapes are rejected before any read.
Not in this release
- Mechanism 4 — Boundary-first autoresearch: documented in the spec as a future proposal; no code shipped.
skills/autoresearch/SKILL.mdunchanged.
[1.4.3] - prior
Previous state. See git log for details.