Writing Plugins

Every capability in PAREL is a plugin. This guide shows how to build your own.

# Plugin Interface

A plugin exports a definePlugin() call that returns hooks and capabilities:

my-plugin/src/index.ts
import { definePlugin } from "@parel/plugin-sdk";

export default definePlugin({
  name: "my-custom-tool",
  version: "0.1.0",

  hooks: {
    onToolsRegister(ctx) {
      ctx.registerTool({
        name: "my_tool",
        description: "Does something useful",
        parameters: {
          type: "object",
          properties: {
            input: { type: "string", description: "The input" },
          },
          required: ["input"],
        },
        async execute({ input }) {
          return { result: `Processed: ${input}` };
        },
      });
    },
  },
});

# Available Hooks

lifecycle
hooks: {
  onToolsRegister(ctx)      // Register custom tools
  onContextBuild(ctx)       // Modify context before model call
  beforeModelCall(ctx)      // Inspect/modify model params
  afterModelCall(ctx)       // Process model response
  beforeToolExec(ctx)       // Gate or modify tool calls
  afterToolExec(ctx)        // Process tool results
  onSessionStart(ctx)       // Session initialization
  onSessionEnd(ctx)         // Cleanup
}

# Model Adapter

To add a new LLM provider, implement registerModelAdapter:

model plugin
hooks: {
  onToolsRegister(ctx) {
    ctx.registerModelAdapter({
      name: "my-provider",
      async call(params) {
        // params: ModelCallParams (messages, tools, config)
        // return: AsyncIterable<ModelStreamChunk>
      },
    });
  },
}
See the first-party plugins in the ts/plugins/ directory for complete examples.