Plugins

Want to make your own?

Anyone can build a plugin — it's just two files in a GitHub repo. Jump to #Writing your own plugin.

Your garden has a small core: it turns published notes into a website. Everything else, search, link previews, the file tree, comments, analytics, is a plugin. Plugins are stored inside your own garden repository under src/plugins/, they survive template updates untouched, and anyone can write and share one as a GitHub repo.

Customizing your garden has always been possible. Custom components, user styles, editing the template. But it was cumbersome, and there was no good way to share what you built with other gardeners. Plugins change that: a customization is now a thing you install with one click, configure from Obsidian, and publish for everyone else by creating a GitHub repo.

This page covers installing plugins and writing your own. (Your existing custom components and styles keep working exactly as before. Plugins sit alongside them, and your customizations always get the last word.)

Installing plugins

Everything happens in Obsidian under Settings → Digital Garden → Plugins → Manage plugins. It works the same whether your garden is self-hosted or on Forestry.md.

The Browse & install tab shows the community plugin gallery. Search, pick a plugin, click Install, and review the confirmation. t names the author and version, counts the files, and links to the source code. Confirming copies the plugin's files into your repository as a single commit. Your site rebuilds automatically, and the plugin is live when the build finishes.

From a GitHub URL

Any public GitHub repo with a garden-plugin.json at its root is an installable plugin — it doesn't need to be in the gallery. Paste its URL into Install from GitHub (any shape works: user/repo, a full URL, even a deep link), click Check plugin, and confirm.

There's also a command for this: open the command palette and run Digital Garden: Install garden plugin from URL.

Only install plugins you trust

A plugin's code runs in your site's build and in your visitors' browsers. Installation itself never runs any plugin code, but the build does. The confirmation links straight to the source so you can read it first. (Or ask an AI agent to review it)

Turning plugins on and off

Every installed plugin has a toggle in the Installed tab. Disabling doesn't delete anything — the files stay in your repository, the plugin just stops being part of your site until you re-enable it. This includes the core plugins that ship with every garden: don't want search? Toggle dg-search off.

Your choices live in src/plugins/plugins.json in your garden repository — visible, versioned, and hand-editable if you prefer working in the repo.

Some plugins replace a part of the site instead of adding to it. Alternative navigations like MOC Navigation or Tag Navigation take over the file tree's spot. Only one navigation can be active at a time: when you install one, the confirmation offers to disable the current provider for you. The installed list always shows which plugin provides navigation and warns when an enabled plugin is being blocked by another.

Configuring plugins

Plugins with options show a Settings button on their row. The form is generated from the plugin's manifest and saves to your repository, so configuration follows the garden, not the device.

Many plugins also support per-note switches in frontmatter, like every other dg- flag:

---
dg-publish: true
dg-enable-search: false   # this note stays out of search
comments: false           # no comments under this note
---

Each plugin's settings and README document what it supports.

Updating and uninstalling

Community plugin rows have Update (fetches the plugin's latest release and asks before changing anything) and Uninstall (removes exactly the files the plugin brought, in one commit). Core dg- plugins update together with your site template, so they have no separate buttons.

Installing by hand

Prefer the terminal? A plugin is just a folder:

cd your-garden-repo
git clone https://github.com/user/garden-plugin-example src/plugins/example
rm -rf src/plugins/example/.git
git add . && git commit -m "Install example plugin" && git push

Any folder in src/plugins/ with a valid garden-plugin.json is live on the next build. No registration step.

Writing your own plugin

A working plugin is two files. Here's one that puts a reading-time badge under every note title:

garden-plugin.json

{
  "id": "reading-time",
  "name": "Reading Time",
  "version": "1.0.0",
  "description": "Estimated reading time under each title.",
  "author": "Your Name",
  "slots": { "notes.header": "templates/badge.njk" }
}

templates/badge.njk

<div class="reading-time">
  {{ ((content | striptags).split(" ").length / 200) | round }} min read
</div>

The manifest declares which surfaces the plugin uses:

A misbehaving plugin never breaks a build — every problem becomes a [plugins] warning in the build log and the rest of the site builds normally.

The fast way: let an AI agent build it

The garden template ships an Agent Skill that teaches AI coding tools the entire plugin API — every slot, hook, setting mechanism, the testing workflow, and how to publish. Install it into Claude Code, Cursor, or any harness that supports skills:

npx skills add oleeskild/digitalgarden

Then just describe what you want:

"Create a garden plugin that adds a photo lightbox to my notes"

The skill keeps the agent inside the rules that matter: valid manifests, safe paths, self-gating templates, no install-time code execution, and small auditable output. It also knows the dev loop and the publishing steps, so the agent can take a plugin from idea to tagged release.

Developing by hand

  1. Clone the garden template and run npm install.
  2. Create src/plugins/my-plugin/ with a garden-plugin.json.
  3. Run npm run dev — template and style edits hot-reload; restart after changing hooks or the manifest.
  4. Watch the build log for [plugins] warnings — that's the loader telling you what it didn't like.

The template's own core plugins in src/plugins/ are the best reference code — dg-link-preview is the smallest, and dg-filetree shows how a navigation plugin should be built. The full author guide lives in the template repo at docs/PLUGINS.md.

Publishing

  1. Push the plugin as its own public GitHub repo with garden-plugin.json at the top level. A good name: garden-plugin-reading-time.
  2. Tag a release matching your manifest version: git tag v1.0.0 && git push --tags. Installs prefer your latest release, so users get stable versions while you keep working on the default branch.
  3. Share the URL. Anyone can install from it immediately.
  4. To appear in the community gallery, open a pull request against digitalgarden-plugins adding one entry to community-plugins.json: your plugin's id, name, author, description, repo, and an optional screenshot.
Two rules for a good citizen plugin

Never require an install-time setup step. Installation must be pure file copying. And keep the code small enough that a cautious user can read it before trusting it.

Powered by Forestry.md