Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>MirrorstoneNew to Visual Studio Code? Get it now.
Mirrorstone

Mirrorstone

Hoo Hugo Kim

|
1 install
| (0) | Free
Obsidian-style Markdown in the built-in preview, with PDF export.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Mirrorstone

Obsidian-style Markdown (OMD) for VS Code — view standalone notes in the built-in Markdown Preview and export them to PDF. Neither workflow requires an Obsidian vault or an open workspace folder. The Mirrorstone CLI runtime is bundled; PDF export also requires Pandoc and Typst.

Mirrorstone is an independent project and is not affiliated with or endorsed by Obsidian (obsidian.md). "Obsidian-style" describes the visual target only.

Status: v0.3.0 public pre-release candidate. The built-in-preview dialect, PDF export and optional vault index (wikilink completion, navigation, best-effort backlinks) are implemented. Full Obsidian compatibility and identical preview/PDF appearance are not claimed.

Mirrorstone extends the built-in Markdown Preview and the Markdown source editor. Compatibility with VS Code's native visual Markdown Editor is still under investigation. This release provides no separate editor, and that development path is on hold.

Install and receive updates

After this candidate is published to the Visual Studio Marketplace, open Extensions in ordinary VS Code, search for @id:hoohugokim.mirrorstone, and select Install Pre-Release Version (or Switch to Pre-Release Version on an existing installation). Keep extension automatic updates enabled to receive later pre-release builds. No separate VS Code application or dogfood launcher is needed. See VS Code's extension installation guide.

The source repository remains private. Installing the public package does not require repository access. The package's documentation and license are included in the installation.

Open a Markdown file and use Markdown: Open Preview (Ctrl/Cmd+Shift+V). For PDF output, install the tools below and run Mirrorstone: Export to PDF. Use Mirrorstone: Version and Mirrorstone: Diagnostics to identify the extension, selected CLI and export dependencies when investigating a problem.

Preview

VS Code's own Markdown preview (Ctrl/Cmd+Shift+V) renders the Obsidian flavor — no separate command and no webview of ours. The extension contributes a markdown-it plugin set and a stylesheet to the preview you already use.

Rendered: callouts in Obsidian's own .callout[data-callout] DOM (so your CSS snippets drop in — including the hard-break rule, where every line in a callout body breaks except inside list items), wikilinks and ![[image]] embeds with |WxH sizing, hidden %%comments%%, ==highlight==, x^2^ / H~2~O, footnotes, #tag pills, block ids, task lists, the filename→H1 the PDF injects, and pandoc's smart typography. Math (KaTeX) and Mermaid come from VS Code itself.

The preview and PDF share many dialect rules, with known differences. The most visible limitations: a heading or > quote on the line directly after a paragraph stays paragraph text, callout titles are plain text, [/] [-] [>] task states stay literal, and ![[note]] transclusion is a placeholder. Mermaid diagrams can render in the native preview but export as code blocks because the bundled PDF runtime has no Mermaid rendering step. Fonts, line wrapping and pagination also differ between a preview and a PDF.

mirrorstone.preview.enabled — read this one

VS Code has one Markdown preview engine, and it serves every markdown-family file: .md, but also *.prompt.md, *.instructions.md, *.agent.md, *.chatmode.md and SKILL.md. A preview plugin cannot ask which file it is rendering, so the dialect is a per-window switch:

Value Behavior
auto On only when a workspace folder root contains a .obsidian directory — i.e. when you actually opened an Obsidian vault.
on (default) OMD rendering with no vault or open folder required. This changes every Markdown preview in the window, including READMEs and agent instruction files.
off Never. VS Code's stock preview, byte for byte.

Only optional auto-detection needs a real filesystem; the default on also works in virtual workspaces. Changing the setting reloads the preview's plugins — if an already-open preview does not update, run Markdown: Refresh Preview.

Frontmatter is left to VS Code, which shows it as a properties table (markdown.preview.frontMatter). The exported PDF strips colon-bearing frontmatter, so this is a deliberate, registered difference.

Three preview settings are re-applied by VS Code after every plugin and therefore win over anything the extension asks for: markdown.preview.breaks, markdown.preview.linkify and markdown.preview.typographer. Smart dashes, ellipses and curly quotes are forced at rule level so PDF parity survives typographer: false (the default), but breaks: true will add line breaks the PDF does not have.

Vault features

