Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>Lapis — Markdown WorkspacesNew to Visual Studio Code? Get it now.
Lapis — Markdown Workspaces

Lapis — Markdown Workspaces

Mariano Viola

|
1 install
| (0) | Free
Lightweight knowledge navigation and structured views for plain Markdown workspaces.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Lapis icon

Lapis — Markdown Workspaces

A lightweight knowledge workspace for VS Code, built from ordinary Markdown files and YAML frontmatter. Keep your notes in plain text while using VS Code's editor, Explorer, search, and Markdown preview.

Key Features

  • Find notes quickly — search by title, path, and selected properties with Lapis: Open Note.
  • Connect your knowledge — insert wikilinks with a dedicated note and heading picker, then navigate with Cmd/Ctrl+click or F12. Theme-aware link styling distinguishes resolved, missing, and ambiguous targets.
  • Organize notes into views — use plain-text .base definitions to explore note properties in read-only table and Kanban views, with search, grouping, and property visibility controls.
  • Set note reminders — schedule date reminders from a Base preview and receive VS Code notifications. Reminders persist across restarts in the same workspace; alerts are delivered while VS Code is running or on the next launch.
  • Edit Markdown tables — format tables, align columns, and insert or delete rows and columns with explicit, undoable commands.
  • Read richer previews — render wikilinks, highlights, footnotes, task-list checkboxes, and theme-aware blockquotes in the native Markdown preview.
  • Stay in control of your files — notes remain ordinary Markdown, with no application-specific database. Authoring commands edit only the active buffer and never automatically save your notes.

Get started: create a .lapis marker file in your notes folder, open that folder in VS Code, and run Lapis: Open Note from the Command Palette.

Extension ID: marianoviola.lapis. Licensed under the MIT License.

Lapis defines its own workflows and documented view syntax. Notes remain plain Markdown with YAML properties; using them does not require Obsidian or another note application. Data portability is a design goal, not a promise of feature or file-format parity with other tools. See Portability and compatibility for the current boundaries and criteria for future integrations.

Vaults

A vault is a directory containing a .lapis marker file. Lapis indexes Markdown files only inside vaults; a marker may be in a workspace folder, a descendant, or an ancestor of a workspace folder. The extension checks ancestor directories as well as markers beneath each workspace folder.

Workspace folders inside the same vault share one link-resolution namespace. The highest (outermost) discovered marker defines that vault root. Separate vaults have isolated namespaces, including when they are open in the same multi-root workspace. Creating or removing a marker updates the index.

Milestone 1: Index And Note Navigation

