Skip to main content
Agent Orchestrator’s flexibility comes from its plugin architecture. Every major component — from where sessions run to how notifications are delivered — is swappable via plugins.

Plugin System Overview

A plugin is a TypeScript module that implements one of the 8 plugin interfaces defined in packages/core/src/types.ts. Each plugin:
  • Exports a manifest object describing itself
  • Exports a create() function that returns the plugin implementation
  • Uses satisfies PluginModule<T> for compile-time type safety

Plugin Structure

Every plugin follows this pattern:
import type { PluginModule, Runtime } from "@composio/ao-core";

export const manifest = {
  name: "tmux",
  slot: "runtime" as const,
  description: "Runtime plugin: tmux sessions",
  version: "0.1.0",
};

export function create(): Runtime {
  return {
    name: "tmux",
    async create(config) { /* ... */ },
    async destroy(handle) { /* ... */ },
    async sendMessage(handle, message) { /* ... */ },
    async getOutput(handle, lines) { /* ... */ },
    async isAlive(handle) { /* ... */ },
  };
}

export default { manifest, create } satisfies PluginModule<Runtime>;
The satisfies PluginModule<T> syntax ensures compile-time checking that your plugin correctly implements all required interface methods.

The 8 Plugin Slots

1. Runtime Plugin

Slot: runtime
Interface: Runtime
Purpose: Determines WHERE and HOW agent sessions execute
Available Plugins:
Local tmux sessionsPros:
  • Native terminal access
  • Persist across disconnects
  • Easy to attach and monitor
  • Minimal overhead
Cons:
  • Local machine only
  • Requires tmux installed
Configuration:
defaults:
  runtime: tmux
Interface Methods:
interface Runtime {
  create(config: RuntimeCreateConfig): Promise<RuntimeHandle>;
  destroy(handle: RuntimeHandle): Promise<void>;
  sendMessage(handle: RuntimeHandle, message: string): Promise<void>;
  getOutput(handle: RuntimeHandle, lines?: number): Promise<string>;
  isAlive(handle: RuntimeHandle): Promise<boolean>;
  getMetrics?(handle: RuntimeHandle): Promise<RuntimeMetrics>;
  getAttachInfo?(handle: RuntimeHandle): Promise<AttachInfo>;
}

2. Agent Plugin

Slot: agent
Interface: Agent
Purpose: Adapter for specific AI coding tools
Available Plugins:
Anthropic’s Claude CodeFeatures:
  • Session resume support
  • JSONL-based activity detection
  • Auto-generated summaries
  • Cost tracking
  • Workspace hooks for metadata updates
Configuration:
defaults:
  agent: claude-code

projects:
  my-app:
    agentConfig:
      permissions: skip  # or "default"
      model: claude-sonnet-4-20250514
Interface Methods:
interface Agent {
  readonly name: string;
  readonly processName: string;
  readonly promptDelivery?: "inline" | "post-launch";
  
  getLaunchCommand(config: AgentLaunchConfig): string;
  getEnvironment(config: AgentLaunchConfig): Record<string, string>;
  detectActivity(terminalOutput: string): ActivityState;
  getActivityState(session: Session, readyThresholdMs?: number): Promise<ActivityDetection | null>;
  isProcessRunning(handle: RuntimeHandle): Promise<boolean>;
  getSessionInfo(session: Session): Promise<AgentSessionInfo | null>;
  getRestoreCommand?(session: Session, project: ProjectConfig): Promise<string | null>;
  postLaunchSetup?(session: Session): Promise<void>;
  setupWorkspaceHooks?(workspacePath: string, config: WorkspaceHooksConfig): Promise<void>;
}
Critical for Dashboard: The setupWorkspaceHooks() method configures agents to automatically update session metadata when they run git/gh commands. Without this, PRs created by agents never show up in the dashboard.

3. Workspace Plugin

Slot: workspace
Interface: Workspace
Purpose: Code isolation mechanism
Available Plugins:
Git worktreesPros:
  • Shares git history (fast)
  • Minimal disk usage
  • Instant branch switching
  • Multiple sessions see each other’s commits
Cons:
  • Requires Git 2.25+
  • All worktrees share hooks
  • Can’t delete parent repo while worktrees exist
Configuration:
defaults:
  workspace: worktree

