Plugins are first-class runtime modules that can register:
- Connectors
- Tools
Plugins execute in the same Node.js process as the engine. There is no VM isolation, so module caches and globals are shared across plugin instances. Treat plugins as trusted code.
Each plugin type is described by a JSON descriptor (plugin.json in the
plugin folder) and a module that exports a
plugin object (or default export) with:
settingsSchema(Zod) to validate instance settingscreate(api)returning{ load?, unload? }
The plugin API surface is intentionally narrow:
api.instance:{ instanceId, pluginId, enabled }api.settings: validated settings for the instanceapi.engineSettings: full engine settings snapshotapi.registrar: connector/inference/tool/image registrationapi.auth: auth store (providers use the provider/plugin id; other plugins typically use instance id)api.fileStore: shared file storeapi.logger: per-plugin loggerapi.mode:"runtime"or"validate"(used duringgram addvalidation)api.engineEvents: engine event bus (optional)api.events.emit({ type, payload }): enqueue plugin events
Load/unload is internal: the plugin manager reconciles enabled instances from
.scout/settings.json and loads or unloads instances to match.
{
"id": "telegram",
"name": "Telegram",
"description": "Telegram connector and incoming message adapter.",
"entry": "./plugin.js"
}{
"plugins": [
{
"instanceId": "telegram",
"pluginId": "telegram",
"enabled": true,
"settings": { "polling": true }
}
]
}Plugin events are queued and processed sequentially. Each event is persisted in memory with metadata for later routing:
id(generated)pluginIdinstanceIdtypepayloadcreatedAt
Each instance gets a dedicated data directory:
.scout/plugins/<instanceId>
Credentials are stored in .scout/auth.json and keyed by the identifier the plugin uses.
Provider plugins store credentials under the provider id (same as pluginId), not the random instance id.
flowchart TD
Settings["settings.json"] --> Manager["PluginManager"]
Manager --> Loader["PluginModuleLoader"]
Loader --> Plugin["Plugin instance<br/>load()/unload()"]
Plugin --> Registrar["PluginRegistrar"]
Plugin --> Events["PluginEventQueue"]
Registrar --> Connectors["ConnectorRegistry"]
Registrar --> Inference["InferenceRegistry"]
Registrar --> Tools["ToolResolver"]
Registrar --> Images["ImageGenerationRegistry"]
Events --> Engine["PluginEventEngine"]
telegram(connector)brave-search(tool)memory(tool + storage)
Providers are built-in modules (not plugins). They register inference and/or image
generation capabilities and are configured in .scout/settings.json.