Releases: GD4AI/obsidian-llm-wiki
Release list
1.27.2
🌟 Karpathy LLM Wiki v1.27.2
Highlights
PATCH with no new features and no new settings — 23 bug fixes, two of them closing content-loss classes that could quietly damage a page, and one regression the pair introduced between them. If you are on v1.27.1, this is a straight upgrade.
- A body rewrite cut off at the token limit is no longer written over the page (Issue #704, PR #705). When a model stopped because it hit
max_tokens, the partial answer was saved as if complete. Measured on a rebuilt vault: 13 body rewrites grew past 8 KB, 10 of them within four minutes of a"finish_reason": "length", one page going 32 KB → 127 KB with 300–760 provenance footnotes and 2463 of 2703 prose links dead. Truncation is only knowable after the fact, so it is checked there — at the three call sites that overwrite an existing body, the frontmatter write is kept, the existing body is restored, a warning is logged, and the truncated text is discarded. - Provenance footnote brackets are repaired before they can cost you a paragraph (PR #702). A page's inline source marker (
^[Source: [[Name]]]) is what decides which paragraph a rewrite may drop, and the model gets the brackets wrong often enough to matter — measured over a rebuilt vault, about a third of markers came back with two closing brackets instead of three, one in five with the opening bracket doubled. Every malformed form is invisible to the guard, so its paragraph lost its owner and became droppable. The write gate now repairs the four written forms; the label is carried through verbatim and the semantic half (which paragraph, which source) is untouched. - The end-of-run link repoint now sees every page it was meant to (Issue #713, PR #714). Two producers wrote
updated_pagesin different shapes — vault paths for created pages, bare page names for related-page updates — and the repoint pass filters on.md, so every bare name was skipped in silence. Fixed at the source, plus a second fix in the same change: updated pages no longer render as dead links in the ingest log. - Corporate and gateway OpenAI-compatible endpoints can ingest again (Issue #711, PR #712). A gateway that rejects the whole
response_formatenvelope without namingjson_schemamatched no classifier, so the rejection surfaced raw and the provider was unusable behind such a proxy. It now engages the existing demotion chain. - Strict structured output is a negotiated tier at the schema boundary (Issue #658, PR #686). A provider that rejects the strict dialect demotes one tier instead of failing the call.
- Delete Empty Stubs collects the stubs it is named for, and leaves the deliberate ones alone (Issue #678, PR #691). Three different writers set
stub: true; one of them writes a dead-link placeholder on purpose. The collector now requires a stub that is actually empty. - Ingest lifecycle is released when a file is skipped (Issue #688, PR #690). The status bar no longer stays stuck after a skip or a cancel.
- A regression found and fixed before it shipped (PR #722). Two of the fixes above touched the same function — one added a guard returning a boolean, the other changed that function's return type to a string path. Each passed the full test suite on its own branch; merged, they left
mainfailing type-checks for five consecutive commits. The runtime half was worse than the type error: the recorded value becametrue, which the repoint filter drops silently — the exact bug #713/#714 had just repaired, reintroduced on the path the guard was added to protect. Fixed at the root, with the test that had pinned the old contract updated to pin the new one. - Documentation and repository hygiene. The repository links now point at the organisation that owns the project (
GD4AI/obsidian-llm-wiki) rather than the pre-move account; ten broken in-page links across the READMEs were found and fixed; and the guard that pins the README link prefix was rewritten — its previous form could not match anygithub.comURL at all, which is why the stale owner had survived two releases.
What's in this release
Fixed
- A rewrite cut off at the token limit is not adopted (Issue #704, PR #705). New
captureFinish()inllm-sdk/finish-reason.tsreturns anonFinishsink plus atruncatedgetter; only'length'counts, and a client that reports nothing leaves the reason'unknown', so legacy and mock clients keep their exact behaviour. Guarded atmerge-body,reviewed-appendand the related-page rewrite. analysis.updated_pagescarries one shape (Issue #713, PR #714). De-duplicated at the fill site rather than in each reader, which also keeps the cancelled and failed paths correct — they hand the list straight toonDonewithout passing a reader. The ingest log'spageLinks()now strips the wiki folder prefix for updated pages too.- Provenance markers normalised on the content write gate (PR #702). Four malformed written forms repaired to the canonical shape; idempotent, and a no-op returning the same reference when the content holds no wikilink. Guards keep ordinary wikilinks whose name contains a colon out of the rewrite.
- Gateway
response_formatrejections classified (Issue #711, PR #712). The strict-dialect body stays owned by its existing classifier; negative cases keep the match from widening into a generic 400 catch-all. - Strict structured-output demotion (Issue #658, PR #686).
LLMClientgains anoutputModeofjson_schema/json_schema_strict/json_object/text_prompt. - Delete Empty Stubs predicate (Issue #678, PR #691).
isStubPage(fm) && isEmptyStub(content); mutation-verified, and the tests that asserted the opposite of their own names were corrected. - Two contradiction paths only the model could feed removed (Issues #604, #666, PR #684).
- Source page head stamped from code (Issues #679, #670, #661, PR #681). Title, note path and date are no longer copied through the model.
- Skipped file releases the ingest lifecycle (Issue #688, PR #690).
- One label table for the ingest log (Issue #667, PR #685). Three supported languages had been falling back to English.
- One-token JSON defects repaired before spending a model call (Issue #682, PR #683).
- Related-sibling cap holds at three (Issue #644, PR #645). Siblings rescue an orphan; they no longer form a clique per note.
- Smaller correctness fixes. Case folded when checking a page's own aliases (#674, PR #675) · the create path's alias floor applied on the source path (#671) · a two-character name created rather than sent to semantic dedup (#661, PR #663) · Related sections rendered after a complementary append (#659, PR #660) · model-invented
sources:entries dropped before the true one is stamped (#650, PR #651) · a baresources:line no longer emits a stray[[]](#648, PR #649) · a cancel reaches the running model call and stops at the next page write (#646, PR #647) · frontmatter seams no longer grow a blank line on every call. - Schema suggestions read as proposals, and the schema diff modal no longer crashes on first render (Issues #594, #593, PRs #655, #654).
Changed
- The Five-Gate now runs on pushes to
main, not only on pull requests (PR #698). Merged commits were previously unverified; this is the trigger that surfaced the regression described in Highlights. package-lock.jsonis gated againstpackage.json(PR #693), and the lockfile pair is regenerated at release time (PR #692 regenerated only the npm side, which let the pnpm lockfile drift silently).
Docs
- Where a document is processed, per PDF path (Issue #657, PR #694). Both the English and Chinese guides now state that residency is US by default for Anthropic, OpenAI and Google, the configured region for Bedrock, and that OpenAI offers EU residency.
- Repository links migrated to the new organisation. All repository URLs across 25 files now point at
GD4AI/obsidian-llm-wiki; the sibling CLI repository did not move and its links are deliberately unchanged. - Ten broken in-page anchors fixed across the eleven READMEs, plus maintainer notes on review and release practice.
Dependencies
actions/checkout4 → 7 ·pnpm/action-setup4 → 6 ·actions/setup-node4 → 7 ·actions/attest-build-provenance1 → 4 ·vitest4.1.10 → 5.0.0 ·yaml2.8.3 → 2.9.0.
Upgrading from v1.27.1
If you installed via Obsidian's Community plugins flow (the normal case), this release appears as a one-click update in Obsidian Settings → Community plugins. Click Update.
There is no migration and no default-behaviour change in this release: no new settings, no renamed settings, no file-format change, and no change to minAppVersion (1.11.4). The only visible difference on an existing vault is the set of pages that are no longer overwritten by a truncated rewrite.
What's accepted (and why)
- One Obsidian review-bot warning is accepted, not fixed. The bot reports "README links to another repository with the same name". After the repository migration, the only remaining such link is the sibling CLI repository (
obsidian-llm-wiki-cli): it is owned by the pre-move account, and its name begins with this repository's name, which is what the rule matches on. The link is correct — that repository genuinely lives there and has not moved. Moving it is an organisation-level decision, not part of this patch, so the warning is recorded here rather than silenced by deleting a working cross-reference. The README prefix guard was simultaneously rewritten, because its previous form could not match anygithub.comURL and therefore could never have caught this. - Known issue, not fixed here, no fix pending: ingestion can hang on a single file (Issue #703). Reported against v1.27.1 on Windows with DeepSeek. Cancel does not reach the blocked extraction, so the run must be ended by restarting Obsidian; no data ...
1.27.1
🌟 Karpathy LLM Wiki v1.27.1
Highlights
PATCH that turns the Related sections into deterministic output — the model no longer transcribes lists it was handed — and closes the rewrite-loss classes the wave-B audit found. 46 merge commits / 194 files / +10487 / −3257 / 3993 tests passing. No breaking changes, no new required settings, no migration.
- Related lists are now deterministic (Issue #635, PR #636). Siblings born from the same note link each other; a related name the vault already has a page for is written under that page's own title and folder; the two Related sections are rendered from the typed lists instead of transcribed by the model. Measured on a 413-note vault rebuild: dead related entries 24% → 1%, pages without a live outgoing link 103 → 0, sibling lists complete 246/246. Unicode-safe end to end.
- A paragraph another source footnoted survives a rewrite (PR #631).
guardBodyRewritenow restores sourced paragraphs a different-source rewrite dropped — 571-pair replay: 120 paragraphs restored, 164 footnotes re-attached. - Folder-wrong links re-pointed vault-wide (Issue #624, PR #626). 314 links corrected — prose, source-page sections, plus a new end-of-run pass over every page the run wrote.
- The per-step thinking policy now reaches the stream path (Issue #627, PR #629). The Query Wiki answer the user waits for was thinking 43 of 55s while the keyword call sent
reasoning_effort: none; stream now honourstaskPolicies. - Vault dates are local calendar dates, not UTC (Issue #611, PR #612). All 17 date-write sites route through
localDateStamp()— east of UTC, days no longer start stamped with yesterday. - Two gates before a contradiction record (Issue #609, PR #610). The page sentence must exist AND the source must hold the claim — measured 7 of 9 records were previously false.
- Query no longer hides the page the user named (Issue #623, PR #625). Unicode-aware tokenizer + word-start matching + PPR-ranked merge fixed a 3,025-page German vault loading Kahneman while "Creatin" was absent.
- Three-phase repo audit cleanup (PRs #632/#633/#634). 8 no-op fixes, one SDK wrap contract, T1/T3 lossless pass (−82 net LOC, 3932→3932 tests).
- 8 fast-uri Dependabot alerts closed at the root (PR #637). fast-uri
^3.1.7, redundant override dropped, CIpnpm auditgate added,.github/dependabot.ymlweekly auto-PRs — the fix path no longer depends on a human noticing an alert.
What's in this release
Fixed
- Related sections rendered from the lists, not the model (PR #636, Issue #635). Three deterministic layers —
core/related-shaping.ts(sibling edges by kind, vault-answering names to their own title+kind, tag values dropped against the active vocabulary, unanswered names kept and counted),core/related-sections.ts(sections written from typed lists; vault path when known, planned path otherwise; rewrite-kept entries re-resolved in front, one target once across both sections; everything else byte-identical),page-factory/related-links.ts(one helper, three call sites collapse to one line each). Default behaviour change without a switch, argued and five-line opt-in available. - Sourced paragraphs restored across rewrites (PR #631).
preserveSourcedParagraphsinsrc/core/paragraph-provenance.tsmatches footnoted paragraphs into the rewrite by word overlap;guardBodyRewritecomposes sections + sourced paragraphs + H1 guards. - Folder-wrong links corrected everywhere (PR #626, Issue #624).
correctRelatedLinkPrefixesre-points in prose + source-page sections; new Stage 4.5repointLinksAfterRunreads every written page once, resolves folder-typed links against the run's own pages. - Stream path honours per-step thinking policy (PR #629, Issue #627).
createMessageStreamspreadsenableThinkingfromapplyTaskPolicy— root cause of the "streamed answer thinks" report (notb302aab, verified). - Local-calendar dates everywhere (PR #612, Issue #611).
localDateStamp()insrc/core/format.ts; full-ISO instants deliberately untouched. - Two gates before a contradiction record (PR #610, Issue #609). Gate 1
existing_statementchecked against the page; Gate 2 stance as its own small call; demotions never silent. - Stop-word substrings + lex/PPR merge fixed (PR #625, Issue #623).
\p{L}\p{N}\p{M}word runs, word-startneedleHits, PPR-rankedmergeWithPPR. - Mention-only pruning no longer cuts edges to existing pages (PR #621, Issue #620). Candidate gate takes an
isKnownPagepredicate backed bybuildVaultResolver. - Kept-but-collapsed sections restored (PR #618, Issue #617). Below
SECTION_SHRINK_FLOOR→ treated as dropped, previous block restored in place. - Mentions re-emit never shrinks the accumulated block (PR #616, Issue #614). Existing length is the floor.
- Related-page rewrites never land on source pages (PR #615, Issue #613). Lookup scoped to
entities/+concepts/. - Contradiction
source_pageresolved against the page index (PR #602, Issue #601). Never trusted from the model — 3 user notes previously hit. - Merge triage contradictions reach log + report (PR #606, Issue #605).
onContradictioncallback collects both lanes. - Ingest ownership from
source_file, notsources:(PR #596, Issue #595). - Picker shows disk state, not session memory (PR #600, Issue #598).
- Cross-folder dedup routes through the semantic call (PR #589, Issue #588). Folder never decides.
- Preamble cut no longer eats the first section (PR #580, Issue #579 via audit).
- Cancelled ingest no longer reads as completed (PR #583, Issue #582).
- Repetition-loop requires consecutive source occurrences (PR #572, Issue #542).
__proto__duplicates rejected in task policies (PR #571, Issue #543).- Audit phase-1 latent bugs (PR #632). UTC-day site →
localDateStamp(),rulocale gaps, dead code. - Dev-instrument link retarget is no longer a silent no-op (PR #591, Issue #590).
Changed
- Two-gate contradiction lane replaces the model's word (PR #610). See Fixed.
- Contradiction marker lane surfacing (PR #578, Issue #575).
contradictions:marker read back + item-level lane given one (PR #576). contentHashdrift flag (PR #577, Issue #220 Tier 0 read half). Source notes changed since ingest flagged.- Merge calls get the note's own paragraphs (PR #579).
- Heading spacing + blank-line runs normalised at the write gate (PR #581).
minAliasLengththreaded to the create path (PR #559, Issue #558).- Gate link-markup parens no longer miscount (PR #564, Issue #562).
Refactor
- Three-phase repo audit (PRs #632/#633/#634). Phase 1: 8 no-op changes (UTC-day site,
rulocale gaps, deadappendGranularityToPrompt, byte-identicalbuildKnownTargetsfolded,createMergeCtxhelper, test twin folded, graph-cache test renamed). Phase 2:openai-sdk-clientonto canonicalwrapReasoningContent(one wrap contract, missing</thinkescape + idempotence guard). Phase 3:escapeRegExp→ canonicalescapeRegex, 22 tests relocated into__tests__mirrors (zero loss), 12 dead exports privatized,controller.tsreport round-trip collapse (−85L), zero-consumerOUTPUT_MODESdeleted.
Added
- Merge triage contradiction lane surfaced (PRs #576/#578). Item-level contradictions get a lane; the marker's read half shows in lint.
contentHashdrift detection (PR #577). Read half of Issue #220 Tier 0.- Dev-instrument link cache + resolver (PR #591).
retargetLinksToPageworks under the instrument. - Co-maintainer credit (PR #619). manifest/README/NOTICE list DocTpoint.
- CI
pnpm auditgate +.github/dependabot.yml(PR #637). Dependency security is now automated, not human-remembered. - SEO metadata blocks completed across all 11 READMEs (this release). DE/PT/RU/ZH-Hant gained the block EN and the other locales already had.
Docs
- README Marp URL + LICENSE relative links fixed (PR #622, community PR by @NotAFlightRisk).
- Wave-C/B records, audit trio, v1.27.1 prep in CHANGELOG/ROADMAP/MEMORY.
Upgrading from v1.27.0
If you installed via Obsidian's Community plugins flow (the normal case), this release appears as a one-click update in Obsidian Settings → Community plugins. Click Update and you're done — your wiki, settings, and history carry over automatically.
One deliberate default-behaviour change: the two Related sections on generated pages are now written from the typed lists (deterministic) rather than transcribed by the model — the previous behaviour produced a dead link one time in four. Existing pages are rewritten on their next ingest with the corrected links. No settings changed, no migration.
What's accepted (and why)
This release touched zero production code in the release commit itself — v1.27.1's 46 feature commits all passed Gate 1 with eslint-plugin-obsidianmd local lint at 0 errors, and the release prep commit (version bump + docs) changed only non-code files. The Bot-scan surface is unchanged from the v1.27.0 baseline; the pre-existing accepted-structural warnings (128, all documented in the v1.27.0 notes) carry over untouched. Local mirror stands in for the GitHub-hosted Bot pipeline per the v1.26.2 hardening record.
Installation
Install or update via the standard Obsidian plugin flow — your existing wiki is preserved on upgrade.
- From Obsidian — Settings → Community plugins → Browse → search "Karpathy LLM Wiki" → Install (or Update, if you already have it). Then toggle Enable.
- From the marketplace — community.obsidian.md/plugins/karpathywiki → Add to Obsidian.
- Manual — only needed if you want a specific version or are running Obsidian without the in-app marketplace. Download
main.js,manifest.json, andstyles.cssfrom the release assets below into `.obsidi...
1.27.0
🌟 Karpathy LLM Wiki v1.27.0
Highlights
MINOR that adds one new auth path on Bedrock, one new conversion backend (MinerU), and closes the frontmatter-parity chain. 36 merge commits / 181 files / +11197 / −3158 / 3677 tests passing. No breaking changes, no new required settings, no migration.
- AWS Bedrock — three auth modes (Issue #425, PR #540). API key (existing), SSO via hand-rolled IAM Identity Center OIDC, IAM-key. Zero AWS SDK, ≈+10–15 KB. Stage 1
bedrockRegionforwarding bug (every call fell onus-east-1regardless of the user's region setting) rides along as commit 0. PR #540 awaits an account-holding E2E of three isolated constants before full activation. - MinerU multi-format ingest (Issue #404, PR #404). PDF / images / Office docs via online Precise parser; new
markdownConversionBackendsetting. Local native path unchanged. - Source-page verbatim quotes (Issue #496, PR #546). Captured quotes route into
sources/<slug>.md.[MENTIONS-CAPTURE]injection +maxChars: 2000per page (mutation-verified). - Fix Dead Links
leave_itoutcome (Issue #485, PR #545). Default ON; opt-out viafixDeadLinksCreateStub. Unresolvable refs no longer spawn empty stubs. - Per-step
taskPoliciesUI (Issue #525, PR #525).task=mode[:thinking]parsing; text-mode extract baseline wired. CodexoutputModeOverridehonoured (PR #539). - Composite-key probe caches (Issue #551, PRs #552/#553).
TokenKeyProber/ReasoningStripProberkey on(baseURL, model)— fixes the cache-suppression bug across distinct models under the same provider. npm auditHIGH → 0 (Issue #501). Top-leveloverridespinsbrace-expansion5.0.9 andfast-uri3.1.5; lockfiles regenerated per pre-release-gate §2f.2.
What's in this release
Added
src/llm-sdk/bedrock-sso/— hand-rolled AWS SSO + SigV4 for Bedrock (PR #540, Issue #425).bedrockAuthMethodsetting:'api-key' | 'sso' | 'iam', default'api-key'. SSO flow:registerClient→startDeviceAuthorization→completeDeviceAuthorization(polling withslow_down+5s, deadline,AbortSignal).BedrockAuthManagercaches credentials withexpiry − 2minskew, single-flight on expiry, no silent retry storm. Sign-out overwrites SecretStorage + clears in-memory cache (mirrors Codex discipline). Three auth secrets:karpathywiki-bedrock-sso,karpathywiki-bedrock-iam,karpathywiki-bedrock-apikey.- Mineru PDF / image / Office backend (PR #404, Issue #404). New
markdownConversionBackend(native | mineru); MinerU path accepts PDF / PNG / JPG / DOCX / PPTX / XLSX. 11 locale READMEs synced. - Source-page verbatim quotes (PR #546, Issue #496).
buildSourceAnalysispopulates top-levelmentionsCaptured;[MENTIONS-CAPTURE]token injected into per-task prompt;maxChars: 2000per page. leave_itoutcome for Fix Dead Links (PR #545, Issue #485).FixDeadLinksOutcomeenum nowcreate_stub | leave_it; defaultleave_it.- Opt-in
skipMentionOnlyCandidatesingest gate (PR #521, Issue #514). Skips mention-only candidates from dedup prompt; default OFF. - One ranked candidate window for dedup + dead-link (PR #520, Issue #519). Replaces full-list fallback (recall nominal 0/18, cost real — ~40K tokens × 61% candidates). Gate-4-accepted: ~2KB text/page (~5.6MB peak @ 2.8K pages).
- Per-step
taskPoliciesUI (PR #525, Issue #525).task=mode[:thinking]parsing;resolveTaskPolicy(map, task)returns{outputMode, thinking}. minAliasLengthsetting (PR #532). Settings → Advanced, default 2, range 2..6.- Composite-key probe caches (PRs #552/#553, Issue #551). Per
(baseURL, model)instead ofbaseURLalone. - CLI →
tools/dev-instrument/migration (PR #511, Issue #507). Replacestools/llm-wiki-cli/with UPSTREAM DEV-ONLY INSTRUMENT; eliminates 49 of ~52 Obsidian Bot errors. Legacy snapshot attools/legacy/cli-v1.26.4-snapshot. Dev-instrument exit codes 0/1/2 (PR #526). - Schema three-layer delivery (PR #546, Issue #491). Five default-schema sections reach their owning tasks; per-task whitelist fixed;
summarytask writes tosources/<slug>.md.
Changed
extractdefaults to text-mode output on LM Studio / Codex (PR #525, Issue #524).json_schemasilently degrades on those providers; text-mode baseline now wired. Opt-back viataskPolicies *=json.mergeFrontmatterunions incomingtags:(PR #510, Issue #509). Stored tag set no longer depends on source order;incomingTypeTagguards custom vocabulary.- Alias comparison keys NFC-normalised and Turkish-folded (PRs #530/#531/#537, Issues #366 p2/#484/#536). File-naming untouched; create path drops self-named aliases; typed-list folder map keyed on comparison slug (
preserveCaseparam removed). stripUnknownSectionsapplied to generation paths (PR #529). Reviewed pages bypass.- OpenRouter
:variants visible (PR #538, Issue #534). ~79 models including all:freenow show in the catalog. - OpenRouter model-404 no longer a URL fault (PR #535, Issue #533).
isUrlErrordifferentiates transport failure (retry) vs 404 on model id (report and stop). - Test Connection blank-model guard (PR #518, Issue #517).
errorNoModelper-task; probe early-returns. Localised in +11 locales. - OpenRouter Anthropic baseURL fixture fix (PR #516, Issue #515).
- Stream path carries explicit
tasklabel (PR #547, Issue #469). Query Wiki now files underquery-wiki, not'untagged'. cache_controlcontract asserted at wire, not at mock (PR #497, Issue #493 partial).- Type repair at intake (PR #528, Issue #527).
repairTypesAgainstVocabularyfold + short repair call. NoOutputGeneratedErrorreturns in-scope composite (PR #544, Issue #506). Single bad batch no longer loses the whole run; welcome-translate thinking pinned off.- Five-Gate order fix in CI (carry-over, PR #487).
pnpm buildbeforepnpm test(test readsmain.jsfor bundle shape). Bundle smoke test now in Gate 1.
Fixed
- Duplicate-merge passthrough carries unknown frontmatter fields (PR #513, Issue #512). Closes the last #356 parity gap.
- Constraints pass carries block-form unknown fields (PR #523, Issue #522). Parity chain complete.
- Five default-schema sections reach their owning tasks (PR #546, Issue #491). Previously orphaned
summarytask now writes tosources/<slug>.md. - Vault-root picker's exclusion rule applied everywhere (PR #504, Issues #502/#505).
- Codex client honours pinned text mode + spares retry on source-borne loops (PR #539).
- Designator is
(letters, type), not the opposite folder (PR #499, Issue #472). - CHANGELOG records the #504 upgrade note for
/entries (PR #508). docs(notice)brings DocTpoint attribution up to v1.26.4 (PR #498).- Docs orthogonalise CLAUDE/ROADMAP/CHANGELOG per one-fact-one-place (PR #500).
Internal
tools/dev-instrument/run-instrument.mjs:97closes PR #511's leftoverno-unsanitized/methodlint gap (PR #550 follow-up).OUT_PATHis a hardcoded local constant; documentedeslint-disableper Botno-restricted-disableallowance..mjsis out of Bot scan scope by design.pnpmandnpmlockfiles aligned onbrace-expansion5.0.9 +fast-uri3.1.5 (Issue #501). Both pin keys live at top level (overrides) and underpnpm.overrides; lockfiles regenerated from localnode_modules.
Upgrading from v1.26.4
If you installed via Obsidian's Community plugins flow (the normal case), this release appears as a one-click update in Obsidian Settings → Community plugins. Click Update and you're done — your wiki, settings, and history carry over automatically.
New settings (markdownConversionBackend, bedrockAuthMethod, skipMentionOnlyCandidates, minAliasLength, taskPolicies, fixDeadLinksCreateStub) all carry defaults that preserve v1.26.4 behaviour byte-identical. MINOR bump reflects user-visible surface growth (5 new bullets in 11 README Features sections), not breaking changes.
What's accepted (and why)
Local Obsidian Bot pre-review (eslint-plugin-obsidianmd@0.4.2, aligned with latest per CLAUDE.md "Bot alignment (pre-release)" rule) returned 0 errors against the v1.27.0 baseline. 128 warnings are all pre-existing accepted-structural from the v1.26.2 / v1.26.4 baselines: obsidianmd/prefer-create-el × 32, hardcoded-config-path × 25, no-nodejs-modules × 22 (all on tools/ static node:* imports — accepted per eslint.tools-bot.config.mjs), no-global-this × 17 (window / activeWindow shim, partially fixed in PR #550), prefer-window-timers × 5, no-tfile-tfolder-cast × 1. 0 new findings on touched code. The GitHub-hosted Bot pipeline (separate from CI, not a status check) was bypassed this cycle — the local mirror is mature enough to substitute per the v1.26.2 hardening record.
Installation
Install or update via the standard Obsidian plugin flow — your existing wiki is preserved on upgrade.
- From Obsidian — Settings → Community plugins → Browse → search "Karpathy LLM Wiki" → Install (or Update, if you already have it). Then toggle Enable.
- From the marketplace — community.obsidian.md/plugins/karpathywiki → Add to Obsidian.
- Manual — only needed if you want a specific version or are running Obsidian without the in-app marketplace. Download
main.js,manifest.json, andstyles.cssfrom the release assets below into.obsidian/plugins/karpathywiki/, then enable the plugin in Obsidian Settings → Community plugins.
Tests
3677 tests passing (260 files). Up from v1.26.4's 3434 / 235 — +243 across the 17 feature PRs (#404, #425 × 6 test files, #485, #491+#496, #506, #509+#510+#512+#513+#522+#523, #517, #519, #520, #521, #524, #525, #527, #530+#531+#532+#536+#537, #533+#534, #539, #551).
Contributors
- @green-dalii (Greener-Dalii) — Mai...
1.26.4
🌟 Karpathy LLM Wiki v1.26.4
Highlights
A PATCH release that closes six silent-bug-class fixes that surfaced under v1.26.x — most of them invisible to the user until a vault grew past 2,000 pages or a wire-shape changed. The biggest single win: the prompt cache finally lands on the user-message block that Anthropic's render order iterates (not the system block that fell below the 1024-token cache floor). One PATCH-only release train (v1.26.3 → v1.26.4) with 20 merge commits / 3434 tests / +3786 / −1816. No breaking changes, no new required settings, no migration.
-
cache_controlfinally lands on the user-message prefix that Anthropic's prompt-caching render order actually iterates — Issue #449 (PR #464). Anthropic prompt caching renderstools → system → messagesand matches by prefix. DocTpoint's blocking review correctly identified that the v1.26.0 wiring put the marker on the system block (a few KB — below Anthropic's 1024-token cache floor); the 75K-char user-message prefix thatstaticPrefix.lengthactually points at fell after the marker and was never cached. Fix:cacheBreakpointnow splits the first user message's text content atsource-analyzer.ts:404'sstaticPrefix.lengthand emits[prefix + cache_control, suffix]as two text parts — Anthropic sees the marker on the block the offset points at, the prefix cache hits on the next call in the batch. The system block is left as a plain string (truthy-check dropssystem: ''from the wire, eliminating the latent "empty system block consumes one of the four cache breakpoints" risk). Measured on Anthropic Claude Sonnet 4 (cache_control tier): cache-hit rate on the 75K-char user-message prefix went from 0% (marker on wrong block) to >95% on calls 2..N of the batch. Branch D fix included:system ? { system } : {}truthy-check drops the empty-system block from the wire entirely. 5 Issue #449 tests rewritten + 1 new Branch D test added. -
Per-note extraction prompt's slug-list block stops re-sorting on every note — Issue #452 (PR #483). The per-note extraction prompt carries a ~24.5K-token page-list block that lists every slug the run has touched so far. As the run progressed, every new note triggered a full re-sort of this list (a single fresh slug could bubble to the top, invalidating Anthropic's prompt cache for every subsequent note in the batch). Fix: freeze the slug catalog at run start. The list only grows at the end (first-seen order) instead of re-sorting on every note. Measured on the LM Studio (gemma-4-26b-a4b-qat, 2844 slugs) benchmark: 23.50s → 4.39s (4.4×) when new slugs sort into the list; 0.69s when unchanged (cache hit preserved across the batch). Companion to #449: the catalog is now prefix-stable, so the cache_control marker that #449 introduces lands on a block that actually has a stable prefix to cache. Closes #452.
-
LintReportModalstops dragging the LLM analysis section into the modal body — Issue #473 (PR #494).analysis-phase.ts:118was reading the fullwiki/index.md(whose size tracks the vault) on every modal open. The LLM analysis section was supposed to live in the Query UI reasoning panel — not the modal — but the import path put the entire file content into the modal'sadditionalContextpayload. Fix: remove the analysis-section import from the modal entirely; restore the Query UI reasoning render path. Modal no longer grows with vault size (a 5,000-page vault was triggering a 12s modal-open hitch). Closes #473. -
Per-step output mode + thinking policy — Issue #481 (PR #490). On an openai-compatible wire the two are not independent: a
response_formaton the request setsreasoning_tokensto 0 regardless ofreasoning_effort,disableThinking, or the server's own switch. "Let this step think" is therefore not a flag but a decision about the output mode, and it can only be made per step — the pipeline's schema callers (extract, lemma-classify, merge-triage, the dedup pair) and its prose callers (page-generate, source-page, merge-body, related-page, complementary, pdf-convert) want opposite things from the same setting. Fix:task-policy.tsexposestask=mode[:thinking]parsing and aresolveTaskPolicy(map, task)lookup that returns{outputMode, thinking}. Default ='default'on both axes, which means theOutputModeProberpicks the mode exactly as before and the call site's ownenableThinkingargument passes through untouched. Per-call policy (PR #411 F5-B): source-analyzer parent (source-analyzer.ts:386) honors; JSON-repair (source-analyzer.ts:417) does NOT honor — repair needs reasoning budget to understand broken-JSON semantics, disabling produces structurally-valid-but-wrong content. The axis independence lets future comparison runs compare output mode + thinking as a single arm instead ofO(3 modes × 4 thinkings)of separate rebuilds. Closes #481. -
Ingest payload stops growing with vault size — Issue #482 (PR #484, Stages 1+2). Stages 1 (source analysis) and 2 (extraction) were rebuilding the per-page context from the full vault history on every note. The payload grew linearly with vault size and dominated the per-note ingest budget past ~2,000 pages. Fix: Stages 1+2 now trim the per-page context to a stable prefix; later stages no longer rebuild the full vault history. The LLM sees the same per-note content but the request shape is bounded by the static prefix + a per-batch variable suffix (slug catalog + granularity + batchSize + lang hints) — exactly the shape
cacheBreakpoint(#449) expects. Closes #482. -
Contradiction clamping restores withheld content to the user-visible page — Issue #492 (PR #492).
clampPageSectionswas discarding the wholly-withheld sections (when the contradiction record exceeded the 3000-char budget, the tail was silently dropped). Fix: the clamp now uses the section list to keep logical order while still honouring the budget — withheld content is restored to the user-visible page in its original position rather than disappearing from the report. Closes #492.
What's in this release
Fixed
cache_controlmarker landed on the wrong block (Issue #449, PR #464). See Highlights. Anthropic prompt cache hit rate on the 75K-char user-message prefix went from 0% (marker on system block, below 1024-token floor) to >95% on calls 2..N. Branch D fix: emptysystem: ''no longer consumes an Anthropic cache breakpoint. 5 Issue #449 tests rewritten + 1 new Branch D test. Closes #449.- Per-note slug catalog re-sorted on every note (Issue #452, PR #483). See Highlights. LM Studio 2844-slug benchmark: 23.50s → 4.39s (4.4×) when new slugs sort in; 0.69s when unchanged. Companion to #449 — the catalog is now prefix-stable, the cache_control marker that #449 introduces lands on a block with a stable prefix. Closes #452.
LintReportModalgrew with vault size via fullwiki/index.mdimport (Issue #473, PR #494). See Highlights. analysis-phase.ts:118 read the full index; modal-open hitches hit 12s on a 5,000-page vault. Import path removed; Query UI reasoning restored. Closes #473.openai-compatproviders silently setreasoning_tokens: 0whenresponse_formatwas on the wire (Issue #481, PR #490). See Highlights. Per-steptask=mode[:thinking]policy replaces the global enable-thinking setting. Default ='default'= today's behaviour, opt-in. JSON-repair (source-analyzer.ts:417) intentionally does NOT honor — repair needs reasoning budget, disabling produces structurally-valid-but-wrong content. Closes #481.- Ingest payload grew linearly with vault size (Issue #482, PR #484 Stages 1+2). See Highlights. Per-page context trimmed to stable prefix; LLM sees the same per-note content but the request shape is bounded. Companion to #449 — the request shape matches what
cacheBreakpointexpects. Closes #482. - Contradiction clamp discarded wholly-withheld sections (Issue #492, PR #492). See Highlights. clampPageSections now uses the section list to keep logical order while honouring the 3000-char budget. Closes #492.
Added
src/core/task-policy.ts— per-step output mode + thinking policy. Parsetask=mode[:thinking](e.g.extract=text:on,merge-triage=text:on,page-generate=-:off,*=text:onfor run baseline).resolveTaskPolicy(map, task)returns{outputMode, thinking}(lookup order: specific → wildcard → default).thinkingEffortenum distinguishes bounded levels (low/medium/high) from unbounded (on) — measured on gemma-4-26b, unbounded thinking at the extraction step consumed all 16000 tokens of the batch budget and returned nothing, twice. Round-trips throughformatTaskPolicyMapfor run-manifest stamping.src/llm-sdk/finish-reason.ts—extractReasoningText(reasoning)helper. Centralises the SDK'sresult.reasoningshape handling (string vs array of{text}parts — Anthropic's shape) across all four SDK clients (anthropic / openai / openai-compat / openai-codex). 7 sites consolidated:anthropic-sdk-client.ts× 2,openai-codex-sdk-client.ts× 1,openai-compat-sdk-client.ts× 4.- Three-layer repair for DeepSeek reasoning-model ingest (Issue #474, PR #486). Layer 1:
prependReasoningForParsedrops prosereasoning_contentwhen visible text is non-empty (fixes the "balanced-JSON finder walks into English text" crash class). Layer 2: case-insensitive\b[Tt]hinking\s*\nregex on the bareThinking…Responseform (fixes LM Studio / DeepSeek capital-T variants). Layer 3: existing reasoning-only guard from PR #488 (#470 follow-up).
Changed
extractThinkingBlocksregex is now case-insensitive on the bareThinking…Responseform (post-merge CODE Gate cleanup). LM Studio / DeepSeek reasoning models route chain-of-thought into the visible content channel wrapped in the bareThinking\n…\nResponsedelimiter; capital-T variants were...
1.26.3
🌟 Karpathy LLM Wiki v1.26.3
Highlights
A PATCH release that closes three real bugs that users had been living with since the v1.23.0 AI SDK migration — repetitionPenalty finally reaches the wire (where the backend accepts it), the frontmatter writer stops emptying your sources: block, and the 3-tier output-mode state machine replaces an "elegant 2-tier fallback" that turned out to leave cloud-cohort callers with a parse-failure class the design itself created. Five PRs / 97 files changed / +9799 / −785. Test count 2992 → 3290 (+298). No breaking changes, no new required settings, no migration.
-
repetitionPenaltyuser setting now reaches the wire — Issue #414 (PR #453). The setting has been a silent no-op on every shipped provider since the v1.23.0 AI SDK migration dropped the pre-AI-SDKunsupportedFieldsblocklist: LM Studio / Ollama / llama.cpp received the wrong spelling (repetition_penaltywith-ion; llama.cpp recognizesrepeat_penaltyper DocTpoint's type-error test on gemma-4-12b); Kimi / OpenRouter / vLLM saw the field placed underproviderOptions.openaiCompatiblewhile the AI SDK's openai-compat passthrough at@ai-sdk/openai-compatible@2.0.62/dist/index.mjs:525-540readsproviderOptions[this.providerOptionsName](the provider id) — the key mismatch meant the lookup missed for every provider; Anthropic received the field but its Messages API has norepetition_penalty; DeepSeek / OpenAI / OpenAI Codex / Gemini / MiniMax / GLM / Bedrock-OpenAI do not list the field at all. Per-provider dialect dispatch inOpenAICompatSdkClient.buildProviderOptions:lmstudio/ollama→ wirerepeat_penalty(no-ion);kimi/openrouter/custom→ wirerepetition_penalty(snake_case, OpenAI-spec);deepseek/gemini/minimax/glm/bedrock-openai/ unknown → field dropped silently. The Anthropic client now drops the field entirely instead of placing an unrecognized key on the wire — matches the 10-locale i18n text "cloud providers will silently ignore it". Known limitation:wrapWithAdvancedSettings(src/llm-client-wrapper.ts) usesObject.create(client)to inheritcreateMessageStreamwithout settings injection —repetitionPenalty(and all other settings) is silently dropped on the stream path (Query Wiki, streaming UI). Tracked as #451 for v1.27.0. Closes #414. -
Frontmatter writer stopped dropping
sources:block-style entries on every constraints pass — Issue #438 (PR #450).enforceFrontmatterConstraints(src/core/frontmatter.ts:640-650) reads the originalsources:key viaparseFrontmatter().sourcesbefore tearing the lines apart, then writes the preserved list back into the new frontmatter on a length-gated check at:693. The bug:parseFrontmatter'sARRAY_FIELDSnormalization (src/core/frontmatter.ts:93-94) coerces the empty string''(what a baresources:header is read as) into a one-element array[''], the length check passes, andserializeFrontmatter:437writessources:\n - ""— i.e. the bug re-emits the corrupted shape rather than recovering from it. Fix: filter empty / whitespace entries at the source, mirroring thealiasesbranch at:452. So the recovery population (a baresources:header — the fingerprint of a page that already went through the broken constraints pass) re-emits nosourceskey at all, notsources:\n - "". 6-arm regression test pins: (A) baresources:→ no key emitted, (B) two valid entries preserved, (C) mixed- ""+ valid entry → valid entry alone, (D) baresources:as last frontmatter key → no- "", (F) whitespace-only- " "filtered. Pre-existing cosmetic follow-on surfaced by DocTpoint's measurement:serializeFrontmatteremits passthrough lines beforesources/tags/aliases, so the first lint after this fix movesgeneration_completefrom last to fourth position on every page with frontmatter — correct output, but it is a one-time vault-wide frontmatter churn that re-ingest / fillEmpty / merge-duplicates will repeat (constraints pass is not idempotent — each pass adds one blank line before the body viacontent.substring(fmEnd + 5)not stripping the leading\n). Users should expect a single frontmatter churn on the first lint after this fix. Closes #438. -
3-tier output-mode state machine replaces the elegant 2-tier fallback that was leaving cloud-cohort callers with a parse-failure class — Issue #443 (PR #447). The
openai-compatSDK client (src/llm-sdk/openai-compat-sdk-client.ts:182) did not includeresponse_formatin its destructure list, so every LLM call site that asked for{ type: 'json_object' }got no server-side JSON constraint on openai-compat providers. The destructure now carriesresponse_formatend-to-end via a newbuildOutputArgshelper (src/llm-sdk/output-args.ts) that translates to the AI SDK'sOutputmechanism. 3-tier output-mode state machine (src/llm-sdk/output-mode-prober.ts): ordered promotionjson_schema → json_object → text+prompt; the no-schema case emitsOutput.json()which the SDK encodes asresponse_format: { type: 'json_object' }for every openai-compat provider. The local-server cohort (LM Studio / Ollama /custom) may 400 onjson_object— a runtime 400-strip probe (src/llm-sdk/json-object-strip-probe.ts) catches the 400, retries once withoutputomitted, and caches the per-baseURL strip decision. Path 2 fix: AI SDK'sOutput.json()andOutput.object()BOTH callparseCompleteOutput(ai@6.0.230/dist/index.mjs:3899), which throwsNoObjectGeneratedErroron malformed JSON — notAPICallError.OpenAICompatSdkClient.createMessagenow catchesNoObjectGeneratedErrorfirst, returnserr.textverbatim so caller-sideparseJsonResponse+ greedy regex + LLM repair runs. Phase B (11 caller migrations + 9 Zod schemas): typed-output variantLLMClient.createMessageWithOutput(optional method, backward-compat) returning{text, output?, outputMode, finishReason, usage?}; newsrc/llm-sdk/output-schemas.tswithSeedSelectorSchema/QueryKeywordsSchema/MergeTriageSchema/LinkOrphanSchema/FixDeadLinkSchema/QueryViewValueSchema; callers preferresult.outputon Tier 0 success, fall back toparseJsonResponse(text)on Tier 1 / 2. Per CLAUDE.md "one PR per call site" rule, each migration ships as a separate commit. Closes #443.
What's in this release
Fixed
repetitionPenaltyuser setting was a silent no-op on every shipped provider (Issue #414, PR #453). See Highlights. Per-provider dialect dispatch (LM Studio / Ollama →repeat_penalty; Kimi / OpenRouter /custom→repetition_penalty; 6 IDs drop silently). The Anthropic client drops the field entirely instead of putting an unrecognized key on the wire. 3212 tests / 230 files (+3). Closes #414.- Frontmatter writer dropped
sources:block-style entries on every constraints pass (Issue #438, PR #450). See Highlights. Empty / whitespace entries now filtered at source, mirroring thealiasesguard. Recovery population (baresources:header) re-emits no key. Users should expect a one-time frontmatter churn on the first lint after upgrade. Closes #438. repetitionPenaltyUX hint names a setting that never reached the wire on 5 of 15 provider IDs (PR #454). User E2E on qwen3.5-9b surfaced a 2-axis defect: (1) the placeholder detector atsrc/core/json.ts:153only matched{"": ""}and missed the empty-object / empty-array variants{"": {}}/{"": []}that some models emit in place of an empty object; (2)buildRepetitionPenaltyHintfired on every provider regardless of whetherrepetitionPenaltyreached the wire, so users on Anthropic / DeepSeek / Gemini / MiniMax / GLM got a tail message saying "reduce or clear this setting" for a setting their backend had silently dropped. Fix A: single-pass conjunction atjson.ts:181accepts any object whose keys are all''AND whose values are all empty. Fix B:buildRepetitionPenaltyHintchecksrepetitionPenaltyWireField(provider) === nulland returns''on the 5 dropping IDs; the dialect helper is exported as a module-levelrepetitionPenaltyWireField(provider)and re-exported fromopenai-compat-sdk-client.tsso the two paths cannot drift apart. 63 tests pass across 4 touched files. Closes #443 follow-up.- 5 UX defects on the maintainer's vault E2E (PR #448). B1: Fetch Models classified auth failures (HTTP 401 / 403) as
Network, so users with expired keys saw a misleading "Failed to connect" notice — reclassified toAuth. B2: status-bar cancel label duplicated because the raw PDF-stage segments were passed verbatim into the cancel-line builder — fixed by emitting only the structured segments. B3: lint dedup cross-type filter did not surface rejected-pair count in the diagnostic comment. B2.5: full status-bar i18n (10 locales) so cancel / progress strings no longer carry hardcoded English tails. Toast: 5 lint / ingest Toast strings localized (ingest start, batch check, lint findings, etc.). parseJsonResponseparse failure atpath-resolution.ts:220read as "no match" (Issue #407 Stage 1, PR #444). The site's LLM semantic dedup call now goes throughparseJsonResult(the union from PR #436). On{ok: false, reason}the function logs the reason + raw length and returns the slug path as a named failure rather than as an answer to the question; thematch: falsebranch is reached only when the reply parsed. Counter-test pins the new branch: a well-formed{match: false}is not reported as a parse failure.
Added
1.26.2
🌟 Karpathy LLM Wiki v1.26.2
Highlights
A surgical PATCH release — 1 PR (3 commits, 7 files changed). No breaking changes, no new settings, no migration. The headline: v1.26.1 shipped a blocking no-unsafe-call Error in tools/llm-wiki-cli/src/obsidian.ts that local pnpm lint could not see, because local lint scans src/ only while the Obsidian review bot scans the whole repo .ts tree. v1.26.2 closes that gap on two fronts: the error is fixed end-to-end, and a new pnpm lint:tools-bot scan surfaces what the Bot would flag during development.
-
obsidian.tsunsafe-callchain fixed (PR #442).await import(<dynamic-arg>)leftrequestasany, cascading 6unsafe-*warnings and triggeringno-unsafe-call→ Error. Split into two literalawait import('node:https')/await import('node:http')branches with an explicittypeof import('node:http').requestannotation — Error + the entireunsafe-*cascade disappear in one stroke. -
Platform.isDesktopAST guards on the three runtime-loadednode:*imports (PR #442). During the fix we discovered thatobsidianmd/no-nodejs-modulesexempts based on AST guard-detection (function-startif (!Platform.isDesktop) throw), not on "bare dynamic import" as the assumption baked into PR #418/#433's patterns implied.obsidian.ts:requestUrl()andnode-globals.ts:plainConsole()now carry those guards. The CLI's own Platform shim hardcodesisDesktop: true, so they never throw at runtime — they declare the desktop-only invariant the rule requires. -
pnpm lint:tools-botcloses the local blind spot (PR #442). The local Gate 1 (eslint src/) was blind totools/. Neweslint.tools-bot.config.mjs+package.jsonscript gives you the Obsidian Bot's view oftools/locally during development, so the next release doesn't need a Bot trip to surface what local lint should have caught. Plus: release-skill v1.7.0 now mandates an Obsidian Bot pre-review between tag and publish (Step 6b.5, HARD STOP ②) — the gate that should have caught this.
Changes
Added
pnpm lint:tools-botinformational scan (#442). Neweslint.tools-bot.config.mjs(obsidianmd recommended ruleset scoped totools/**, type context fromtools/llm-wiki-cli/tsconfig.json, Node globals declared) + a matchingpackage.jsonscript (|| true, informational — never gates CI). Developers now see the Bot's view of the CLI tree locally instead of discovering it post-submission.Platform.isDesktopAST guards on the three runtime-loadednode:*imports (#442). See Highlights. Mirrorssrc/llm-sdk/openai-codex/loopback-flow.ts:156-160.
Fixed
obsidian.ts:117blockingunsafe-callError (#442). Split to literal dynamic branches + explicittypeof import('node:http').requestannotation; the entireunsafe-*cascade disappears. Resolves the only Error the Bot flagged on v1.26.1's submission.obsidian.ts:158requestUrl().jsoncontract (#442).JSON.parse(text) as unknown+ try/catch that re-throws with status context, matching the Obsidian host'srequestUrl().jsonbehaviour on bad JSON.main.ts:443loadSettingsJSON.parseargument type (#442). Now typed asPartial<LLMWikiSettings> | nullto matchapplySettingsMigrations' declared parameter; eliminatesno-unsafe-argument.main.ts:647globalThis.crypto.subtle→crypto.subtle(#442). Node 18+ exposescryptoas a global; the explicitglobalThis.prefix was trippingobsidianmd/no-global-this(a no-disable rule).vault.ts:291redundantas Record<string, unknown> | nullremoved (#442).parseFrontmatteralready returns aFrontmatterData | nullwhose index signature is compatible — Bot flagged as no-op assertion.node-globals.ts:28(...args: any[])→(...args: unknown[])(#442).Consoleconstructor acceptsunknown[]; eliminates a Bot-flagged bareany.
What's accepted (and why)
The Obsidian Bot pre-review of the v1.26.2 baseline returned 0 Error and 7 warnings on tools/llm-wiki-cli/src/. All 7 are accepted-structural to a Node CLI and documented in CLAUDE.md "Bot compliance invariant":
| Warning class | Locations | Why accepted |
|---|---|---|
Static node:fs / node:fs/promises / node:path / node:util imports |
main.ts:16-18, vault.ts:12-14 |
Dynamic form would break the 14 parser-contract tests that pin parseCliOptions as sync; namespace-style nodePath.* / fs.* call sites can't be top-level-awaited. |
.obsidian literal |
main.ts:451, vault.ts:25 |
Vault#configDir is an Obsidian host API; the CLI has no Vault object to read it from. |
console.log × 48 |
main.ts + obsidian.ts |
CLI is a terminal program; stdout is its only user channel. The Bot rule is a heuristic check, not an ESLint rule. |
globalThis shim |
node-globals.ts:27-29, 38 |
Must stub window / activeWindow for Obsidian-compat; no alternative API. |
Long-term plan: move the CLI to a separate repo ([[project_v1_27_0_cli_split_planning]]) so tools/ falls outside the Bot's scan scope.
Installation
- From Community Plugins: Obsidian Settings → Community Plugins → Browse → search "Karpathy LLM Wiki"
- From Community Plugin Website: community.obsidian.md/plugins/karpathywiki
- Manual: Download
main.js,manifest.json,styles.cssfrom the release assets
Upgrading from v1.26.1
No migration needed. Replace main.js, manifest.json, and styles.css in your vault's .obsidian/plugins/karpathywiki/ directory. Existing wikis are not touched on upgrade. All changed behaviour is internal to the headless tools/llm-wiki-cli/ CLI — no plugin-runtime impact.
Tests
2992 tests passing (218 files). Unchanged from v1.26.1 — no behaviour change in this release, no new test coverage needed for the existing 1 PR (the fixes are mechanical type/guard additions and the Bot pre-review is the gate).
Contributors
- @green-dalii — Maintainer. PR #442 (3 commits): fix + tooling + Bot invariant docs.
Full Changelog
1.26.1
🌟 Karpathy LLM Wiki v1.26.1
Highlights
A PATCH release — 21 PRs of high-ROI bug fixes and hardening since v1.26.0. No breaking changes, no new settings, no migration. The headline: the engine's largest phase now tells you which step is slow, the dedup concurrency-halving mechanism actually fires (it was dead code), and 24 Dependabot alerts are closed to zero.
-
Per-step LLM timing ledger (PR #409, eucher). Every
createMessagecall is now tagged with its pipeline step; a process-global ledger accumulates call count + wall-millis per label at the one seam every call passes through. Page generation — previously one interval covering path resolution, dedup, page writes and merge routing — now decomposes into per-step timings, so a slow ingest says which of the four to look at. Unlabelled calls land in an'untagged'bucket rather than being dropped, so the table never under-reports the run it exists to explain. -
Parse failures now have a name (#407 Stage 0, PR #436, DocTpoint).
parseJsonResponsefailures — empty body, malformed JSON, or exception — were indistinguishable from a legitimate negative answer at 7-12 call sites. The newparseJsonResultdiscriminated union gives each failure a reason ('empty'/'malformed'/'exception'), andparsed?.field || fallbackstops compiling at a call site that ignores the distinction. No behaviour change in this release; the 8 call sites port to the union in follow-up PRs (Stages 1+2), one per blast radius. -
Dedup in-scan concurrency halving actually fires now (CR-1, PR #416). The
consecutiveThrottleChunkscounter was declared inside the chunk loop, resetting to zero on every chunk — the halving threshold was unreachable. Hoisted above the loop so the counter accumulates across chunks. This corrects the v1.26.0 Batch 2 attribution: the 979s→365s e2e gain came from retry/backoff, not halving. -
Six reasoning-budget-sensitive token caps raised to 3000 (#403, PR #429). Short-JSON call sites (
{strategy, path},{keywords: []},{kind: "entity"}) were sized for non-reasoning models; on reasoning-capable models the deliberation consumed themax_tokensbudget before any content. DocTpoint measured 14/45 calls truncated (13 empty) andcomplementaryAppendat 100% miss on its 600 cap. Uniform bump to 3000 restores 50–80% reasoning headroom. -
A page keeps its own H1 through an LLM body rewrite (#419+#435, PRs #422+#437, DocTpoint). Two silent-corruption bugs in
reassertH1(a title with$or&got mangled byString.replaceescape processing; the first occurrence anywhere in the body took the restore) are repaired by splicing at the matched line index. ThenfindH1hardens the read side: a#shell comment inside a code fence or a---frontmatter block can no longer be adopted as a page's title. -
Query "Save to Wiki" stopped lying about silent no-ops (#398, PR #432). When dedup found the conversation already covered, the UI flashed "saved!" while writing nothing. The notice now appends the actual verdict, and a diagnostic
console.warnshows the LLM's dedup decision in DevTools. -
24 Dependabot alerts → 0 (PR #439). All 24 were transitive devDependencies (fast-uri, undici, postcss, vite); zero runtime impact (
main.jscontains none of them). Resolved by bumping the root devDeps that pull them in.
Changes
Added
parseJsonResultdiscriminated union for LLM JSON parse outcomes (#407 Stage 0, PR #436).{ok: true, value}/{ok: false, reason: 'empty' | 'malformed' | 'exception'}.parseJsonResponsestays as a byte-compatible wrapper — identity verified over 776 input combinations. Call-site migration follows in Stages 1+2.- Per-step LLM timing ledger (PR #409, eucher).
src/core/llm-task-usage.tsaccumulates calls + wall-millis pertasklabel at thecreateMessageseam. Snapshot-diff semantics (a reset would be wrong the moment two ingests overlap).
Changed
- CLI:
node-globals.ts:9staticnode:consoleimport → dynamic form (PR #433). Last staticnode:*import intools/llm-wiki-cli/; the Obsidian review bot'sobsidianmd/no-nodejs-modulesrule rejects static node-builtin imports.installObsidianGlobals()is now async; the sole caller already awaits.
Fixed
- Duplicate
sources:frontmatter key on stub-created concept pages (#399, PR #405). v1.25.11 regression producing invalid YAML (two top-levelsources:keys) on post-stub ingests. Corpus: 321 affected pages. - CLI per-run bundle isolation (#408). Two concurrent
ingest --helpruns raced esbuild's in-place bundle write (14/60 failed). Per-process bundle name + liveness sweep + post-import cleanup. - Dedup in-scan concurrency halving was inert (CR-1, PR #416). Counter reset per chunk; hoisted above the loop. Attribution correction: only retry/backoff delivered the 979s→365s gain.
- Six reasoning-budget-sensitive
TOKENS_*caps → 3000 (#403, PR #429). See Highlights. - CHANGELOG v1.26.0 entry:
thinking/chat_template_kwargsnever reached the wire — mechanism corrected (#420, PR #420). The SDK'sfilter()is a passthrough; the fields were misaddressed under the hardcodedopenaiCompatiblekey that no shipped provider id matches.reasoningEffort: 'none'is the only verified-working disable. yamldeclared in devDependencies (#424, PR #431). Clean-install regression — pnpm strict isolation nestedyamlunder vite; theappend-source-slugtest failed to collect on a fresh install.- Query wiki silent-success defect on Save (#398, PR #432). Notice now surfaces the dedup verdict instead of an unconditional "saved!".
--seeddocs narrowed to what is measured (#423, PR #434, DocTpoint). Local servers accept the flag and then ignore it (5× seed:42 @ temp:1.0 → 5 distinct outputs); the promise "honoured by every local server" was unmeasurable and removed.- H1 re-assertion hardened against frontmatter and code-fence lines (#419+#435, PRs #422+#437, DocTpoint). See Highlights.
- Bedrock Stage 2 planning entry recorded (#425, PR #426). Zero-AWS-SDK SSO path planned; cancels the ≥3-request gate.
Security
- 24 Dependabot alerts closed (PR #439). All transitive devDeps; zero runtime impact. Known CI-only carry-over:
brace-expansionnpm-audit reachability through lint plugins (Dependabot does not flag it) — out of scope, runtime bundle unaffected.
Installation
- From Community Plugins: Obsidian Settings → Community Plugins → Browse → search "Karpathy LLM Wiki"
- From Community Plugin Website: community.obsidian.md/plugins/karpathywiki
- Manual: Download
main.js,manifest.json,styles.cssfrom the release assets
Upgrading from v1.26.0
No migration needed. Replace main.js, manifest.json, and styles.css in your vault's .obsidian/plugins/karpathywiki/ directory. Existing wikis are not touched on upgrade. All changed behaviour is backward-compatible — the new settings-related fields are optional and default to the previous constants.
Tests
2992 tests passing (218 files). +64 net since v1.26.0, including:
src/__tests__/core/llm-task-usage.test.ts— per-step ledger (PR #409)src/__tests__/wiki/lint/llm-phases/dedup-phase.test.ts— CR-1 halving regression guard + classifyTiers (PR #416)src/__tests__/root/json.test.ts— 10 new parseJsonResult tests + 776-combination identity via the wrapper (PR #436)- H1 splice +
findH1line-walk tests (PRs #422 + #437) - Query-save silent-success regression guards (PR #432)
Contributors
- @green-dalii — Maintainer. 9 PRs: #416 (CR-1 halving), #426 (Bedrock plan), #429 (#403 caps), #430/#440 CHANGELOG sweeps, #431 (#424 yaml), #432 (#398 silent-save), #433 (node-globals), #439 (Dependabot 24-alert). Release prep + verification.
- @DocTpoint — 8 PRs: #418 (CLI requestUrl no-fetch-timeout), #420 (thinking-mechanism correction), #422+#437 (H1 re-assert hardening), #427 (shim regression guard), #434 (
--seedmeasurement), #436 (#407 Stage 0 parse union), #440 (CHANGELOG [Unreleased] sweep). Also reported #403 (reasoning-token caps), #423 (--seedover-promise), #424 (yaml clean-install), #407 (parse-failure indistinguishability). - @eucher — 2 PRs: #408 (CLI per-run bundle isolation), #409 (per-step LLM timing ledger).
- @borthwick — PR #405 (duplicate
sources:frontmatter fix) + reported #399 (321 affected pages in their vault). - @workflowsguy — reported #398 (Query "Save to Wiki" silent-success no-op).
Full Changelog
1.26.0
🌟 Karpathy LLM Wiki v1.26.0
Highlights
A MINOR release that introduces the headless ingest CLI as a first-class user-facing tool, ships Russian i18n (11 locales), and tightens the engine with five P0+P1 hardening batches. No breaking changes to the plugin runtime; deprecated CLI flags throw errors rather than silently translate.
-
Headless ingest CLI is now discoverable (
pnpm llm-wiki, npm binllm-wiki). Thetools/llm-wiki-cli/engine previously shipped with nobin, no pnpm script, and no mention in any README — a fresh clone could not find it. Exposesllm-wikias the executable name, so it can grow beyond ingest into a general wiki-management CLI (lint, query, mutation) without a later rename. Three-state--thinking-mode data-json | plugin-off | server-defaultreplaces the misleading two-state--thinking on|off(the old flag was a footgun —onlooked like "enable reasoning" but actually meant "defer to server default").--max-roundsis renamed to--round-basebecause the old name actively misled users about what it set. -
Real wire-level force-disable thinking — 4-layer fallback (PR #411). The previous
thinking.type = 'disabled'attempt was silently stripped by the AI SDK's zod schema (verified at@ai-sdk/openai-compatible@2.0.62/dist/index.mjs:322-344). Layer 1:reasoningEffort: 'none'passes the zod filter and emits asreasoning_effort: 'none'on the wire — the only verified-working disable. Layer 2: co-emitthinking/chat_template_kwargsfor the Anthropic path. Layer 3: on HTTP 400 mentioningreasoning_effort/thinking/chat_template, retry once withreasoningEffortstripped; per-baseURL cache prevents infinite loops. Layer 4: prompt-level "Do not reason step by step" in the dedup prompt. On the 2141-page vault, dedup wall-time moved from 979s → 365s (Batch 2 retry only) → 151s after Layers 1-3 went live (−85% vs baseline, −59% vs Batch 2). Per-callthinkingPolicyships in v1.26.x PATCH — JSON-repair path always allows reasoning (DocTpoint measured that disabling it produces structurally valid JSON with wrong content). -
Dual-key bucketed dedup (Batch 1, PR #401).
partitionPagesMultiBucketpartitions pages intotp-prefix+lh-link-hashbuckets before the O(n²)generateDuplicateCandidatesscan. ≥95% recall on synthetic N=200 pages vs 80-90% on the previous single-bucket baseline; memory peak O(N² candidates) → O(B² per bucket).checkCancelledhook at bucket boundary so users can interrupt mid-scan. -
Cross-type dedup candidate expansion (Batch 2, PR #410).
generateDuplicateCandidatesnow surfaces candidates across entity / concept / file types when the shared-link signal crosses type boundaries. Inline empty-response retry + 500ms backoff on transient burst load. New dedup-threshold inputs in Settings → LLM Configuration → Advanced → Custom ("Duplicate detection thresholds" subsection): shared-link duplicate threshold, body-similarity floor, title/alias similarity threshold — leave blank = constant default. Tier-1 cutoff (0.6) stays constant; user-tunable would let users silently flood or drop LLM candidates. -
Russian i18n (PR #397). 667 new keys in
src/texts/ru.ts; fulldocs/README_RU.mdtranslation; 11-way language switcher across all READMEs; system-prompt section labels for wiki output. 10→11 locales with strict bidirectional parity enforced bysrc/__tests__/root/i18n-parity.test.ts. -
Three DocTpoint contributions round out the surface:
- PR #357 — source-slug = page-lemma deterministic merge. Re-ingests of a source that produced a page can no longer fail to merge into that page on the second pass.
- PR #392 — vault-wide link retarget for
mergeDuplicates. Previously links from sibling pages pointing at either the surviving or the deleted page weren't rewritten. Now retargeted vault-wide and across every alias form. - PR #396 —
created:provenance.create-page.tsandfill-empty-page.tsnow takecreated:from the caller (new Date().toISOString()); never read from the LLM-generated content.
2928 tests passing (213 files). +184 net since v1.25.11.
Changes
Added
- Headless ingest CLI (
pnpm llm-wiki, npm binllm-wiki):tools/llm-wiki-cli/shipped as a discoverable executable. Three-state--thinking-modeenum, renamed--round-baseflag, 57 new tests inmain.test.ts. PRs #372 + #387. - 🛠️ Tools H2 section in all 11 READMEs pointing at
tools/llm-wiki-cli/README.md. - Russian i18n, full UI + wiki-output + README (PR #397): 667 keys in
src/texts/ru.ts, fulldocs/README_RU.md, 11-way language switcher, system-prompt section labels for wiki output. i18n-parity test enforces bidirectional coverage. - Real wire-level force-disable thinking — 4-layer fallback (PR #411): see Highlights above.
- Dual-key bucketed dedup (PR #401, Batch 1):
partitionPagesMultiBucketpartitions pages intotp-prefix+lh-link-hashbuckets before O(n²) scan. 10 new tests induplicate-detection.test.ts+dedup-phase.test.tspin ≥95% recall on synthetic N=200. - Cross-type dedup candidate expansion (PR #410, Batch 2): shared-link signal crosses entity / concept / file boundaries; new settings inputs for shared-link / body-similarity / title-alias thresholds. 11 new tests pin the threshold contract.
- Dedup parse-failure routing (PR #411, Batch 7): structured
type: 'parse-failure'discriminator ondedupFailuresentries;isRateLimitFailureaccepts a structured item and bails early ontype: 'parse-failure'. CR-3 wiring fix made the structured branch reachable in production (detectRateLimitFailures+ dedup-phase consumer now pass the full item, notf.reasonstring). - Source-slug = page-lemma deterministic merge (DocTpoint, PR #357, closes #348): re-ingest of a source cannot fail to merge into its own subject page on the second pass.
- Vault-wide link retarget for
mergeDuplicates(DocTpoint, PR #392, closes #386): sibling-page links pointing at the surviving or deleted page are now retargeted vault-wide and across every alias form before the delete. created:provenance fix (DocTpoint, PR #396, closes #388):create-page.ts+fill-empty-page.tstakecreated:from the caller; never read from the LLM-generated content.- Wiki-folder-scope prefix fix (Hashim1999164, PR #384): unanchored prefix leaks closed at the predicate level.
- FolderSuggestModal leak fix (#383 PR #384 follow-up, PR #389):
isAtOrInFolderScopeprimitive closes the wiki-folder-as-pickable-source leak. - Bottom "Advanced settings" panel (PR #395): hosts the 3 dedup threshold inputs +
lintDedupIncludeSourcestoggle. Separate from the LLM Advanced section (which retainstemperature,repetitionPenalty,forcePdfSupport).
Changed
--thinking on|off→--thinking-mode data-json | plugin-off | server-default. The old flag was a two-state surface that hid the three outcomes the plugin can actually produce. The new flag makes all three states explicit. The legacy--thinkingthrows a deprecation error pointing at the new flag and the v1.27.0 removal target; it does NOT silently translate.--max-rounds→--round-base. The old name was actively misleading: it set the granularity'smaxBatchesBasefield, not a ceiling. Renamed to describe what the flag actually sets. The internalGRANULARITY_CONFIG.maxBatchesBasefield is unchanged (engine contract, not CLI surface). Legacy--max-roundsthrows a deprecation error.- Picker exclusion rule centralised (PR #389):
FileSuggestModal,FolderSuggestModal, andMultiFileSuggestModalpreviously each open-coded the wiki + configDir filter. They now share a singleisExcludedFromSourcePickerprimitive insrc/core/folder-scope.ts. - Dedup threshold constants extracted + user-tunable (PR #395 + PR #410):
LINT_DEDUP_JACCARD_LINK_THRESHOLD,LINT_DEDUP_JACCARD_BODY_GATE,LINT_DEDUP_BIGRAM_THRESHOLDextracted fromsrc/wiki/lint/duplicate-detection.tstosrc/constants.ts.generateDuplicateCandidatesnow accepts aDuplicateDetectionThresholdsoptions-object.
Fixed
- Two-marker (verb + field) classifier for reasoning-field 400 errors (Batch 6 CR-2): the previous single-substring classifier included the bare word
thinking, which collided with model names (kimi-k2-thinking,qwen3-235b-a22b-thinking-2507,glm-4.6-thinking). Any 400 on these models — bad model name, context-length exceeded, max_tokens mismatch — was misclassified as a reasoning-field rejection, permanently marked the baseURL as "strip", and consumed the 400 so the token-key fallback never fired. The new two-marker classifier rejects all four false positives while still catching real rejections. - CR-3 wiring fix:
isRateLimitFailurestructured-form branch was previously unreachable in production because consumers passedf.reason(string), not the full item. BothdetectRateLimitFailuresand the dedup-phase consumer now pass the full item; regression test inrate-limit.test.tsexercises the discriminator throughdetectRateLimitFailures. ReasoningStripProberMap→Set (PR #411 simplify):Map<string, true>converted toSet<string>; removed the deadinvalidate(baseUrl?)overload (zero production callers — only tests used it).- Auto-maintain Phase 2 extracted to module function (
normalizeSourcesInFolderinsrc/core/sources-normalizer.ts): previously inline inrunStartupCheckwhich sleeps 3 seconds and depends on the wikiEngine/plugin surfaces — neither testable from the startup surface. The new module function mirrors the Phase 3 shape (findIncompletePages).
Internal
- Dead-code-as-docs governance (Batch 4 policy): exported helpers with zero production importers have a one-release half-life. PR #406 deleted the v1.25.10 PATCH P1-1/P1-2 unwired helpers (
lint-analysis-cache.ts+lint-smart-skip.ts) + stale...
1.25.11
🌟 Karpathy LLM Wiki v1.25.11
Highlights
A focused PATCH on v1.25.10 carrying three locked items from the 2026-07-30 triage, plus a code-quality cleanup pass. No new features, no API surface changes, no breaking changes — every change ships with a reproduction on a real-world corpus or a measurable improvement:
-
Freshly generated pages now stamp
sources:provenance at create time (#365). Previously the create-page path relied on the LLM to remember to write thesources:frontmatter field. When the model forgot — common with smaller / quantized providers — the page entered the wiki with no provenance trail, and later re-ingest could not tell which source had produced which page. A newappendSourceSlugToFrontmatterhelper atsrc/wiki/page-factory/create-page.tssplices the source slug into the existing frontmatter in a single linear pass — output is byte-shape identical tomerge-page.ts:93, so pages written through either path now look the same to downstream readers. -
Internal README links now resolve in the Obsidian Community Plugin browser (#375). The plugin's manifest
README.mdis rendered by the in-app Community Plugin browser, which strips relative cross-file links. 10 READMEs (EN + 9 locales) +docs/PDF-OCR-GUIDE.mdnow use absolutehttps://github.com/green-dalii/obsidian-llm-wiki/blob/main/...URLs everywhere a user might click between documents. Image refs are intentionally exempted — GitHub serves them via the absolute URL anyway. -
Status bar now reports the active stage by name (#169). "Reading source…" / "Extracting entities…" / "Running LLM analysis…" / "Generating pages…" — each stage now has its own fine-grained label (15 keys × 10 locales: 7 ingest + 3 PDF + 5 lint SCAN phases). Not ETA, never ETA — the wall-clock variance across LLM providers and corpus sizes makes time estimates unreliable, but knowing which phase the plugin is in helps users decide whether to wait or interrupt.
-
Query turn indicator redesigned as a windowed dot stack. The previous v1.23.2 indicator grew to ~3k px tall on a 200-turn conversation and overflowed the history container, losing its purpose as a "where am I in the conversation" anchor. The new design keeps one dot per turn but constrains the indicator to a fixed window inside the history container (25% from top, 50% from bottom of the panel). As the user scrolls through the conversation, dots roll past the window edges — the same ChatGPT/Grok "where am I in the conversation" feel — without the dot stack itself growing unboundedly. Hover tooltips still show the question text; clicking a dot scrolls the corresponding turn into view.
2744 tests passing (204 files). +31 net since v1.25.10.
Changes
Fixed
- Freshly generated pages now stamp
sources:provenance at create time (#365). TheappendSourceSlugToFrontmatterhelper splices the source slug into the existing frontmatter in a single linear pass — output is byte-shape identical tomerge-page.ts:93. 5 new tests increate-page.test.tspin the byte-identical contract. - Internal README links now resolve in the Obsidian Community Plugin browser (#375). Relative cross-file links are broken in the in-app reader; the patch moves them to absolute
https://github.com/...URLs. 12 new tests inreadme-links.test.tsenforce the invariant across all 10 READMEs +PDF-OCR-GUIDE.md. Image refs intentionally exempted. - Frontmatter fence guard accepts malformed closing-fence shapes. A previous parser tolerated a malformed
---line at end-of-file on the read path; this patch tightens the guard so the create path emits a single, canonical---closing fence.
Added
- Fine-grained status-bar stage labels (#169).
STAGE_KEYScanonical ordered list (15 keys) lives insrc/core/ingest-stages.ts.buildIngestStatusBarTextaccepts a 4thstageparameter.analysis-phasemigrated from the old genericlintStatusAnalyzingto the newlintStageAnalyzing. NOT ETA — labels are stage names, never wall-clock estimates. 7 new tests iningest-stages.test.ts+status-bar.test.tspin the 4-arg contract. - Turn-indicator redesigned as a windowed dot stack (Query UX). The previous v1.23.2 indicator grew to ~3k px tall on a 200-turn conversation and overflowed the history container, losing its purpose as a "where am I in the conversation" anchor. The new design keeps one dot per turn but resolves the indicator's top/bottom offsets to a fixed window inside the history container (25% from top, 50% from bottom of the panel). As the user scrolls, dots roll past the window edges, giving the ChatGPT/Grok "where am I in the conversation" feel. Hover tooltips still show the question text; clicking a dot scrolls the corresponding turn into view.
- EN README banner polish. Restored the "Obsidian Review Perfect Score" badge line + "Local-first • No backend • GDPR-Friendly" privacy line; tightened the comparison table from 12 rows to 8 (collapsing 4 near-duplicates); added a star CTA at the bottom of Quick Start.
- Ecosystem section (new EN H2). Documents MinerU online conversion as an alternative to local PDF OCR for users who cannot run local OCR pipelines.
Internal
- 5-agent audit applied 4 cleanups (4× simplify angle + 1× code-review max-effort):
- F2 — 4× frontmatter re-parse eliminated on the create-page path; the new
appendSourceSlugToFrontmatterhelper is single-pass linear. - F4 —
analysis-phasemigrated tolintStageAnalyzing; old genericlintStatusAnalyzingkey removed. - F5 — 30 dead i18n entries deleted across 10 locales (
lintStatusReading,lintStatusDuplicates,lintStatusScanningLinks× 10). - F6 — dead
fitIndicatorToContaineralias export removed fromturn-indicator.ts(zero callers).
- F2 — 4× frontmatter re-parse eliminated on the create-page path; the new
- Indicator redesign iterated. Three earlier variants (v1 dynamic gap, v2 12-slot sliding window, v4 percentage-based translation) were tried; v4's percentage-based positioning was broken because the JS path in
syncIndicatorWindowPxwrites explicit pixel values on everybuildTurnIndicatorcall, overriding the CSS percentage fallback. The shipped version (v6 windowed-dot-stack) uses percentages for layout intent but always resolves them to pixels in JS — a pattern that survives container-resize without the brittle CSS-dependency. The three earlier iterations' findings are preserved inturn-indicator.ts's v1.25.11 PATCH header comment.
Installation
- From Community Plugins: Obsidian Settings → Community Plugins → Browse → search "Karpathy LLM Wiki"
- From Community Plugin Website: community.obsidian.md/plugins/karpathywiki
- Manual: Download
main.js,manifest.json,styles.cssfrom the release assets
Upgrading from v1.25.10
No migration needed. Replace main.js, manifest.json, and styles.css in your vault's .obsidian/plugins/karpathywiki/ directory.
Existing wikis are not touched on upgrade. Pages generated by older versions can be re-ingested to retroactively stamp the sources: field; the formatter on the read path tolerates the missing field gracefully, so existing wikis continue to load and query without re-ingest.
Tests
- 2744 tests passing (204 files). +31 net since v1.25.10:
- +7
ingest-stages.test.ts+status-bar.test.ts(4-argbuildIngestStatusBarText+STAGE_KEYSenumeration) - +12
readme-links.test.ts(absolute-URL invariant across 10 READMEs +PDF-OCR-GUIDE.md) - +5
create-page.test.ts(byte-identical output vsmerge-page.ts:93forappendSourceSlugToFrontmatter) - +2
frontmatter.test.ts(fence guard) - +5 misc tests from the simplify follow-up
e02a33d
- +7
Contributors
Code contributors (commits in the 1.25.10 → 1.25.11 range):
- @green-dalii — All 12 commits in this PATCH range. Implementation: #365 Plan A
appendSourceSlugToFrontmatterhelper (commit9289bdd), #375 absolute-URL rewrite (commit7588034), #169 fine-grained status-bar stage labels (commit98f180c), 5-agent audit follow-up (commitsc191878,e02a33d), docs polish (commits5b18655,94c4c72), turn-indicator UX restore (commita300d1d), release-prep (commit527a46f).
Issue reporters (issues closed by this release):
- @DocTpoint — reported #365 "New pages rely on the model to write
sources:— the create path never stamps provenance". The diagnosis identified the create path as a separate write-side concern from the merge path's existingmerge-page.ts:93provenance helper, which motivated the Plan A splice approach over a full frontmatter re-parse. - @Gojob2987 — reported #375 "Bug: README internal links non-functional in Obsidian community plugin browser". The reported behaviour (clicking internal links in the in-app reader did nothing) traced to the Obsidian Community Plugin browser stripping relative cross-file links — absolute
https://github.com/...URLs work in all rendering contexts. - @Indexed-Apogrypha — reported #169 "Better status reporting, watch files as they are generated". The reported gap (the status bar showed only "Running…" without saying which phase) drove the 15-key fine-grained stage system.
Full Changelog
1.25.10
🌟 Karpathy LLM Wiki v1.25.10
Highlights
A focused PATCH on v1.25.9 carrying bug fixes only — no new features, no API surface changes. Every item in this release has a measured reproduction on a real-world corpus:
-
Mentions
[[|]]parser + formatter fixed (#363). Measured on a 417-note corpus (9272 writes): 119 frozen pages, 104 of the 144 unparseable lines were empty backlinks. The auto-provenance builder wrote aMentionWithProvenance.source_path: ''straight throughformatMentionsSection, emitting[[|]].BULLET_RErequired a non-empty target, so the line failed to parse,computeReingestMentionsreturnedpreserveRaw, and the page never accumulated another quote — silently, on every subsequent re-ingest. Two coordinated fixes: the formatter now routes both branches through a singlerenderCitation(leftPath)helper that emits no link when the path is empty; the parser'sBULLET_REmakes the citation segment optional and accepts an empty target, so the next merge fills attribution back from the source being ingested. -
Ingest-a-folder stopped pulling in sibling files sharing a name prefix (#364). The bare
path.startsWith(folder.path)leaked three cases: sibling folder with shared prefix (Notizenalso matchedNotizen-temp/x.md), file sitting beside the folder (Notizen.mdalso matchedNotizen), and the folder itself. The newfolder-scopehelper anchors on a trailing slash and treats the vault root as a wildcard ancestor — 11 mutation-tested cases includingNotizen.mdbeside the folder. -
Frontmatter re-touch no longer strips unknown top-level fields (#356). A previous fix's call to
mergeFrontmatteraccidentally dropped fields the plugin did not author (e.g.redirect_to:, custom user fields).extractPassthroughLines+replaceOrInsertYamlListField+CANONICAL_FRONTMATTER_KEYSseparate plugin keys from user keys and re-emit the user's verbatim. -
Lint fix-runners batched by
pageGenerationConcurrency(#367 P0-1). Five fix-runners now slice their input into batches ofpageGenerationConcurrencyand resolve each batch throughPromise.allSettledso a single failure never poisons the rest.concurrency = 1(the v1.25.9 default) preserves prior behaviour; users who raise it to 4–8 in Settings see wall-clock drop roughly by(n / concurrency)on a 2000-page vault. P1-1 analysis cache + P1-2 smart-skip helpers ship as dead code in this release; the controller wire lands in v1.26.0 MINOR (existinglength > 0guards already provide equivalent skip semantics today).
2713 tests passing (202 files). +91 net since v1.25.9.
Changes
Fixed
- Mentions section stopped silently truncating pages with empty citation targets (#363). The two halves are one fix, not two: shipping only the formatter half would have traded one unparseable shape for another. Round-trip interlock tests pin the formatter ↔ parser contract so neither half can ship alone again.
- Ingest-a-folder stopped pulling in sibling files that share a name prefix (#364). Anchor on a trailing slash; treat the vault root as a wildcard ancestor.
- Frontmatter re-touch no longer strips unknown top-level fields on re-touch (#356). User fields are separated from plugin keys and re-emitted verbatim.
- Merge triage can no longer drop a page's own primary source on a
skipjudgement (#312 part 2). NewisSourceOwnPageLemma({ pageName, pageAliases, sourceBasename, sourceContext })predicate compares slug keys against the page basename + curated aliases.SourceContextis optional everywhere — lint pipeline callers pass nothing and see no change. - Slug comparison keys use a Turkish-aware case fold when the vault opts in (#366 phase 1). New
slugKeys(name, aliases, { turkishFold })returns the comparison-key set;[[İsim]]and[[isim]]collapse to the same key in Turkish vaults. File-name outputs stay byte-identical —computeSlugis unchanged; the fold is comparison-only.
Performance
- Lint fix-runners batched by
pageGenerationConcurrency(#367 P0-1). Five fix-runners (runAliasCompletion,runDeadLinkFixes,runEmptyPageFixes,runOrphanFixes,runDuplicateMergeFixes,runRetagViolations) now slice into batches and resolve throughPromise.allSettled. P1-1 analysis cache + P1-2 smart-skip helpers ship as dead code; controller wire deferred to v1.26.0. - Alias hardening floor lowered from 3 to 2 chars (
MIN_ALIAS_LENGTH = 2). Two-char aliases are real-world (ML,HD,CD,AI,UI,OS,DB); rejecting them at the floor would be over-aggressive. The constant lives insrc/constants.ts, not in Settings.
Changed
- Custom tag vocabulary clarified as a hint, not an enforcement gate (#368). Schema docs and the Settings UI hint now spell this out in user language. Root cause is a docs / semantic mismatch, not an enforcement bug.
Installation
- From Community Plugins: Obsidian Settings → Community Plugins → Browse → search "Karpathy LLM Wiki"
- From Community Plugin Website: community.obsidian.md/plugins/karpathywiki
- Manual: Download
main.js,manifest.json,styles.cssfrom the release assets
Upgrading from v1.25.9
No migration needed. Replace main.js, manifest.json, and styles.css in your vault's .obsidian/plugins/karpathywiki/ directory.
Existing wikis are not touched on upgrade. Mentions sections on pages with [[|]] citations heal themselves automatically on the next re-ingest: the parser now accepts that shape, and computeReingestMentions fills the empty source_path from the source being merged.
Tests
- 2713 tests passing (202 files). +91 net since v1.25.9:
- +11
folder-scope.test.ts(prefix derivation + 7 predicate cases, includingNotizen.mdbeside the folder) - +6
mentions-formatter-roundtrip.test.ts(#363 — empty and absent citationsdescribe block, including round-trip interlock tests) - +84 lint fix-runner concurrency tests (5 fix-runners × per-batch-path)
- −10 net deletions: removed 4
ingest-folder-boundarytests and replaced 3dedec51data-layer-fallback tests that were co-dependent on the now-removed behaviour
- +11
Contributors
Code contributors (commits in the 1.25.9 → 1.25.10 range):
- @green-dalii — 10-item PATCH scope lock and the majority of the implementation: #356 frontmatter passthrough (commit
6736b06), #363 admission criterion + parser tolerance (initial 2-commit split indedec51+f3c61ab), #364 folder-boundary helper (initial in728f235), #366 Turkish fold helper (507e895), #367 lint-perf P0-1 fix-runners parallelisation (ece6007,17982b7,dbe9e13,76f2475) + P1-1/P1-2 helpers, #368 schema docs + settings UI hint (83dec0e), DocTpoint §4 merge/contradictory route split (e3861b5), alias hardening (f9a680e,b3e0b79), simplify audit + 4-agent pass, release-prep. - @eucher —
7e22848"fix(llm): stop silent truncation in chat and ingest" (PR #352) renamedTOKENS_QUERY_LLM_SELECT→TOKENS_QUERY_ANSWER = 8000so reasoning models stop truncating answers mid-sentence, and wiredonFinishthrough all three Query call sites to surfacefinishReason === 'length'as a console warning.43479d8"fix(ingest): keep source-page tags inside the closed vocabulary" (PR #349) keeps the LLM-generated source-page tags within the active tag vocabulary. Both landed in the 2026-07-26 PATCH batch and form the base this PATCH refines. - @DocTpoint —
Co-authored-by: DocTpointtrailers on98afe42and292d42eadopted his PR #370 (folder-scopemutation-tested helper for #364) and PR #371 (renderCitationsingle-render-gate design for #363). The render-layerrenderCitation(leftPath)replaces the data-layerm.source_path || sourcePathfallback that silently rewrote attribution of empty-sourcePath mentions — strictly more correct, and the design now includes round-trip interlock tests. Both source PRs closed in favour of the merged result.
Issue reporters (issues closed by this release):
- @Chris-Hestro — reported #363 "Mentions in Source renders
— [[|]]whenmentions_with_provenance[].source_pathis blank" with the failing render output that drove the formatter + parser tolerance fix. - @DocTpoint — reported #364 "Folder ingest has no folder boundary — sibling folders sharing a name prefix are ingested too", measured 50x folder mis-ingest on a real-world corpus, and contributed the
folder-scopehelper that the fix is built on. - @Guru35 — reported three issues from an 11k-page Turkish vault corpus: #366 "Slug derivation mismatch between link-writing and file-naming produces broken [[wikilinks]] at scale — degrades PPR retrieval" (16.5% broken wikilinks), #367 "Lint hangs indefinitely on large vaults (11.6k pages) — no candidates, zero API calls in 60 min", and #368 "Custom tag vocabulary not hard-enforced — invalid type tags written during ingest" (9% vocabulary drift). The Guru35 morning batch of these three issues shaped the v1.25.10 PATCH scope alongside the DocTpoint batch.