projects:
  my-app:
    workspace: worktree
    symlinks:
      - node_modules
      - .env
    postCreate:
      - pnpm install
Interface Methods:
interface Workspace {
  create(config: WorkspaceCreateConfig): Promise<WorkspaceInfo>;
  destroy(workspacePath: string): Promise<void>;
  list(projectId: string): Promise<WorkspaceInfo[]>;
  postCreate?(info: WorkspaceInfo, project: ProjectConfig): Promise<void>;
  exists?(workspacePath: string): Promise<boolean>;
  restore?(config: WorkspaceCreateConfig, workspacePath: string): Promise<WorkspaceInfo>;
}

4. Tracker Plugin

Slot: tracker
Interface: Tracker
Purpose: Issue/task tracking integration
Available Plugins:
GitHub IssuesFeatures:
  • Fetch issue details
  • Generate branch names
  • Create prompts from issues
  • Check completion status
  • Extract labels
Configuration:
projects:
  my-app:
    repo: owner/my-app
    tracker:
      plugin: github
Usage:
ao spawn my-app 42          # GitHub issue #42
ao spawn my-app "#42"       # Also works
Interface Methods:
interface Tracker {
  getIssue(identifier: string, project: ProjectConfig): Promise<Issue>;
  isCompleted(identifier: string, project: ProjectConfig): Promise<boolean>;
  issueUrl(identifier: string, project: ProjectConfig): string;
  issueLabel?(url: string, project: ProjectConfig): string;
  branchName(identifier: string, project: ProjectConfig): string;
  generatePrompt(identifier: string, project: ProjectConfig): Promise<string>;
  listIssues?(filters: IssueFilters, project: ProjectConfig): Promise<Issue[]>;
  updateIssue?(identifier: string, update: IssueUpdate, project: ProjectConfig): Promise<void>;
  createIssue?(input: CreateIssueInput, project: ProjectConfig): Promise<Issue>;
}

5. SCM Plugin

Slot: scm
Interface: SCM
Purpose: Source control + PR/CI/review management
Available Plugins:
GitHubFeatures:
  • Auto-detect PRs by branch
  • Track PR state (open/merged/closed)
  • Monitor CI checks
  • Fetch code reviews
  • Get review comments
  • Check merge readiness
  • Merge PRs
Configuration:
projects:
  my-app:
    repo: owner/my-app
    scm:
      plugin: github
Automatic PR Detection: The github-scm plugin automatically detects PRs created by agents, even if the agent doesn’t write the PR URL to metadata.
Interface Methods:
interface SCM {
  detectPR(session: Session, project: ProjectConfig): Promise<PRInfo | null>;
  getPRState(pr: PRInfo): Promise<PRState>;
  getPRSummary?(pr: PRInfo): Promise<{state: PRState; title: string; additions: number; deletions: number}>;
  mergePR(pr: PRInfo, method?: MergeMethod): Promise<void>;
  closePR(pr: PRInfo): Promise<void>;
  getCIChecks(pr: PRInfo): Promise<CICheck[]>;
  getCISummary(pr: PRInfo): Promise<CIStatus>;
  getReviews(pr: PRInfo): Promise<Review[]>;
  getReviewDecision(pr: PRInfo): Promise<ReviewDecision>;
  getPendingComments(pr: PRInfo): Promise<ReviewComment[]>;
  getAutomatedComments(pr: PRInfo): Promise<AutomatedComment[]>;
  getMergeability(pr: PRInfo): Promise<MergeReadiness>;
}

6. Notifier Plugin

Slot: notifier
Interface: Notifier
Purpose: Push notifications to humans
Primary Human Interface: The Notifier is how the orchestrator communicates with you. The dashboard is for monitoring; notifications are for action.
Available Plugins:
Native OS notificationsFeatures:
  • System notification center
  • Works on macOS/Linux/Windows
  • No external dependencies
  • Immediate delivery
Configuration:
notifiers:
  desktop:
    plugin: desktop

notificationRouting:
  urgent: [desktop]
  action: [desktop]
  warning: [desktop]
  info: []
Interface Methods:
interface Notifier {
  notify(event: OrchestratorEvent): Promise<void>;
  notifyWithActions?(event: OrchestratorEvent, actions: NotifyAction[]): Promise<void>;
  post?(message: string, context?: NotifyContext): Promise<string | null>;
}