Open a folder that is an Obsidian vault — one whose root contains .obsidian/ — and [[wikilinks]] become live in VS Code's Markdown source editor through its completion popup, Cmd+click and Find All References. Vault detection is only an indexing boundary; standalone preview and export remain available outside a vault.

  • Completion inside [[…]]. Note names as you type; # switches to the target note's headings, #^ to its block ids, and a | ends it because an alias is your prose, not a filename. ![[embeds]] complete the same way. Accepting an item writes [[Note]] — including when VS Code has already auto-closed the brackets, where a naive implementation writes [[Note]]]].
  • Cmd+click on [[note]], [[note#heading]] or [[note#^block]] opens the target at that line. Go to Definition does the same from the keyboard, and hovering shows the target's path and first lines.
  • Backlinks through Find All References (Shift+F12) on any note: best-effort results from indexed notes, with peek and grouping. An empty list is not proof that no notes link here; see the limits below.
  • A link to a note that does not exist is still a link — hovering offers Mirrorstone: Create Note from Link (command palette too), which creates an empty note at the vault root unless the link names a folder, then opens it. If either existence check finds a file, it opens that file instead. Creation is not exclusive: a concurrent write between the final check and creation can be overwritten, and stat errors currently count as absence. Use ordinary file creation when another program may be writing the same destination. Cmd+click on a missing note never mints files.
  • Renaming a note rewrites nothing in this release. Update affected links manually; future link-update work requires separate write-safety verification.

Korean names work in both normalizations. macOS stores filenames decomposed (NFD) while anything you type arrives composed (NFC); the two are different strings to JavaScript, so an index that ignores this silently fails to resolve [[한글 노트]] to the file sitting next to it. Every lookup here is normalized, in both directions, and it is tested in both directions.

Index limits

  • Results can be incomplete or stale. The index builds in the background; discovery failures and missed filesystem watcher events can leave gaps. Run Mirrorstone: Reindex Vault before relying on an empty backlink list. Failed walks produce a warning; reindexing cannot remove the limits below.
  • Large notes have a scan ceiling. Notes over 1,048,576 bytes (1 MiB) are retained by name but contribute no links, headings or block IDs. The skipped note is named in Mirrorstone's output channel, with a warning for the first such note in the session.
  • Frontmatter links are omitted. [[links]] in YAML properties contribute no backlinks or completion. The preview's properties table is plain text.
  • Case and Unicode collisions lose index coverage. Files whose names differ only by case or Unicode normalization share an index key. The first indexed note is retained; the other is refused and reported. Mirrorstone does not rename files to normalize them. If both files exist, give them distinct names and update affected links manually.
  • References can include extra links. Self-links are included, as are some links inside math or repeated footnote definitions that the preview does not display as links.

What it does not do

There is no graph view, Dataview, Templater or canvas support. Attachments (images, PDFs) are not indexed, so ![[diagram.png]] still renders but is not offered by completion. Only ATX headings (## Like this) are anchor targets. [[note#Outer#Inner]] matches the last heading named rather than verifying the outline path. Mirrorstone does not provide a custom visual editor; native visual-editor compatibility remains unverified. The old custom-editor spike is unregistered because its resync could discard typing.

Set mirrorstone.vault.enabled to false to switch the index and its file watcher off entirely.

Export to PDF

Mirrorstone: Export to PDF — command palette, editor title bar, editor and tab context menus, or the explorer context menu, including a multi-select that becomes one batch run. Converts .md / .markdown / .mdown / .txt to <stem>.pdf next to the source file.

  • Extensions match case-sensitively, exactly as the CLI matches them: rename NOTE.MD to note.md.
  • Unsaved editors are saved first, because the CLI reads from disk. If a file cannot be saved you are asked whether to export the on-disk version, skip it, or cancel — and "export anyway" is reported as a warning, never a plain success.
  • A failed re-render leaves the previous PDF untouched.
  • What happened is read from the CLI's own log (SUCCESS / FAILED / SKIP per file), so a batch where some files fail reports "N of M converted" and still offers the PDFs that landed.
  • Two exports of the same file never overlap; the second is declined while the first runs.

Also: Mirrorstone: Diagnostics (what was resolved, and where) and Mirrorstone: Recheck Export Dependencies (after installing something).

The export runs the CLI as a child process, which inherits the extension host's environment plus Mirrorstone's own MIRRORSTONE_* variables — standard for an extension that runs a tool on your behalf. Mirrorstone never sends telemetry.

Requirements

Export shells out to two external programs. Neither is bundled, and nothing else is needed: the CLI runtime ships inside the extension, so there is no install.sh step.

Tool Minimum macOS Debian / Ubuntu / Pop!_OS
pandoc 3.9 brew install pandoc upstream .deb from jgm/pandoc/releases — apt ships 3.1.x
Typst 0.14 brew install typst cargo install --locked typst-cli
Pretendard — optional; without it the PDF falls back to system fonts same

Older-than-minimum versions warn once and export anyway. A missing tool is the only thing that blocks, and then the install one-liner is on a button.

"It works in my terminal but not in VS Code." A VS Code launched from the Dock or a desktop launcher does not inherit your shell's PATH. The extension searches the same prefix the CLI does (/opt/homebrew/bin, /usr/local/bin, ~/.local/bin, ~/.cargo/bin, /usr/bin, /bin) before falling back to the inherited PATH. If your tools live elsewhere, set mirrorstone.pandocPath / mirrorstone.typstPath and run Mirrorstone: Diagnostics to see exactly what was searched.

Platforms: macOS and Linux. The CLI is bash + perl, so Windows is not supported natively — use a Remote — WSL window, where the export command is offered because that is where the CLI actually runs. On plain Windows the command explains this and does nothing. Export is disabled in Restricted Mode, since it runs external programs.

Settings

Setting Default What
mirrorstone.vault.enabled true Index the vault so [[wikilinks]] resolve. Off = no completion, no Cmd+click, no backlinks, no watcher.
mirrorstone.preview.enabled on When the dialect applies to the built-in preview. See above — on affects every Markdown preview in the window.
mirrorstone.cli.path "" Explicit CLI path. Machine-scoped; blocked in untrusted workspaces.
mirrorstone.pandocPath "" Explicit pandoc. Machine-scoped; blocked in untrusted workspaces.
mirrorstone.typstPath "" Explicit typst. Machine-scoped; blocked in untrusted workspaces.
mirrorstone.font "" Primary document font for exported PDFs; empty means Pretendard.
mirrorstone.useVaultRoot true Pass the file's workspace folder as the vault root so vault-relative images and embeds resolve. Security trade: it widens Typst's render root from the document's folder to the whole workspace folder, so a note can #image() anything under it. Turn it off for document-directory scoping.

The three path settings are machine-scoped and listed in capabilities.untrustedWorkspaces.restrictedConfigurations: a workspace's .vscode/settings.json must never be able to point the extension at a script of its choosing.

Package notices

  • Third-party notices: THIRD-PARTY-NOTICES.md, shipped in this package.
  • License: MIT (LICENSE).
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft