Glyphary Manual

Plugin authoring

Write small, vault-scoped extensions for Glyphary.

Plugins can add command palette actions, load declared stylesheets, insert templates, and run short WASM text transforms. Plugins do not get shell access, direct DOM access, arbitrary vault filesystem access, background daemons, or network access.

Plugin Location

<vault root>/.glyphary/plugins/<plugin id>/plugin.json
.glyphary/plugins/meeting_tools/
  plugin.json
  styles.css
  templates/agenda.md
  plugin.wasm

The plugin directory name must match the manifest id.

Enabling A Plugin

  1. Copy the plugin directory into <vault root>/.glyphary/plugins.
  2. Open Settings and go to the Plugins tab.
  3. Click Refresh if the plugin was added while Settings was open.
  4. Enable the plugin and save settings.

Enabled plugin commands appear in the command palette.

Manifest

Every plugin must have a plugin.json file.

{
  "id": "meeting_tools",
  "name": "Meeting Tools",
  "runtime": "glyphary-wasm-transform@1",
  "version": "0.1.0",
  "description": "Commands and styles for meeting notes.",
  "permissions": ["document:write", "styles:load"],
  "styles": ["styles.css"],
  "commands": [
    {
      "id": "insert_agenda",
      "title": "Insert Agenda",
      "template": "templates/agenda.md"
    },
    {
      "id": "insert_decision_callout",
      "title": "Insert Decision Callout",
      "insertMarkdown": "::: callout note \"Decision\"\\nDecision:\\n\\nOwner:\\n:::\\n"
    }
  ]
}
idRequired. Must match the directory name.
nameRequired. Display name shown in Settings.
runtimeRequired. Currently only glyphary-wasm-transform@1 is supported.
permissionsOptional declared permissions. Unsupported values make the plugin invalid.
stylesOptional CSS files to load when enabled.
commandsOptional command palette actions.

Runtime

The current runtime is glyphary-wasm-transform@1. It is not WASI, and it is not Extism.

Permissions

document:read
document:write
selection:read
selection:write
styles:load

Command Actions

insertMarkdownInserts literal Markdown at the cursor or selection.
templateReads a declared template file and inserts it.
wasmRuns a pure WASM transform in a Web Worker.
{
  "id": "uppercase_selection",
  "title": "Uppercase Selection",
  "wasm": {
    "module": "plugin.wasm",
    "input": "selection",
    "output": "replaceSelection",
    "timeoutMs": 200
  }
}

WASM Transform ABI

Runtime glyphary-wasm-transform@1 loads a raw WebAssembly module with no imports:

WebAssembly.instantiate(bytes, {})

The module must export:

memory
alloc(length) -> pointer
transform(pointer, length) -> outputPointer

It may also export dealloc(pointer, length).

outputPointer
  +0  u32 little-endian output byte length
  +4  UTF-8 output bytes

Examples

Rust Example

The sample Rust plugin lives at examples/plugins/uppercase_selection_rust.

rustup target add wasm32-unknown-unknown
cargo build --manifest-path examples/plugins/uppercase_selection_rust/Cargo.toml \
  --release \
  --target wasm32-unknown-unknown

Generated WASM Example

The dependency-free generated sample lives at examples/plugins/uppercase_selection.

Plugin Styles

Plugins can declare stylesheets and should follow the same public styling contract as CSS snippets; see the theming reference.

{
  "permissions": ["styles:load"],
  "styles": ["styles.css"]
}

Validation Limits

  • Plugin manifest must be named plugin.json.
  • Manifest id must match the plugin directory name.
  • Manifest runtime must be glyphary-wasm-transform@1.
  • Unknown runtimes, permissions, input modes, output modes, and file extensions make the plugin invalid.

Security Model

  • Plugins are installed per vault and disabled until approved in Settings.
  • Plugin files are restricted to their own plugin directory.
  • WASM runs in a Web Worker with no imports and bounded timeouts.
  • Use WASM only for deterministic text transforms.