Saiki77768 downloadsSurface notes most semantically similar to the one you're reading in a left-sidebar panel, powered by a small multilingual embedding model that runs entirely on your machine. Private and offline.
A left-sidebar panel that surfaces the notes most semantically similar to the one you're reading, so you browse your vault by meaning, not by folders. Open any note and the panel ranks the rest by how closely they relate, as a stack of cards you can click to jump to.
It's powered by a small multilingual embedding model that runs entirely on your machine: no cloud, no API key, no second app or server. Everything happens locally inside the renderer, so your notes never leave your computer. After a one-time model download (cached on first use), it works fully offline. The model understands German, English, and 100+ other languages, so matches cross languages naturally.
Each Markdown note is split into short passages (windows that fit the model's context), covering the whole note, and every passage is turned into a vector by the embedding model. Adjacent passages are then grouped into coherent ideas (~200-500 words, at heading and topic boundaries, with short atomic notes kept whole), so a note is represented at three levels: an overall vector, its idea vectors, and its passage vectors. For the note you're viewing, every other note is ranked by the best cosine similarity of their passages (with its title weighted), blended with how strongly the two notes share a whole idea, so a note related by one coherent idea spanning several paragraphs surfaces, not just one lucky passage match. The closest matches are shown as cards with a similarity percentage.
The model runs through @huggingface/transformers
on the local ONNX runtime, on the CPU via WASM by default, multi-threaded so a
full reindex is quick, and memory-stable. (A WebGPU option exists and is faster,
but its GPU backend can accumulate memory on large vaults, so it's an explicit opt-in.)
The whole engine lives in its own worker, which is shut down after an idle
period (configurable) — so when you're just reading and browsing, the model's
hundreds of MB to several GB are returned to the system instead of sitting resident;
it reloads transparently in a few seconds when next needed. An Indexing speed
setting trades CPU threads against reindex time. The only network traffic ever is
one-time: the model weights from the Hugging Face Hub, and the ONNX runtime
.wasm (version-pinned), which is cached into the plugin's own folder; afterwards
nothing is fetched again and the plugin works offline.
Vectors persist as compact JSON in the plugin's config dir, so the index survives restarts and only changed notes are re-embedded.
For the full picture, see ARCHITECTURE.md: the multi-granularity embeddings, the multi-stage ranking funnel, the measured model A/B, mean-centering, and the roadmap toward tag-free concept search.
~ pill), so it's never empty.
Next up, going beyond reading related notes to tidying the graph itself:
paraphrase-multilingual-MiniLM-L12-v2 is a
symmetric sentence-similarity model, the right tool for ranking how alike two
notes are. paraphrase-multilingual-mpnet-base-v2 (Best quality) is stronger but
larger. e5 models are retrieval-oriented and rank note similarity less well.goa).
A note tagged with an activated namespace (matching goa and goa/character) only
relates to, and takes tag suggestions from, other notes in that area, and never
appears in any other note's cards. Notes in no activated area share one pool. A live
ranking knob (no re-index). Use it to keep a self-contained project (a novel, a world)
from bleeding into unrelated notes.Changing the model or compute device transparently rebuilds the index; unrelated changes (sliders, toggles) never trigger a re-embed.
Run "Vault insights (suggested links, orphans, duplicates)" from the command palette to generate a report note for the whole vault:
goa/character tag) from similarity alone, only proposing discriminative tags.It writes/refreshes Vault Insights (Smart Related Notes).md and opens it; every entry
is a clickable wikilink. Nothing is changed in your notes.
Download main.js, manifest.json, and styles.css from the latest release into
.obsidian/plugins/smart-related-notes/. On first use the plugin fetches, once,
the version-pinned ONNX runtime (cached into its ort/ folder) and the model
weights; after that it works offline.
Add this repository in BRAT and enable Smart Related Notes from the community-plugins list.
On first launch the model weights download from the Hugging Face Hub with a progress
notice, then cache. This happens once; after that the plugin works offline. The
WebGPU (GPU) path uses fp32 weights (470 MB for the default model); the WASM (CPU)
path uses smaller quantized weights (110 MB). The model is downloaded once per
backend, then cached.
A TypeScript project bundled with esbuild (entry src/main.ts → root main.js).
npm install # install dev dependencies
npm run dev # esbuild watch build (inline sourcemap, no minify)
npm run build # gen-ort -> tsc --noEmit -> minified production bundle
npm run lint # eslint (typescript-eslint + eslint-plugin-obsidianmd)
gen-ort.mjs runs before tsc/lint/esbuild: it writes src/ort-version.ts (the
pinned onnxruntime-web version + the CDN base the runtime is downloaded from)
and copies the matching onnxruntime-web .wasm/.mjs assets into ort/ for
local dev builds. Both are build artifacts and are gitignored. Releases ship only
main.js, manifest.json, and styles.css (exactly what Obsidian downloads);
at runtime the plugin caches the pinned ONNX runtime into its ort/ folder on
first use, validated against byte sizes pinned at build time so torn writes or a
plugin update carrying a different runtime build trigger a clean re-download
instead of mixing builds.
The embedding engine (transformers.js + onnxruntime-web) runs inside a dedicated
Web Worker bundled as a second esbuild stage and inlined into main.js (see
esbuild.config.mjs and src/worker/embed-worker.ts); terminating that worker is
what returns the engine's memory to the OS when idle. Environments that expose a
Node-like process would make transformers.js pick the (externalized,
unavailable) onnxruntime-node backend — src/ort-shim.ts (imported first in
the worker entry) flips the relevant process markers during module evaluation so
the web runtime is used and WebGPU/WASM work.
MIT © 2026 Saiki77