Skip to content

Plugin System

Mia’s plugin system abstracts AI providers behind a common interface. You can swap between backends without changing your workflow, and configure automatic fallback chains.

Every plugin implements the CodingPlugin interface:

interface CodingPlugin {
name: string
version: string
initialize(config: PluginConfig): Promise<void>
dispatch(prompt, context, options, callbacks): Promise<PluginDispatchResult>
isAvailable(): Promise<boolean>
getSession(conversationId: string): string | undefined
clearSession(conversationId: string): void
abort(taskId: string): Promise<void>
getRunningTaskCount(): number
cleanup(maxAgeMs?: number): number
}
MethodPurpose
dispatch()Send a prompt with context, receive streamed response
isAvailable()Check if the plugin’s binary/API is accessible
getSession()Retrieve session state for multi-turn conversations
abort()Cancel a running dispatch
cleanup()Remove stale sessions older than threshold
  • Binary: claude
  • Provider: Anthropic
  • Features: Session resumption, tool use, multi-turn context
  • Auth: Claude Max/Pro browser login or ANTHROPIC_API_KEY
  • Binary: codex
  • Provider: OpenAI
  • Features: CLI-based dispatch, streaming output
  • Auth: OPENAI_API_KEY
  • Binary: gemini (CLI) or API
  • Provider: Google
  • Features: OAuth authentication, large context windows
  • Auth: GEMINI_API_KEY or browser OAuth flow
  • Binary: opencode
  • Provider: Various (configurable)
  • Features: Multi-provider routing
  • Auth: Provider-specific API keys

Each plugin is configured in ~/.mia/mia.json:

{
"activePlugin": "claude-code",
"fallbackPlugins": ["opencode", "codex"],
"plugins": {
"claude-code": {
"name": "claude-code",
"enabled": true,
"binary": "claude",
"model": "claude-sonnet-4-6-20250929",
"maxConcurrency": 3,
"timeoutMs": 1800000
},
"gemini": {
"name": "gemini",
"enabled": true,
"model": "gemini-2.5-pro"
}
}
}

When a prompt is dispatched:

  1. Load active plugin from registry
  2. Check availability (cached result, refreshed periodically)
  3. If unavailable, try fallback chain in order
  4. Build context (workspace, memory, git state)
  5. Spawn plugin process or call API
  6. Stream NDJSON callbacks (tokens, tool calls, results)
  7. Accumulate output, handle errors
  8. Capture git changes made during dispatch

CLI-based plugins (Claude Code, Codex) share a common base class BaseSpawnPlugin that handles:

  • Process spawning with proper environment
  • Stdin/stdout streaming (NDJSON protocol)
  • Session management (resume conversation by ID)
  • Timeout handling (kill process after configurable duration)
  • Stall detection (kill if no output for 120 seconds)
  • Concurrency limiting

When the active plugin fails or is unavailable:

Active plugin → Fallback #1 → Fallback #2 → Error

Configure in mia.json:

{
"activePlugin": "claude-code",
"fallbackPlugins": ["gemini", "codex"],
"pluginDispatch": {
"fallback": {
"enabled": true,
"onDispatchError": false
}
}
}
  • enabled: Activate fallback for availability failures
  • onDispatchError: Also retry fallback chain on dispatch errors (aggressive)

All plugins throw standardized PluginError with error codes:

CodeMeaning
TIMEOUTPlugin didn’t respond within timeout
SPAWN_FAILURECouldn’t start the plugin process
PROCESS_EXITPlugin process exited unexpectedly
BUFFER_OVERFLOWOutput exceeded buffer limits
CONCURRENCY_LIMITMax concurrent tasks reached
PROVIDER_ERRORAI provider returned an error
SESSION_ERRORSession state issue
UNKNOWNCatch-all