7. Terminal Plugin

Slot: terminal
Interface: Terminal
Purpose: Human interaction with running sessions
Available Plugins:
iTerm2 integration (macOS)Features:
  • Open sessions in new tabs
  • Native terminal experience
  • Keyboard shortcuts
  • Split panes
Configuration:
defaults:
  terminal: iterm2
Usage:
ao attach session-1         # Opens in iTerm2 tab
ao open my-app              # Opens all sessions
Interface Methods:
interface Terminal {
  openSession(session: Session): Promise<void>;
  openAll(sessions: Session[]): Promise<void>;
  isSessionOpen?(session: Session): Promise<boolean>;
}

8. Lifecycle Manager

Not a plugin slot — this is core functionality built into the orchestrator. Responsibilities:
  • Poll all sessions periodically (default: every 30 seconds)
  • Detect state transitions (working → pr_open → ci_failed → etc.)
  • Emit events on transitions
  • Trigger automatic reactions
  • Track reaction attempts and escalation
  • Notify humans when auto-handling fails
State Machine Logic:
1
Check Runtime
2
Is the session’s runtime environment alive?
3
Check Agent Activity
4
What is the agent currently doing? (active/ready/idle/waiting/exited)
5
Detect PR
6
If no PR in metadata, query SCM by branch name.
7
Check PR State
8
If PR exists: Is it open, merged, or closed?
9
Check CI
10
Are CI checks passing or failing?
11
Check Reviews
12
What’s the review decision? (approved/changes_requested/pending)
13
Check Merge Readiness
14
Is the PR mergeable? (approved + green CI + no conflicts)
15
Determine Status
16
Compute new session status from all checks.
17
Emit Events
18
If status changed, emit event and trigger reactions.
Configuration:
readyThresholdMs: 300000        # 5 minutes before ready → idle

Plugin Configuration

Global Defaults

Set defaults for all projects:
defaults:
  runtime: tmux
  agent: claude-code
  workspace: worktree
  notifiers: [desktop]

Per-Project Overrides

Override defaults for specific projects:
projects:
  my-app:
    repo: owner/my-app
    path: ~/my-app
    defaultBranch: main
    
    # Override runtime
    runtime: docker
    
    # Override agent
    agent: codex
    
    # Override workspace
    workspace: clone
    
    # Agent-specific config
    agentConfig:
      permissions: skip
      model: gpt-4-turbo

Per-Session Overrides

Specify agent at spawn time:
ao spawn my-app 123 --agent aider
The agent name is persisted in metadata so the same agent is used throughout the session lifecycle (including restores).

Plugin Discovery

Plugins are discovered in this order:
  1. Built-in plugins — Shipped with Agent Orchestrator
  2. npm packages — Installed via pnpm install
  3. Local paths — Custom plugins in your project

Using Custom Plugins

Create a plugin in your project:
// plugins/my-runtime.ts
import type { PluginModule, Runtime } from "@composio/ao-core";

export const manifest = {
  name: "my-runtime",
  slot: "runtime" as const,
  description: "My custom runtime",
  version: "1.0.0",
};

export function create(): Runtime {
  return {
    // Implement interface
  };
}

export default { manifest, create } satisfies PluginModule<Runtime>;
Register in config:
plugins:
  - path: ./plugins/my-runtime.ts

defaults:
  runtime: my-runtime

Best Practices

Choosing Plugins

  • Runtime: Use tmux for local work, docker for isolation, k8s for scale
  • Agent: Start with claude-code, try others for specific needs
  • Workspace: Use worktree unless you need complete isolation
  • Tracker: Match your existing issue tracker
  • Notifier: Use desktop for personal work, slack for team visibility

Plugin Configuration

  • Set sensible defaults in global config
  • Override per-project for special cases
  • Use environment variables for secrets: ${SLACK_TOKEN}
  • Test plugin changes with a single session first

Notification Routing

Route notifications by priority:
notificationRouting:
  urgent: [desktop, slack]      # Agent stuck/errored
  action: [desktop]             # Human decision needed
  warning: [slack]              # Auto-fixable issues
  info: []                      # Don't notify for FYI events

Next Steps

Architecture

See how plugins interact in the overall architecture

Workflows

Learn how plugins work together in end-to-end workflows

Plugin Development

Build your own custom plugins

Build docs developers (and LLMs) love