Plugin API

The APIs you can use when writing a plugin for Novelist.

Novelist plugins are written in JavaScript / TypeScript. They talk to the app through @novelist/plugin-api, a thin runtime that exposes the editor’s capabilities.

Hello, plugin

import type { Plugin } from '@novelist/plugin-api';

const plugin: Plugin = {
  async onLoad(ctx) {
    ctx.commands.register({
      id: 'my-plugin.say-hello',
      title: 'Say hello',
      run: async () => {
        ctx.notifications.info('Hello from my plugin!');
      },
    });
  },
};

export default plugin;

What ctx exposes

NamespacePurpose
ctx.commandsRegister / unregister commands, execute other commands
ctx.editorRead and write the current document, move the cursor, batch edits
ctx.workspaceEnumerate open documents, listen for open/close events
ctx.uiAdd views in the sidebar, status bar, or command palette
ctx.eventsSubscribe to documentSaved, documentOpened, editorChanged, etc.
ctx.settingsRead and write the plugin’s own settings
ctx.notificationsShow info / progress / error toasts

The full type definitions live in the app repo: creating-plugins.md.

Lifecycle

onLoad(ctx)    // called when the plugin is enabled
onUnload(ctx)  // called when the plugin is disabled / removed

When your plugin is disabled, every command and view it registered must be disposed — ctx.disposables provides a Disposable aggregator you can push onto and drain on unload.

Permission model

If your plugin needs to read document content, declare "read" in manifest.toml; for writes, add "write". ctx.editor methods only run if the plugin declared the right permission; otherwise they throw PermissionError.

Packaging

pnpm install
pnpm build         # produces dist/
pnpm pack          # emits <id>-<version>.zip

Attach the ZIP as a GitHub Release asset, then follow Submitting a plugin to land the manifest in the marketplace.