Plugin API
Mia’s plugin system is designed for extensibility. Each AI backend implements the CodingPlugin interface, and the daemon handles dispatch, fallback, and lifecycle management.
CodingPlugin Interface
Section titled “CodingPlugin Interface”interface CodingPlugin { /** Plugin identifier (e.g., "claude-code", "gemini") */ name: string
/** Plugin version string */ version: string
/** Initialize with configuration */ initialize(config: PluginConfig): Promise<void>
/** Dispatch a prompt and stream response */ dispatch( prompt: string, context: PluginContext, options: DispatchOptions, callbacks: DispatchCallbacks ): Promise<PluginDispatchResult>
/** Check if plugin binary/API is accessible */ isAvailable(): Promise<boolean>
/** Get session ID for a conversation */ getSession(conversationId: string): string | undefined
/** Clear session state for a conversation */ clearSession(conversationId: string): void
/** Abort a running dispatch */ abort(taskId: string): Promise<void>
/** Number of currently running dispatches */ getRunningTaskCount(): number
/** Clean up stale sessions */ cleanup(maxAgeMs?: number): number}PluginConfig
Section titled “PluginConfig”interface PluginConfig { name: string // Plugin identifier enabled: boolean // Whether plugin is active binary?: string // Path to CLI binary model?: string // Default model maxConcurrency: number // Max concurrent dispatches timeoutMs: number // Dispatch timeout}PluginContext
Section titled “PluginContext”Assembled by ContextPreparer before each dispatch:
interface PluginContext { /** Relevant facts from memory store */ memoryFacts: string[]
/** Compressed codebase summary (languages, frameworks) */ codebaseContext: string
/** Git branch, recent commits, staged changes */ gitContext: string
/** File structure, recently modified files */ workspaceSnapshot: string
/** Contents of .claude-code-instructions if present */ projectInstructions: string
/** Compacted summary of prior conversation turns */ conversationSummary?: string}DispatchCallbacks
Section titled “DispatchCallbacks”Plugins stream responses via typed callbacks:
interface DispatchCallbacks { /** Called for each streaming token */ onToken(token: string): void
/** Called when a tool is invoked */ onToolCall(tool: ToolCallInfo): void
/** Called when a tool returns a result */ onToolResult(result: ToolResultInfo): void
/** Called when dispatch completes */ onComplete(result: PluginDispatchResult): void
/** Called on error */ onError(error: PluginError): void}PluginDispatchResult
Section titled “PluginDispatchResult”interface PluginDispatchResult { /** Full accumulated response text */ content: string
/** Token usage statistics */ usage?: { inputTokens: number outputTokens: number cacheCreation?: number cacheRead?: number }
/** Session ID for conversation continuity */ sessionId?: string
/** List of tool calls made during dispatch */ toolCalls?: ToolCallInfo[]
/** Duration in milliseconds */ durationMs: number}PluginError
Section titled “PluginError”All plugins throw standardized errors:
class PluginError extends Error { code: PluginErrorCode pluginName: string detail?: string}
type PluginErrorCode = | 'TIMEOUT' | 'SPAWN_FAILURE' | 'PROCESS_EXIT' | 'BUFFER_OVERFLOW' | 'CONCURRENCY_LIMIT' | 'PROVIDER_ERROR' | 'SESSION_ERROR' | 'UNKNOWN'BaseSpawnPlugin
Section titled “BaseSpawnPlugin”CLI-based plugins (Claude Code, Codex) extend BaseSpawnPlugin, which provides:
- Process spawning — Starts the CLI binary with correct args and environment
- NDJSON streaming — Parses stdout as newline-delimited JSON
- Session management — Maps conversation IDs to session IDs for resume
- Timeout handling — Kills process after configurable duration
- Stall detection — Kills process if no output for 120 seconds
- Concurrency limiting — Rejects dispatch if at max concurrent tasks
Extending BaseSpawnPlugin
Section titled “Extending BaseSpawnPlugin”To add a new CLI-based plugin:
import { BaseSpawnPlugin } from '../base-spawn-plugin.js'
export class MyPlugin extends BaseSpawnPlugin { name = 'my-plugin' version = '1.0.0'
protected buildArgs(prompt: string, context: PluginContext): string[] { return ['--model', this.config.model, '--prompt', prompt] }
protected parseOutput(line: string): ParsedOutput { // Parse your CLI's output format const data = JSON.parse(line) return { type: data.type, content: data.content } }}Registering a Plugin
Section titled “Registering a Plugin”Plugins are registered in the daemon’s plugin registry during initialization:
registry.register('my-plugin', new MyPlugin())The plugin then becomes available for selection via:
mia plugin switch my-pluginAPI-Based Plugins
Section titled “API-Based Plugins”For plugins that call HTTP APIs directly (like Gemini), implement CodingPlugin directly without extending BaseSpawnPlugin. Handle HTTP requests, authentication, and streaming within the dispatch() method.