Core Functions
definePlugin()
Defines a plugin with metadata and setup function.
function definePlugin(
name: string,
version: string,
setup: () => Promise<Plugin> | Plugin
): PluginDefinition
Plugin name (used for module identification)
Plugin version (semver format recommended)
setup
() => Promise<Plugin> | Plugin
required
Function that returns the plugin implementation
Example:
import { definePlugin } from '@proj-airi/plugin-sdk'
export default definePlugin('my-plugin', '1.0.0', () => ({
async init(context) {
return true
},
async setupModules(context) {
// Setup logic
}
}))
Plugin Interface
Plugin
The plugin implementation interface.
interface Plugin {
init?: (context: ContextInit) => Promise<void | undefined | false>
setupModules?: (context: ContextInit) => Promise<void | undefined>
}
Plugin initialization hook. Return false to abort initialization.
Module setup hook. Called after configuration is applied.
ContextInit
Context passed to plugin hooks.
interface ContextInit {
channels: {
host: ChannelHost
}
apis: PluginApis
}
Event channel for communicating with the plugin host
APIs for protocol and client operations
Plugin Host API
PluginHost
Manages plugin lifecycle and orchestration.
class PluginHost {
constructor(options?: PluginHostOptions)
async load(manifest: ManifestV1, options?: PluginLoadOptions): Promise<PluginHostSession>
async init(sessionId: string, options?: PluginStartOptions): Promise<PluginHostSession>
async start(manifest: ManifestV1, options?: PluginStartOptions): Promise<PluginHostSession>
async applyConfiguration(sessionId: string, config: ModuleConfigEnvelope): Promise<PluginHostSession>
markConfigurationNeeded(sessionId: string, reason?: string): PluginHostSession
announceCapability(key: string, metadata?: Record<string, unknown>): CapabilityDescriptor
markCapabilityReady(key: string, metadata?: Record<string, unknown>): CapabilityDescriptor
markCapabilityDegraded(key: string, metadata?: Record<string, unknown>): CapabilityDescriptor
withdrawCapability(key: string, metadata?: Record<string, unknown>): CapabilityDescriptor
async waitForCapability(key: string, timeoutMs?: number): Promise<CapabilityDescriptor>
async waitForCapabilities(keys: string[], timeoutMs?: number): Promise<void>
isCapabilityReady(key: string): boolean
listCapabilities(): CapabilityDescriptor[]
listSessions(): PluginHostSession[]
getSession(sessionId: string): PluginHostSession | undefined
stop(sessionId: string): PluginHostSession | undefined
async reload(sessionId: string, options?: PluginStartOptions): Promise<PluginHostSession>
setProvidersListResolver(resolver: () => Promise<Array<{ name: string }>> | Array<{ name: string }>): void
}
PluginHostOptions
interface PluginHostOptions {
runtime?: 'electron' | 'node' | 'web'
transport?: PluginTransport
protocolVersion?: string
apiVersion?: string
supportedProtocolVersions?: string[]
supportedApiVersions?: string[]
}
runtime
'electron' | 'node' | 'web'
Runtime environment. Defaults to 'electron'.
Communication transport. Defaults to { kind: 'in-memory' }.
Preferred protocol version. Defaults to 'v1'.
Preferred API version. Defaults to 'v1'.
PluginStartOptions
interface PluginStartOptions {
cwd?: string
runtime?: 'electron' | 'node' | 'web'
requireConfiguration?: boolean
compatibility?: Omit<ModuleCompatibilityRequest, 'protocolVersion' | 'apiVersion'>
requiredCapabilities?: string[]
capabilityWaitTimeoutMs?: number
}
Working directory for loading plugin files
Stop at configuration-needed phase. Defaults to false.
Capabilities that must be ready before initialization
Timeout for waiting on capabilities. Defaults to 15000ms.
PluginHostSession
interface PluginHostSession {
manifest: ManifestV1
plugin: Plugin
id: string
index: number
cwd: string
identity: ModuleIdentity
phase: PluginSessionPhase
lifecycle: ActorRefFrom<typeof pluginLifecycleMachine>
transport: PluginTransport
runtime: PluginRuntime
channels: {
host: ReturnType<typeof createPluginContext>
}
apis: PluginApis
}
APIs
Protocol APIs
APIs for plugin-host protocol communication.
capabilities
interface CapabilityApis {
wait(key: string, timeoutMs?: number): Promise<CapabilityDescriptor>
snapshot(): Promise<CapabilityDescriptor[]>
}
wait()
Wait for a capability to become ready.
const capability = await apis.protocol.capabilities.wait('llm:openai', 15000)
Capability key to wait for
Timeout in milliseconds. Defaults to 15000.
The capability descriptor when ready
snapshot()
Get current snapshot of all capabilities.
const capabilities = await apis.protocol.capabilities.snapshot()
Array of all capability descriptors
resources.providers
interface ProviderApis {
list(): Promise<Array<{ name: string }>>
}
list()
List available resource providers.
const providers = await apis.protocol.resources.providers.list()
Client APIs
APIs for client-side functionality.
resources.providers
interface ClientProviderApis {
list(): Promise<Array<{ name: string }>>
}
list()
List available providers from client perspective.
const providers = await apis.client.resources.providers.list()
Types
ManifestV1
Plugin manifest structure.
interface ManifestV1 {
apiVersion: 'v1'
kind: 'manifest.plugin.airi.moeru.ai'
name: string
entrypoints: {
default?: string
electron?: string
node?: string
web?: string
}
}
kind
'manifest.plugin.airi.moeru.ai'
required
Manifest kind identifier
Runtime-specific entrypoint paths
ModuleIdentity
interface ModuleIdentity {
id: string
kind: 'plugin'
plugin: {
id: string
labels?: Record<string, string>
}
labels?: Record<string, string>
}
CapabilityDescriptor
interface CapabilityDescriptor {
key: string
state: 'announced' | 'ready' | 'degraded' | 'withdrawn'
metadata?: Record<string, unknown>
updatedAt: number
}
Unique capability identifier
state
'announced' | 'ready' | 'degraded' | 'withdrawn'
required
Current capability state
Additional capability metadata
Unix timestamp of last update
PluginSessionPhase
Plugin lifecycle phases.
type PluginSessionPhase =
| 'loading'
| 'loaded'
| 'authenticating'
| 'authenticated'
| 'announced'
| 'preparing'
| 'waiting-deps'
| 'prepared'
| 'configuration-needed'
| 'configured'
| 'ready'
| 'failed'
| 'stopped'
ModuleConfigEnvelope
Configuration envelope structure.
interface ModuleConfigEnvelope<C = Record<string, unknown>> {
configId: string
revision: number
schemaVersion: number
full: C
}
Unique configuration identifier
Configuration revision number
Configuration schema version
Complete configuration object
Protocol Events
Standard protocol events emitted by the plugin host.
module:authenticate
Request authentication with token.
{
type: 'module:authenticate',
payload: {
token: string
}
}
module:authenticated
Authentication result.
{
type: 'module:authenticated',
payload: {
authenticated: boolean
}
}
module:announce
Announce module to registry.
{
type: 'module:announce',
payload: {
name: string
identity: ModuleIdentity
possibleEvents: string[]
}
}
module:prepared
Module is prepared and ready for configuration.
{
type: 'module:prepared',
payload: {
identity: ModuleIdentity
}
}
module:configuration:needed
Module requires configuration.
{
type: 'module:configuration:needed',
payload: {
identity: ModuleIdentity
reason?: string
}
}
Configuration has been applied.
{
type: 'module:configuration:configured',
payload: {
identity: ModuleIdentity
config: ModuleConfigEnvelope
}
}
Apply configuration to module.
{
type: 'module:configure',
payload: {
config: Record<string, unknown>
}
}
module:status
Module status update.
{
type: 'module:status',
payload: {
identity: ModuleIdentity
phase: PluginSessionPhase
reason?: string
details?: Record<string, unknown>
}
}
registry:modules:sync
Sync module registry.
{
type: 'registry:modules:sync',
payload: {
modules: Array<{
name: string
index?: number
identity: ModuleIdentity
}>
}
}
Best Practices
Always define TypeScript interfaces for your plugin configuration to catch errors early.
Validate all configuration and event payloads before using them.
Wrap async operations in try-catch blocks and emit appropriate status events.
Use descriptive capability keys
Use namespaced capability keys like 'tool:weather' or 'llm:provider:openai'.
Listen for stop events and clean up timers, connections, and other resources.
Next Steps
Creating Plugins
Learn how to build plugins step-by-step
Plugin SDK Overview
Understand plugin architecture and concepts