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
loadidempotent 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