Plugins extend Meridian without modifying the core. Drop a folder into
.meridian/plugins/<your-plugin>/ and Meridian picks it up — with hot
reload. Plain ESM, no build step required.
A minimal plugin
Plugins register commands, react to vault events, and render side panels. The smallest useful example is a word counter:
// .meridian/plugins/word-counter/main.js
export default class WordCounter {
onLoad(api) {
api.registerCommand({
id: 'word-counter:show',
name: 'Word Counter: Show stats',
run: () => {
const text = api.editor.getActiveText() ?? '';
const words = text.trim().split(/\s+/).filter(Boolean).length;
api.ui.toast(`${words} words`);
},
});
}
}
Save the file. The command appears in the palette (⌘K) immediately —
no restart, no rebuild.
Folder layout
A plugin is a folder with one required file:
.meridian/plugins/word-counter/
├── main.js required
├── plugin.json optional — metadata shown in Settings
└── README.md optional — shown in Settings → Plugins
What plugins can do
The api object passed to onLoad lets plugins:
- Register commands that appear in the command palette
- React to vault events — note create, change, delete
- Render side panels in the right sidebar
- Show toasts and notices in the UI
See the source code in the repo for the full type definitions of the
api object.
Hot reload
Save main.js and Meridian re-instantiates the plugin in a fresh
context. The previous instance’s onUnload runs first. No restart
needed.
Distribution
There is no plugin store. Publish the folder to a GitHub repo or share
the zip — users drop it into their .meridian/plugins/ directory.
That’s the whole pipeline.