Johannes Kaindl1 downloadsSearch and replace by intent — a local LLM writes the regex, you review every match before it runs.
🇬🇧 English · 🇩🇪 Deutsch
Describe what to replace in plain language — a local LLM writes the regular expression, and you review every match before anything is written.
GET /v1/models; leaving the setting empty lets the server pick whichever model is loaded.<think> blocks are stripped before the JSON answer is parsed, and — where the server supports it — reasoning is actively suppressed so thinking models answer faster and don't leak their chain of thought into the note.Transmute solves a gap Obsidian leaves open: the built-in search is read-only, and the existing regex plugins (Regex Find/Replace, Search and Replace Regex, Apply Patterns) all assume you already know how to write a regular expression. Transmute lets you describe the edit in your own words instead. A ribbon icon (replace, label "Transmute") and the command "Open panel" open a sidebar panel: pick a scope, describe the change, click "Generate", and the model's pattern is compiled, screened for catastrophic-backtracking risk, and run against your text — never blindly. The resulting hits are shown with highlighting; select or deselect individual matches (or use "Select all" / "Select none"), refine the instruction as many times as you like, and only write the note once you are satisfied.
Search for Transmute in Settings → Community plugins → Browse, then click Install and Enable.
Download main.js, manifest.json, and styles.css from the latest release and place them in <vault>/.obsidian/plugins/transmute/, then enable the plugin under Settings → Community plugins.
git clone https://codeberg.org/jkaindl/obsidian-transmute
cd obsidian-transmute
npm install
npm run build # produces main.js
Then copy main.js, manifest.json, and styles.css into <vault>/.obsidian/plugins/transmute/ and reload Obsidian.
Open Settings → Community plugins → Transmute. Settings are grouped under "Connection" and "Behaviour".
| Setting | Default | Effect |
|---|---|---|
| Endpoints | ["http://127.0.0.1:1234"] |
Ordered list of OpenAI-compatible servers, tried in order; the first reachable one is used. One-click presets for LM Studio and Ollama, plus a per-row reachability status and a "Test connections" button. |
| Model | "" (empty) |
Which model to request. Empty lets the server choose whichever is loaded. A dropdown is filled from the active endpoint's /v1/models; use the reload button to refresh it. |
| Request timeout (ms) | 120000 |
How long to wait for the model to answer before giving up. |
| Default scope | file (Whole note) |
Which scope a new rule starts with — "Whole note" or "Selection". Switchable per run in the panel. |
| Text sample sent to the model | 2000 (characters) |
How much of the scope text is sent along with the instruction, so the model can see what it is matching against. |
| Time budget for running the pattern (ms) | 2000 |
A pattern that runs longer than this on a line-by-line scan is stopped, and the matches found so far are shown with a notice. |
| Ask reasoning models to skip thinking | true |
Sends reasoning-suppression parameters to the endpoint (and strips <think> blocks from the answer either way) so reasoning-capable local models answer faster and more reliably. |
Endpoint tip: enter the base URL without a trailing /v1 — the client appends /v1 itself (a trailing /v1 is stripped automatically either way, so both forms work).
Transmute sends your instruction, plus a sample of the scope text, to the configured endpoint's /v1/chat/completions and asks for a single JSON object — regex, flags, replacement, explanation — never prose. The answer is parsed leniently (code fences and any <think> block are stripped, the first balanced JSON object is extracted), and one retry with the concrete error is sent back to the model if the first answer doesn't parse or validate.
Before the generated pattern ever runs, a static heuristic screens it for constructs known to cause catastrophic backtracking — nested quantifiers, quantified alternation over identical branches, unbounded backreferences — and rejects it with a plain-language reason if it looks dangerous. A pattern that passes is then executed line by line against the scope text under a configurable time budget; multi-line patterns (an s/m flag, or a literal \n in the pattern) run once against the full text instead, since a time budget only makes sense between discrete steps.
Nothing is written to your note until you click "Apply". At that point, only the checked matches are applied — in reverse order, so earlier replacements never shift the offsets of later ones — and the result is written through Obsidian's editor API (editor.replaceRange), which is what puts the change on the normal undo stack.
The full documentation follows the Diátaxis framework — see docs/manual/index.md:
See the changelog for release notes.
ksawl/obsidian-alchemist shares the alchemy/transmutation imagery but a different job: it is a general vault-hygiene toolkit. Transmute is narrowly about turning a plain-language instruction into a reviewed, applied regex replacement — it does not aim to cover vault hygiene more broadly.
Contributions are welcome. Please read CONTRIBUTING.md for the workflow (test-driven, main always green, feature work in feat/<name>, Conventional Commits) and AGENTS.md for the architecture and module conventions. The canonical repository lives on Codeberg; GitHub (johannes-kaindl/obsidian-transmute) is a mirror.
Copyright © 2026 Johannes Kaindl.