Basic Plugin
A simple plugin uses the@Plugin decorator:
Using Plugins
Attach plugins at app scope:Dynamic Plugin with Options
For plugins that need runtime configuration, extendDynamicPlugin:
Type-Safe Options with Zod
For complex options with defaults, use Zod schemas with two types:my-plugin.types.ts
my-plugin.plugin.ts
Option-Derived Providers and Nested Plugins
The providers a plugin derives from its options (dynamicProviders(options) and init({ providers })) are registered before the plugin’s nested plugins are built. A nested plugin can therefore inject them, for example through init({ inject, useFactory }):
MyPlugin.init(options) and MyPlugin.init({ inject, useFactory }). In the factory form, the factory runs first, and the providers derived from the options it returns are registered before the nested plugins.
Because option-derived providers are registered first, they cannot inject a provider that a nested plugin exports.
Keep those dependencies in the nested plugin, or read them at runtime with
this.get(...).Installing a Plugin in Several Apps
Each app that installs a plugin gets its own copy of the plugin’s providers, CONTEXT-scoped ones included. Tools, resources and prompts resolve the providers of the plugins their own app installed, sothis.approval, this.featureFlags or this.remember in one app never resolve to another app’s configuration:
this.approval inside RefundTool is written to billingStorage, and one made inside DeployTool is written to opsStorage.
Adding Hooks
Plugins can intercept flow stages using hooks. Usethis.get(Token) to access providers:
Contributing Skills
Plugins can contribute skills that teach AI how to perform workflows using the plugin’s tools:searchSkills results alongside app-level skills and can be loaded with loadSkill.
Available Hooks
ToolHook (tools:call-tool)
Intercept tool execution flow:ListToolsHook (tools:list-tools)
Intercept tool listing flow:Hook Timing
.Will(stage)- runs before the stage.Did(stage)- runs after the stage
DynamicPlugin API
The
init() method accepts your plugin’s input options type and returns a provider
configuration that the framework uses internally. You don’t need to import or reference
the return type—just pass the result directly to the plugins array.Extending Tool Metadata
Plugins can extend the global tool metadata interface:Plugin Scope
By default, plugins operate at the app scope - their hooks only fire for requests to that specific app. For cross-app functionality, you can use server scope.App Scope (Default)
Hooks fire only for requests to the app where the plugin is registered:Server Scope
Hooks fire at the gateway level for all apps in the server:When to Use Each Scope
Accessing Other Apps (Server Scope)
Server-scoped plugins can access other apps viascope.apps: