> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/ComposioHQ/agent-orchestrator/llms.txt
> Use this file to discover all available pages before exploring further.

# Event System

> Orchestrator event types, priorities, and notification routing

## Overview

The Agent Orchestrator uses an event-driven architecture for communication between the lifecycle manager, notification system, and reaction engine. Events represent state transitions and important occurrences in session lifecycles.

<Note>
  There is no dedicated EventBus class - events are created and dispatched directly by the Lifecycle Manager. This page documents the event system as implemented across the codebase.
</Note>

**Key concepts:**

* Events are emitted on session state transitions
* Each event has a priority level (urgent, action, warning, info)
* Events are routed to notifiers based on priority
* Events can trigger automated reactions

## Event Structure

```typescript theme={null}
interface OrchestratorEvent {
  id: string;              // Unique UUID
  type: EventType;         // Event type identifier
  priority: EventPriority; // urgent | action | warning | info
  sessionId: SessionId;    // Associated session
  projectId: string;       // Associated project
  timestamp: Date;         // When event occurred
  message: string;         // Human-readable description
  data: Record<string, unknown>;  // Event-specific payload
}
```

**Example:**

```typescript theme={null}
{
  id: "a3b4c5d6-e7f8-1234-5678-9abcdef01234",
  type: "ci.failing",
  priority: "warning",
  sessionId: "my-app-1",
  projectId: "my-app",
  timestamp: new Date("2026-03-04T10:30:00Z"),
  message: "my-app-1: pr_open → ci_failed",
  data: {
    oldStatus: "pr_open",
    newStatus: "ci_failed",
    prUrl: "https://github.com/org/repo/pull/42"
  }
}
```

## Event Types

All event types are string literals defined in the `EventType` union:

```typescript theme={null}
type EventType =
  // Session lifecycle
  | "session.spawned"
  | "session.working"
  | "session.exited"
  | "session.killed"
  | "session.stuck"
  | "session.needs_input"
  | "session.errored"
  // PR lifecycle
  | "pr.created"
  | "pr.updated"
  | "pr.merged"
  | "pr.closed"
  // CI
  | "ci.passing"
  | "ci.failing"
  | "ci.fix_sent"
  | "ci.fix_failed"
  // Reviews
  | "review.pending"
  | "review.approved"
  | "review.changes_requested"
  | "review.comments_sent"
  | "review.comments_unresolved"
  // Automated reviews
  | "automated_review.found"
  | "automated_review.fix_sent"
  // Merge
  | "merge.ready"
  | "merge.conflicts"
  | "merge.completed"
  // Reactions
  | "reaction.triggered"
  | "reaction.escalated"
  // Summary
  | "summary.all_complete";
```

### Session Lifecycle Events

Events related to session creation, execution, and termination.

<Accordion title="session.spawned">
  **Trigger:** Session enters `spawning` status

  **Priority:** info

  **Data:**

  ```typescript theme={null}
  {
    branch: string;
    issueId?: string;
    workspacePath: string;
  }
  ```

  **Example:**

  ```typescript theme={null}
  {
    type: "session.spawned",
    message: "my-app-1: session created",
    data: {
      branch: "feat/INT-1234",
      issueId: "INT-1234",
      workspacePath: "/Users/foo/.agent-orchestrator/my-app/worktrees/my-app-1"
    }
  }
  ```
</Accordion>

<Accordion title="session.working">
  **Trigger:** Session enters `working` status

  **Priority:** info

  **Data:**

  ```typescript theme={null}
  {
    oldStatus: SessionStatus;
    newStatus: "working";
  }
  ```
</Accordion>

<Accordion title="session.exited">
  **Trigger:** Agent process exits (activity state becomes `exited`)

  **Priority:** urgent

  **Data:**

  ```typescript theme={null}
  {
    lastActivityAt: Date;
    exitReason?: string;
  }
  ```

  **Reaction:** `agent-exited` - Notifies human immediately
</Accordion>

<Accordion title="session.stuck">
  **Trigger:** Session enters `stuck` status (agent idle for too long)

  **Priority:** urgent

  **Data:**

  ```typescript theme={null}
  {
    idleDurationMs: number;
    lastActivityAt: Date;
  }
  ```

  **Reaction:** `agent-stuck` - Notifies human after threshold (default: 10 minutes)
</Accordion>

<Accordion title="session.needs_input">
  **Trigger:** Session enters `needs_input` status (agent asking a question)

  **Priority:** urgent

  **Data:**

  ```typescript theme={null}
  {
    prompt?: string;  // Agent's question if available
  }
  ```

  **Reaction:** `agent-needs-input` - Notifies human immediately
</Accordion>

<Accordion title="session.errored">
  **Trigger:** Session enters `errored` status

  **Priority:** urgent

  **Data:**

  ```typescript theme={null}
  {
    error: string;
    stackTrace?: string;
  }
  ```
</Accordion>

### PR Lifecycle Events

Events related to pull request creation and status changes.

<Accordion title="pr.created">
  **Trigger:** Session enters `pr_open` status

  **Priority:** info

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    prNumber: number;
    branch: string;
    baseBranch: string;
  }
  ```

  **Example:**

  ```typescript theme={null}
  {
    type: "pr.created",
    message: "my-app-1: PR #42 created",
    data: {
      prUrl: "https://github.com/org/repo/pull/42",
      prNumber: 42,
      branch: "feat/INT-1234",
      baseBranch: "main"
    }
  }
  ```
</Accordion>

<Accordion title="pr.merged">
  **Trigger:** Session enters `merged` status

  **Priority:** action

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    mergedAt: Date;
    mergedBy?: string;
  }
  ```
</Accordion>

<Accordion title="pr.closed">
  **Trigger:** PR is closed without merging

  **Priority:** warning

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    closedAt: Date;
    reason?: string;
  }
  ```
</Accordion>

### CI Events

Events related to continuous integration checks.

<Accordion title="ci.failing">
  **Trigger:** Session enters `ci_failed` status

  **Priority:** warning

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    failedChecks: string[];  // Names of failed checks
    checkUrl?: string;
  }
  ```

  **Reaction:** `ci-failed` - Sends message to agent with instructions to fix

  **Example:**

  ```typescript theme={null}
  {
    type: "ci.failing",
    message: "my-app-1: CI checks failing",
    data: {
      prUrl: "https://github.com/org/repo/pull/42",
      failedChecks: ["test", "lint", "typecheck"],
      checkUrl: "https://github.com/org/repo/actions/runs/123"
    }
  }
  ```
</Accordion>

<Accordion title="ci.passing">
  **Trigger:** All CI checks pass after previously failing

  **Priority:** info

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    passedChecks: string[];
  }
  ```
</Accordion>

### Review Events

Events related to code review activity.

<Accordion title="review.pending">
  **Trigger:** Session enters `review_pending` status

  **Priority:** info

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    reviewers: string[];
  }
  ```
</Accordion>

<Accordion title="review.approved">
  **Trigger:** Session enters `approved` status

  **Priority:** action

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    approver: string;
    approvedAt: Date;
  }
  ```
</Accordion>

<Accordion title="review.changes_requested">
  **Trigger:** Session enters `changes_requested` status

  **Priority:** warning

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    reviewer: string;
    comments: Array<{
      path: string;
      line: number;
      body: string;
    }>;
  }
  ```

  **Reaction:** `changes-requested` - Sends comments to agent with instructions to address
</Accordion>

### Merge Events

Events related to merge readiness and completion.

<Accordion title="merge.ready">
  **Trigger:** Session enters `mergeable` status (approved + CI passing + no conflicts)

  **Priority:** action

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    ciStatus: "passing";
    reviewDecision: "approved";
    conflictsResolved: true;
  }
  ```

  **Reaction:** `approved-and-green` - Notifies human that PR is ready to merge
</Accordion>

<Accordion title="merge.completed">
  **Trigger:** PR is successfully merged

  **Priority:** action

  **Data:**

  ```typescript theme={null}
  {
    prUrl: string;
    mergedAt: Date;
    mergedBy: string;
    method: "merge" | "squash" | "rebase";
  }
  ```
</Accordion>

### Reaction Events

Events emitted by the reaction system itself.

<Accordion title="reaction.triggered">
  **Trigger:** A reaction is executed

  **Priority:** info (or reaction's configured priority)

  **Data:**

  ```typescript theme={null}
  {
    reactionKey: string;
    action: "send-to-agent" | "notify" | "auto-merge";
    message?: string;
  }
  ```
</Accordion>

<Accordion title="reaction.escalated">
  **Trigger:** A reaction escalates to human notification after retries/timeout

  **Priority:** urgent

  **Data:**

  ```typescript theme={null}
  {
    reactionKey: string;
    attempts: number;
    reason: "max_retries" | "timeout";
  }
  ```
</Accordion>

### Summary Events

<Accordion title="summary.all_complete">
  **Trigger:** All sessions are in terminal states (merged/killed)

  **Priority:** info

  **Data:**

  ```typescript theme={null}
  {
    totalSessions: number;
    merged: number;
    killed: number;
    summary: string;
  }
  ```

  **Reaction:** `all-complete` - Sends summary notification
</Accordion>

## Event Priorities

Events have one of four priority levels:

```typescript theme={null}
type EventPriority = "urgent" | "action" | "warning" | "info";
```

### Priority Levels

<ParamField path="urgent" type="EventPriority">
  **Critical issues requiring immediate human attention.**

  Examples:

  * Agent stuck or crashed
  * Agent asking a question (needs\_input)
  * Session errored
  * Reaction escalated after max retries

  Default routing: Desktop + Composio notifications
</ParamField>

<ParamField path="action" type="EventPriority">
  **Actionable events that may require human decision.**

  Examples:

  * PR approved and ready to merge
  * PR merged successfully
  * Review completed

  Default routing: Desktop + Composio notifications
</ParamField>

<ParamField path="warning" type="EventPriority">
  **Issues that may need attention but aren't blocking.**

  Examples:

  * CI checks failing (but reaction is auto-fixing)
  * Review changes requested (but reaction is handling)
  * Merge conflicts detected

  Default routing: Composio notifications only
</ParamField>

<ParamField path="info" type="EventPriority">
  **Informational updates about progress.**

  Examples:

  * Session spawned
  * PR created
  * CI passing
  * All sessions complete

  Default routing: Composio notifications only
</ParamField>

### Priority Inference

The lifecycle manager automatically infers priority from event type:

```typescript theme={null}
function inferPriority(type: EventType): EventPriority {
  if (type.includes('stuck') || type.includes('needs_input') || type.includes('errored')) {
    return 'urgent';
  }
  if (type.startsWith('summary.')) {
    return 'info';
  }
  if (type.includes('approved') || type.includes('ready') || type.includes('merged')) {
    return 'action';
  }
  if (type.includes('fail') || type.includes('changes_requested')) {
    return 'warning';
  }
  return 'info';
}
```

## Event Creation

Events are created by the lifecycle manager using a factory function:

```typescript theme={null}
function createEvent(
  type: EventType,
  opts: {
    sessionId: SessionId;
    projectId: string;
    message: string;
    priority?: EventPriority;
    data?: Record<string, unknown>;
  }
): OrchestratorEvent {
  return {
    id: randomUUID(),
    type,
    priority: opts.priority ?? inferPriority(type),
    sessionId: opts.sessionId,
    projectId: opts.projectId,
    timestamp: new Date(),
    message: opts.message,
    data: opts.data ?? {},
  };
}
```

**Example:**

```typescript theme={null}
const event = createEvent('ci.failing', {
  sessionId: 'my-app-1',
  projectId: 'my-app',
  message: 'CI checks failing on PR #42',
  data: {
    prUrl: 'https://github.com/org/repo/pull/42',
    failedChecks: ['test', 'lint'],
  },
});
```

## Event Routing

Events are routed to notifiers based on priority:

```yaml theme={null}
# agent-orchestrator.yaml
notificationRouting:
  urgent: ["desktop", "composio"]
  action: ["desktop", "composio"]
  warning: ["composio"]
  info: ["composio"]
```

### Routing Logic

```typescript theme={null}
async function notifyHuman(event: OrchestratorEvent, priority: EventPriority): Promise<void> {
  const eventWithPriority = { ...event, priority };
  const notifierNames = config.notificationRouting[priority] ?? config.defaults.notifiers;

  for (const name of notifierNames) {
    const notifier = registry.get<Notifier>('notifier', name);
    if (notifier) {
      try {
        await notifier.notify(eventWithPriority);
      } catch {
        // Notifier failed - not much we can do
      }
    }
  }
}
```

### Custom Routing

You can customize routing per priority level:

```yaml theme={null}
notificationRouting:
  urgent:
    - desktop      # OS notification
    - composio     # Composio dashboard
    - slack        # Slack message
  action:
    - desktop
    - composio
  warning:
    - slack        # Only Slack for warnings
  info:
    - composio     # Dashboard only for info
```

## Event-Triggered Reactions

Events can trigger automated reactions. The lifecycle manager maps event types to reaction config keys:

```typescript theme={null}
function eventToReactionKey(eventType: EventType): string | null {
  switch (eventType) {
    case "ci.failing":
      return "ci-failed";
    case "review.changes_requested":
      return "changes-requested";
    case "automated_review.found":
      return "bugbot-comments";
    case "merge.conflicts":
      return "merge-conflicts";
    case "merge.ready":
      return "approved-and-green";
    case "session.stuck":
      return "agent-stuck";
    case "session.needs_input":
      return "agent-needs-input";
    case "session.killed":
      return "agent-exited";
    case "summary.all_complete":
      return "all-complete";
    default:
      return null;
  }
}
```

See [Lifecycle Manager - Reaction System](/api/lifecycle-manager#reaction-system) for details on how reactions work.

## Complete Example

```typescript theme={null}
import { createLifecycleManager, createSessionManager, loadConfig, createPluginRegistry } from '@composio/ao-core';
import type { OrchestratorEvent } from '@composio/ao-core';

// Setup
const config = loadConfig();
const registry = createPluginRegistry();
await registry.loadBuiltins(config);

const sessionManager = createSessionManager({ config, registry });
const lifecycleManager = createLifecycleManager({
  config,
  registry,
  sessionManager,
});

// Custom event monitoring (hook into notifier)
class EventMonitorNotifier {
  name = 'event-monitor';
  
  async notify(event: OrchestratorEvent): Promise<void> {
    console.log('\n=== Event Received ===');
    console.log(`Type: ${event.type}`);
    console.log(`Priority: ${event.priority}`);
    console.log(`Session: ${event.sessionId}`);
    console.log(`Message: ${event.message}`);
    console.log(`Data:`, JSON.stringify(event.data, null, 2));
    
    // Log high-priority events to file
    if (event.priority === 'urgent' || event.priority === 'action') {
      await appendFile('important-events.log', 
        `${event.timestamp.toISOString()} [${event.priority}] ${event.message}\n`
      );
    }
  }
}

// Register custom notifier
registry.register({
  manifest: {
    name: 'event-monitor',
    slot: 'notifier',
    description: 'Event monitoring and logging',
    version: '1.0.0',
  },
  create: () => new EventMonitorNotifier(),
});

// Add to notification routing
config.notificationRouting.urgent.push('event-monitor');
config.notificationRouting.action.push('event-monitor');

// Start lifecycle manager
lifecycleManager.start();

// Spawn a session and watch events
const session = await sessionManager.spawn({
  projectId: 'my-app',
  issueId: 'INT-1234',
});

// Events will be logged as session progresses:
// - session.working
// - pr.created
// - ci.failing (if CI fails)
// - review.pending
// - review.approved
// - merge.ready
// - merge.completed
```

## See Also

* [Lifecycle Manager](/api/lifecycle-manager) - Event emission and reaction system
* [Plugin: Notifier](/plugins/notifier/desktop) - Notification delivery
* [Config Loader](/api/config-loader) - Notification routing configuration


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.