Implemented:

  • Lapis: Open Note opens a native Quick Pick searchable by title, path, and selected properties. Selecting a note opens the native Markdown editor.
  • A shared in-memory index tracks Markdown files, typed frontmatter, headings, body wikilinks, file timestamps, and unsaved editor changes.
  • File creation, modification, deletion, and native renames update the index. Pending reads cannot overwrite newer changes or resurrect deleted records.
  • Invalid frontmatter appears in the Problems panel. Notes remain navigable.
  • Lapis: Rebuild Index provides explicit recovery after missed filesystem events. The Lapis Output channel reports discovery and read failures.
  • The data layer supports root-scoped link resolution and cached backlinks. Backlinks are not exposed as a sidebar yet.
  • Wikilinks support Cmd/Ctrl+click and F12 in the Markdown source editor, including heading destinations and unsaved buffers. Ambiguous links show a hover listing candidates instead of guessing a destination.
  • Lapis: Insert Wikilink opens a dedicated note picker, then offers headings and an optional alias. Selected text is proposed as the alias; existing aliases are editable. Empty alias means no alias; Esc at any step makes no edit. Targets use the shortest uniquely resolving reference within the same vault, including unsaved headings. Aliases inside tables use \|. Code and metadata are excluded. Only the active buffer is edited, with one undo step; no note is created or saved.
  • Editor completion is optional and off by default, so Lapis does not compete with VS Code or Copilot suggestions. Enable lapis.wikilinkCompletion to use [[, # and Ctrl+Space completion. It preserves existing aliases/closing brackets and uses the same index and resolver as the dedicated command.
  • Wikilinks in the source editor use theme-aware colours: resolved targets use the link colour, missing notes use the warning colour with a dotted underline, and ambiguous targets use the info colour with a dashed underline. The entire wikilink, including its alias, is coloured; surrounding text is unchanged. Colours update when notes change, appear or disappear, including unsaved edits. Code, metadata and notes outside vaults are not decorated. Non-Markdown embeds are not marked as missing while attachment resolution remains undefined. A resolved note with a missing heading still uses the link colour, matching navigation's fallback to the top of the note.
  • Blockquote prose in the source editor uses the active theme's normal text colour instead of the quote syntax colour. Quote markers, code, links and wikilinks retain their own colours; bold and italic formatting is unchanged. This also applies outside vaults and updates as you type, without editing the document or changing VS Code settings.
  • The native Markdown preview hides a closed YAML frontmatter preamble, even when the YAML is invalid. Metadata stays editable in the source and available in the index; diagnostics are unchanged. An unclosed preamble remains visible.
  • Inline code in the native preview uses 90% of the surrounding font size. Code blocks and source-editor font settings are unchanged.
  • Ordinary blockquotes in the preview use a slim link-coloured bar, a subtle tinted background and compact spacing. Text keeps the surrounding colour; high-contrast themes omit the tint. Nested quotes, lists and code retain their Markdown structure. This does not add callout syntax. The accent follows the active VS Code theme's link colour, not a fixed blue; no separate Lapis accent setting is currently provided.
  • GFM task-list markers (- [ ], - [x] and - [X]) render as read-only checkboxes, including nested and ordered lists. Change their state in the Markdown source; code examples and escaped markers remain ordinary text. Checked boxes use the theme's link colour as their background.
  • Highlights (==important text==) and footnotes ([^1] with a [^1]: Footnote text definition) render in any native Markdown preview, including notes outside vaults. Inline footnotes (^[Footnote text]) are also supported. Highlights use theme colours; code and escaped syntax are left alone. Repeated references have distinct backlinks. Lapis reuses highlight and footnote support already registered on the Markdown parser, preserving existing footnote renderers. Extensions that register plugins afterward or use different conventions are not covered by this compatibility check.
  • Preview wikilinks resolve through the same vault index, including heading anchors and unsaved target headings. Missing links have a dotted underline; ambiguous links have a dashed underline and list candidates in their tooltip. Colours follow the VS Code theme. Target changes refresh open previews.

Lapis never automatically rewrites or saves notes. Explicit authoring commands edit the active buffer only. There is no database, hidden vault metadata, graph view, or application-specific note container. Optional .base files are plain-text view definitions using the documented Lapis syntax.

Content Authoring

Commands are the primary authoring interface for Lapis: tables and wikilinks now, and callouts in a future slice. Completion is an optional aid, not the main workflow. Changes are explicit, undoable and never automatically saved.

.base Views

In Lapis, a Base is a saved view over note properties, not a separate database. Create a YAML .base file inside a vault to define read-only table and Kanban views over its Markdown notes. Run Lapis: Open Base Preview from the Command Palette or use the file's editor-title preview button or Explorer context menu. Switch between Source and Preview using VS Code's editor-title toolbar in the same editor group. The preview includes view tabs, search, layout/grouping toggles and property visibility controls. Use a note's bell to schedule a persistent date reminder through VS Code notifications, or Lapis: Manage Note Reminders to open or cancel alerts. Reminders survive restarts in the same workspace; overdue alerts appear on the next launch, not while VS Code is closed. See Creating .base views for the supported YAML syntax, filters, ordering, grouping, reminders, and examples.

Markdown Tables

Place a single cursor inside an existing table and use the Command Palette, Ctrl+., or the Lapis: Table editor context submenu:

  • Format Table and Align Column Left/Center/Right.
  • Insert Table Row Above/Below and Delete Table Row.
  • Insert Table Column Left/Right and Delete Table Column.

These commands work in any Markdown buffer, including untitled documents and notes outside vaults. They change only the target table, preserve its container prefixes and line endings, keep the cursor in a logical cell, and use one undo step. Formatting is idempotent and pads to the widest cell without a width cap or content truncation; CJK and emoji display widths are considered.

Row insertion leaves existing rows unchanged and adds a compact row such as | | |, with the cursor in its first cell. Tab moves to the next cell and Shift+Tab returns to the previous one using native snippet navigation; the last Tab exits after the row. Use Format Table when ready to align the padding.

Column insertion also adds compact empty cells without changing existing cell content or padding. The cursor starts in the new header cell; Tab proceeds down the new column, skipping the separator, and Shift+Tab goes back. The last Tab exits at the end of the last editable row. Missing cells in ragged tables are completed so the new column has the same position throughout the table.

Escaped pipes and pipes inside code spans are preserved. Native GFM previews still require escaped pipes inside code spans to render those cells correctly. Code fences and frontmatter are excluded. The header/separator and last column cannot be deleted. Lapis registers no document formatter and performs no format-on-save. Creating a new table is a separate, not-yet-implemented command (#15).

Try It

Requires Node.js 24 and VS Code 1.140.0 or newer. pnpm is the selected package manager; these commands also work without a global pnpm installation:

npx --yes pnpm@10 install
npx --yes pnpm@10 run compile

Press F5 in this project to launch Run Lapis in an Extension Development Host. Open a folder containing or inside a .lapis vault in that window, then run Lapis: Open Note from the Command Palette. F5's build task uses pnpm through npx.

The index is read-only and can operate in Restricted Mode. Desktop/local workspaces are the currently verified target. Virtual workspaces are not supported; remote behavior has not been certified.

Index Rules

  • Files must have a .md extension, including mixed-case extensions.
  • Files are UTF-8; notes larger than 2 MiB are skipped and logged.
  • YAML 1.2 preserves ordinary date values as strings, rather than implicitly converting them into JavaScript dates. Derived date semantics come later.
  • Frontmatter must be a mapping with unique string keys. Unsupported tags, aliases, and non-finite numeric values produce diagnostics.
  • title in frontmatter supplies the navigation title; otherwise the filename without .md is used. File identity is its URI, not its display title.
  • Editor buffers take precedence over disk content. Event updates are debounced by 100 ms. Nothing is automatically saved.
  • lapis.excludedFolders lists directory names excluded at any depth. Defaults: .git, node_modules, dist, out, and .vscode-test. Entries in this setting and enabled files.exclude patterns are both respected. Recursive watcher events may also be suppressed by files.watcherExclude; rebuild to recover.

The index recognizes [[Note]], [[Note|Label]], [[Note#Heading]], and ![[Note]] in Markdown body text, excluding fenced/indented code, inline code, and escaped syntax. Escaped alias separators ([[Note\|Label]]) are supported inside Markdown tables and ordinary body text. Heading line numbers are zero-based.

Heading references match the heading text exactly; a missing heading opens the top of the target note. Editor link ranges include aliases and embed syntax. Preview links use native Markdown navigation and respect markdown.preview.openMarkdownLinks. Outside indexed vaults, wikilinks remain ordinary Markdown text. Embeds remain raw text in the preview and do not yet render target contents.

Resolution checks explicit relative paths, then local/root-relative candidates, then a unique basename within the source vault. /Note is explicitly vault-root-relative. Names are case-sensitive, ambiguous matches are not guessed, and an empty target with a heading refers to the current note. Current rename handling updates index identity only; it does not rewrite inbound links.

Checks

npx --yes pnpm@10 test
npx --yes pnpm@10 run compile
npx --yes pnpm@10 run test:integration
npx --yes pnpm@10 run package

Unit tests cover parsing, link resolution, backlinks, and index races. Editor-decoration tests cover resolver states, source-version guards, visible editors, target lifecycle updates, code exclusions and disposal. Integration tests launch a separate Extension Host against a temporary vault; they cover marker discovery and lifecycle, multi-root namespace sharing and isolation, index exclusions, native wikilink navigation, preview metadata hiding, heading IDs, encoded preview URLs, target lifecycle changes and native completion ranges/unsaved headings. Completion unit tests include a 10,000-note fixture with a measured generation threshold of 50 ms. Actual webview clicks and theme appearance also need a manual F5 check. The runner removes its fixture on exit and uses an isolated VS Code profile. By default it downloads VS Code 1.140.0. To use an existing installation:

VSCODE_EXECUTABLE='/Applications/Visual Studio Code.app/Contents/MacOS/Code' \
	npx --yes pnpm@10 run test:integration

package builds the production bundle; it does not publish an extension or create a VSIX. No telemetry or network service is used by Lapis at runtime.

Next Slices

See the architecture and implementation sequence. Next are backlinks UI and practical rename safety, frontmatter mutations, editable Bases/Kanban, Timeline, and bounded note embedding.

Install In An Existing VS Code Window

Install Lapis — Markdown Workspaces from the VS Code Marketplace.

If you previously installed the Lapislazuli VSIX, uninstall that extension before installing Lapis to avoid running both copies. The extension identifier has changed: commands now use lapis.*, and the folder exclusion setting is lapis.excludedFolders. Move any customized value from lapislazuli.excludedFolders to the new setting and update custom keybindings that reference the old commands. No automatic settings migration is performed. Vault markers remain .lapis; notes and vault directories need no changes.

Create a local VSIX (the prepublish step builds and checks the extension):

npx --yes --package pnpm@10.34.6 --package @vscode/vsce@4.0.0 -- vsce package --no-dependencies

Dependencies are bundled in dist/extension.js. In VS Code, use Extensions → … → Install from VSIX and select lapis-0.1.0.vsix. Reload the window if prompted. Rebuild and reinstall the VSIX after source changes.

Version Builds And Marketplace Publishing

The release workflow builds tags matching v*. The tag must exactly match v plus the version in package.json. It installs locked dependencies, runs unit tests, type-check and lint, creates a VSIX, and uploads it as a workflow artifact and a GitHub release asset. Tag builds do not publish to the Marketplace.

To release a new version, update the manifest version and changelog, commit, then push an annotated tag such as v0.1.1. The existing v0.1.0 tag predates the Marketplace manifest and workflow; do not move or reuse it.

For Marketplace publishing:

  1. Add the repository Actions secret VSCE_PAT: an Azure DevOps personal access token with Marketplace > Manage, belonging to an account authorized for the marianoviola publisher. Never commit the token.
  2. In Actions > Version build and Marketplace publish > Run workflow, use the workflow on main, enter the exact release tag, and enable Publish this version to the VS Code Marketplace.
  3. The workflow rebuilds and validates that tagged source, then publishes the resulting VSIX. Leaving the checkbox off only builds a downloadable artifact.

Marketplace versions cannot be overwritten. Since 0.1.0 is already published, use a new version for the next publication. The workflow does not increment versions, create tags, or publish on an ordinary branch push.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft