Polpo emits typed events for everything it does — task transitions, agent activity, assessments, deadlocks, notifications, and more. Events are streamed via SSE and WebSocket to all connected clients and optionally persisted to a log store.
Events marked with Not persisted are excluded from the log store because they fire too frequently. All other events are automatically persisted when a LogStore is attached.
Task Lifecycle
Core events for task creation, state transitions, updates, and removal.
| Event | Description | Key Payload Fields |
|---|
task:created | Task added to the registry | task: Task |
task:transition | Task status changed | taskId, from: TaskStatus, to: TaskStatus, task: Task |
task:updated | Task fields modified (description, assignment, etc.) | taskId, task: Task |
task:removed | Task deleted from registry | taskId |
// Example: listen for status changes
orchestrator.on("task:transition", ({ taskId, from, to, task }) => {
console.log(`Task ${taskId}: ${from} → ${to}`);
});
Agent Lifecycle
Events tracking agent process spawning, completion, and real-time activity.
| Event | Description | Key Payload Fields |
|---|
agent:spawned | Agent process launched for a task | taskId, agentName, taskTitle |
agent:finished | Agent process exited | taskId, agentName, exitCode, duration, sessionId? |
agent:activity | Tool call or progress update from an agent | taskId, agentName, tool?, file?, summary? |
orchestrator.on("agent:finished", ({ taskId, agentName, exitCode, duration }) => {
console.log(`${agentName} finished task ${taskId} in ${duration}ms (exit: ${exitCode})`);
});
Assessment
Events for the assessment lifecycle — started, progress updates, completion, and expectation corrections.
| Event | Description | Key Payload Fields |
|---|
assessment:started | Assessment began for a task | taskId |
assessment:progress | Status update during assessment | taskId, message |
assessment:complete | Assessment finished | taskId, passed: boolean, scores?: DimensionScore[], globalScore?: number, message? |
assessment:corrected | Expectations auto-corrected by the judge | taskId, corrections: number |
The DimensionScore type:
{
dimension: string; // e.g. "correctness"
score: number; // 1-5
reasoning: string; // chain-of-thought explanation
weight: number; // weight used for global score
}
Orchestrator
Events for the orchestrator’s own lifecycle.
| Event | Description | Key Payload Fields |
|---|
orchestrator:started | Orchestrator started | org, agents: string[] |
orchestrator:tick | Periodic aggregate counts (Not persisted) | pending, running, done, failed, queued |
orchestrator:deadlock | Unresolvable deadlocks found | taskIds: string[] |
orchestrator:shutdown | Graceful shutdown initiated | (empty) |
orchestrator:tick fires every 5 seconds and includes a queued count in addition to pending, running, done, and failed.
Retry & Fix
Events for the multi-stage retry system: fix attempts, full retries, and exhaustion.
| Event | Description | Key Payload Fields |
|---|
task:retry | Full retry started | taskId, attempt, maxRetries |
task:retry:blocked | Automatic retry/fix blocked (task has sideEffects: true) | taskId, reason |
task:fix | Fix phase started (targeted corrections) | taskId, attempt, maxFix |
task:maxRetries | All retries exhausted | taskId |
Question Detection
Events for agent questions and auto-resolution.
| Event | Description | Key Payload Fields |
|---|
task:question | Agent asked a question during execution | taskId, question |
task:answered | Orchestrator auto-answered a question | taskId, question, answer |
Deadlock Resolution
Events for detecting and resolving dependency deadlocks.
| Event | Description | Key Payload Fields |
|---|
deadlock:detected | Blocked tasks found with failed dependencies | taskIds: string[], resolvableCount |
deadlock:resolving | Attempting to resolve a specific blocked task | taskId, failedDepId |
deadlock:resolved | Deadlock successfully resolved | taskId, failedDepId, action: "absorb" | "retry", reason |
deadlock:unresolvable | Deadlock cannot be resolved | taskId, reason |
Resilience
Events for timeout and stale agent detection.
| Event | Description | Key Payload Fields |
|---|
task:timeout | Task exceeded its maxDuration | taskId, elapsed, timeout |
agent:stale | Agent hasn’t reported activity recently | taskId, agentName, idleMs, action: "warning" | "killed" |
Recovery
Events for task recovery after restarts.
| Event | Description | Key Payload Fields |
|---|
task:recovered | Orphaned task recovered on restart | taskId, title, previousStatus: TaskStatus |
Missions
Events for mission lifecycle management.
| Event | Description | Key Payload Fields |
|---|
mission:saved | Mission created or updated | missionId, name, status: MissionStatus |
mission:executed | Mission group started execution | missionId, group, taskCount |
mission:completed | All tasks in a mission group finished | missionId, group, allPassed: boolean, report: MissionReport |
mission:resumed | Mission resumed from a previous run | missionId, name, retried, pending |
mission:deleted | Mission deleted | missionId |
Chat / Sessions
Events for the conversational chat interface.
| Event | Description | Key Payload Fields |
|---|
session:created | New chat session created | sessionId, title? |
message:added | Message added to a session | sessionId, messageId, role: "user" | "assistant" |
Approval Gates
Events for human-in-the-loop approval workflows.
| Event | Description | Key Payload Fields |
|---|
approval:requested | Approval request created | requestId, gateId, gateName, taskId?, missionId? |
approval:resolved | Approval resolved | requestId, status: "approved" | "rejected", resolvedBy? |
approval:revised | Task sent back for rework | requestId, taskId?, feedback, revisionCount, resolvedBy? |
approval:timeout | Approval timed out | requestId, action: "approve" | "reject" |
Escalation
Events for the 4-level escalation chain (agent retry, fallback agent, orchestrator LLM, human).
| Event | Description | Key Payload Fields |
|---|
escalation:triggered | Escalation level activated | taskId, level, handler, target? |
escalation:resolved | Escalation level completed | taskId, level, action |
escalation:human | Human notification sent | taskId, message, channels? |
SLA & Deadlines
Events for monitoring task and mission deadlines.
| Event | Description | Key Payload Fields |
|---|
sla:warning | Approaching deadline | entityId, entityType: "task" | "mission", deadline, elapsed, remaining, percentUsed |
sla:violated | Deadline exceeded | entityId, entityType: "task" | "mission", deadline, overdueMs |
sla:met | Completed within deadline | entityId, entityType: "task" | "mission", deadline, marginMs |
Quality Gates
Mission-level quality gate events.
| Event | Description | Key Payload Fields |
|---|
quality:gate:passed | Quality gate passed | missionId, gateName, avgScore? |
quality:gate:failed | Quality gate failed | missionId, gateName, avgScore?, reason |
quality:threshold:failed | Mission average score below threshold | missionId, avgScore, threshold |
Scheduling
Events for cron-based mission scheduling.
| Event | Description | Key Payload Fields |
|---|
schedule:triggered | Scheduled mission triggered | scheduleId, missionId, expression |
schedule:created | Schedule registered | scheduleId, missionId, nextRunAt? |
schedule:completed | Scheduled run completed | scheduleId, missionId |
Notifications
Events for the notification router.
| Event | Description | Key Payload Fields |
|---|
notification:sent | Notification dispatched successfully | ruleId, channel, event |
notification:failed | Notification dispatch failed | ruleId, channel, error |
General
| Event | Description | Key Payload Fields |
|---|
log | General log message | level: "info" | "warn" | "error" | "debug", message |
Subscribing to Events
SSE (HTTP)
const events = new EventSource('/api/v1/projects/my-project/events');
events.onmessage = (e) => {
const { event, data } = JSON.parse(e.data);
// event: "task:transition", data: { taskId: "...", ... }
};
WebSocket
const ws = new WebSocket('ws://localhost:3000/api/v1/projects/my-project/ws');
ws.send(JSON.stringify({ type: 'subscribe', pattern: 'task:*' }));
ws.onmessage = (e) => {
const { event, data } = JSON.parse(e.data);
};
Node.js (TypedEmitter)
import { TypedEmitter } from "polpo";
orchestrator.on("task:transition", ({ taskId, from, to, task }) => {
console.log(`Task ${taskId}: ${from} → ${to}`);
});
// Glob-style patterns work for notifications
// (see Notifications guide for details)