Plugins

Install providers and other engine capabilities through a stable lifecycle.

Plugins

Plugins are how you install cross-cutting capabilities into the engine without reaching into private fields. A plugin receives a public PluginContext and registers what it owns — usually a provider, sometimes exporters or other services.

Why plugins exist#

The engine needs extension points. Direct mutation of internals makes upgrades fragile and makes it unclear what a process loaded at startup. Plugins declare metadata and capabilities, then register through stable APIs.

import { Engine } from "@shiro-sdk/core";
import { OpenAIPlugin } from "@shiro-sdk/openai";

const engine = new Engine();
engine.use(
  new OpenAIPlugin({
    apiKey: process.env.OPENAI_API_KEY!,
    model: "gpt-5",
  })
);

engine.execute() activates plugins as needed before creating a runner.

When to write a plugin#

Write a plugin when behavior should be installed once and reused across many runs:

  • Provider adapters (@shiro-sdk/openai, future Anthropic/Gemini packages)
  • Trace exporters wired at process start
  • Memory or approval backends shared by all runs
  • Studio / observability integrations

Do not write a plugin for request-specific logic. That belongs in tools, middleware, or session data.

Capabilities#

Plugins advertise capabilities (for example PluginCapability.Provider). That metadata is how tooling — including shiro plugins in the CLI — discovers what is installed.

Best practices#

  • Keep plugin load idempotent and side-effect light
  • Register providers; do not call them during load
  • Pass configuration into the plugin constructor, not globals

Common mistakes#

  • Mutating engine private state
  • Storing the current user on a plugin instance
  • Hiding provider HTTP calls inside unrelated lifecycle hooks