Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Hooks & Events

Perry plugins communicate through hooks, events, and tools.

Hook Modes

Hooks support three execution modes:

Filter Mode (default)

Each plugin receives data and returns (possibly modified) data. The output of one plugin becomes the input of the next:

api.registerHook("transform", (data) => {
  data.content = data.content.toUpperCase();
  return data; // Returned data goes to next plugin
});

Action Mode

Plugins receive data but return value is ignored. Used for side effects:

api.registerHook("onSave", (data) => {
  console.log(`Saved: ${data.path}`);
  // Return value ignored
});

Waterfall Mode

Like filter mode, but specifically for accumulating/building up a result through the chain:

api.registerHook("buildMenu", (items) => {
  items.push({ label: "My Plugin Action", action: () => {} });
  return items;
});

Hook Priority

Lower priority numbers run first:

api.registerHook("beforeSave", validate, 10);   // Runs first
api.registerHook("beforeSave", transform, 20);   // Runs second
api.registerHook("beforeSave", log, 100);         // Runs last

Default priority is 50.

Event Bus

Plugins can communicate with each other through events:

Emitting Events

// From a plugin
api.emit("dataUpdated", { source: "my-plugin", records: 42 });

// From the host
import { emitEvent } from "perry/plugin";
emitEvent("dataUpdated", { source: "host", records: 100 });

Listening for Events

api.on("dataUpdated", (data) => {
  console.log(`${data.source} updated ${data.records} records`);
});

Tools

Plugins register callable tools:

// Plugin registers a tool
api.registerTool("formatCode", (args) => {
  return formatSource(args.code, args.language);
});
// Host invokes the tool
import { invokeTool } from "perry/plugin";

const formatted = invokeTool("formatCode", {
  code: "const x=1",
  language: "typescript",
});

Configuration

Hosts can pass configuration to plugins:

// Host sets config
import { setConfig } from "perry/plugin";
setConfig("theme", "dark");
setConfig("maxRetries", "3");
// Plugin reads config
export function activate(api: PluginAPI) {
  const theme = api.getConfig("theme");     // "dark"
  const retries = api.getConfig("maxRetries"); // "3"
}

Introspection

Query loaded plugins and their registrations:

import { listPlugins, listHooks, listTools } from "perry/plugin";

const plugins = listPlugins();  // [{ name, version, description }]
const hooks = listHooks();      // [{ name, pluginName, priority }]
const tools = listTools();      // [{ name, pluginName }]

Next Steps