Writing Plugins
PAREL's runtime capabilities come from plugins. Model providers and the plugin system are configured separately.
# Plugin Interface
A plugin is exported via definePlugin() and registers hooks, tools, and capabilities in setup(ctx):
▓ my-plugin/src/index.ts
import { definePlugin, LifecycleEvent } from "@parel/plugin-sdk";
export default definePlugin({
name: "@example/my-custom-tool",
version: "0.1.0",
async setup(ctx) {
ctx.tool(
{
name: "my_tool",
description: "Does something useful",
parameters: {
type: "object",
properties: {
input: { type: "string", description: "The input" },
},
required: ["input"],
},
},
async (params) => {
return `Processed: ${params.input}`;
},
);
ctx.hook(LifecycleEvent.ContextBuild, async (hookCtx) => {
return {
action: "continue",
mutations: {
system: hookCtx.system
? `${hookCtx.system}\n\nBe concise.`
: "Be concise.",
},
};
});
},
});ctx.tool(definition, handler) takes a JSON-schema tool definition and a handler. The handler receives (params, toolCtx) and returns a string tool result.
# Available Hooks
▓ lifecycle
ctx.hook(LifecycleEvent.SessionStart, handler) ctx.hook(LifecycleEvent.SessionResume, handler) ctx.hook(LifecycleEvent.SessionSuspend, handler) ctx.hook(LifecycleEvent.SessionEnd, handler) ctx.hook(LifecycleEvent.TurnStart, handler) ctx.hook(LifecycleEvent.TurnEnd, handler) ctx.hook(LifecycleEvent.StepStart, handler) ctx.hook(LifecycleEvent.ContextBuild, handler) ctx.hook(LifecycleEvent.ModelBefore, handler) ctx.hook(LifecycleEvent.ModelAfter, handler) ctx.hook(LifecycleEvent.ToolBefore, handler) ctx.hook(LifecycleEvent.ToolAfter, handler) ctx.hook(LifecycleEvent.StepEnd, handler) ctx.hook(LifecycleEvent.Checkpoint, handler) ctx.hook(LifecycleEvent.Error, handler)
Hooks can continue, skip, block, suspend, or stop execution. Events that support mutations return action: "continue" plus a mutations object.
# Model Providers
LLM provider adapters are not ordinary plugins. Use the top-level model config to select openai, openai-responses, anthropic, openai-compatible, or anthropic-compatible.
For full examples, see the first-party plugins under
opensource/js/plugins/.