v0.9.0 — a clone is not consent
Two things changed here: when llmwiki runs at all, and whether capture told the truth about what it captured. The first is a required upgrade step — see the bottom.
A clone was enough to make llmwiki read a repository
"Is this repo mine?" used to be answered by the presence of docs/wiki/ — a directory that arrives with any git clone. So cloning a stranger's project was enough to make the installed hooks read its Markdown into your model's context and queue that session's transcript. Nobody made that decision; it came in the tarball.
Activation is now one explicit step per repository:
llmwiki init /path/to/my-project # scaffolds the wiki, records the marker
llmwiki status /path/to/my-project # is it on, and why not
llmwiki disable /path/to/my-project # off again; your wiki files are untouchedThe marker lives in that worktree's .git/llmwiki/, where a clone cannot deliver it and no commit can carry it. It is per-worktree, so trusting one linked worktree never trusts its siblings, and it records the path it was written for — a copied or moved repository fails closed rather than following you. Until init runs, a repository produces exactly zero bytes of cold-start context, no per-turn injection, and no captured sessions. After it runs, there are no further prompts, ever.
99% of Claude sessions never reached the wiki
The router identified a transcript record by reading its type field first. Real records often carry their content before their type, and those were dropped — silently, since the daemon reported healthy and the queue kept filling. The loop looked alive while almost nothing reached the wiki. Routing now reads the whole record, and the shapes that broke it are pinned by fixtures derived from real transcripts (keys, nesting and types preserved, every value replaced).
Codex threw hook output away without saying so
Plain-text hook output was accepted by the hook and discarded by the harness — no error on either side. Both ends now agree on a JSON envelope. OpenCode and Claude were unaffected but share the same path.
Capture could die quietly
llmwiki doctorgrew a[capture]section: enrolled repositories, queue health, and the repositories that hold a wiki but are not enrolled- when the harness states the session id, that now wins over inferring it from a filename
- an older llmwiki's leftover logs could make the engine refuse its own state directory
- capture buckets normalise to the same wiki root that reads use, NFC/NFD filename splits included
- hooks bind to the repository the session is actually working in, ending a read-here/write-there split
- the daemon re-installs read hooks that a live session removed
Retrieval narrowed the further you got from English
Two thresholds were counted in characters, which is a different bar in every language — the same sentence is far fewer characters in Korean or Japanese than in English, so non-Latin sessions quietly fell under the floor. On one corpus a Korean session's recall went from 1 of 7 prompts to 5 of 7.
Install and retention now report what happened, not what was attempted
daemon/install.sh verifies the service with launchctl list instead of assuming the load worked. Retention warnings count only sessions that can still be saved, the backlog shows the time left before the harness deletes a transcript, and a ledger records what expired. Synthesis lines — compact summaries, sidechains — no longer enter the pool of "things the human said".
Uninstall
./setup.sh --uninstall # every hook, plugin, command, launcher and service llmwiki installed
./setup.sh --uninstall --purge-data # …and its local runtime state as wellRemoval is by ownership, not by restoring a backup: entries llmwiki installed are removed and everything else in your harness configuration is left exactly as it is. Run it from the installed clone before you move or delete that clone. Your wikis are never touched — docs/wiki/ is ordinary Markdown in your own repositories.
Upgrading — one required step. Enrollment is new, and no repository is grandfathered in: after
git pull && ./setup.shevery project you were already using goes inert until you turn it on once:
llmwiki init /path/to/that-projectllmwiki doctor lists exactly which ones need it ("N repositor(ies) hold a wiki but are not enrolled"), and setup.sh runs doctor for you at the end. Nothing under docs/wiki/ is touched either way.
Verified with 752 tests, tsc --noEmit, and a clean-clone consumer run (clone → bun install → bun test → setup.sh --dry-run).