> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipecat.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# WorkerRunner

> Lifecycle orchestrator for multi-agent systems

## Overview

`WorkerRunner` runs agents to completion and acts as the host for a multi-agent session. It owns the shared [`WorkerBus`](/api-reference/server/bus/bus#workerbus) and [`WorkerRegistry`](/api-reference/server/workers/types#workerregistry) that back the whole session, and responds to bus messages for lifecycle coordination.

```python theme={null}
from pipecat.workers.runner import WorkerRunner
```

<Note>
  `PipelineRunner` is a deprecated alias for `WorkerRunner`; existing code that
  uses it keeps working but should migrate to `WorkerRunner`.
</Note>

```python theme={null}
runner = WorkerRunner()

agent = MyAgent("my_agent", ...)
await runner.add_workers(agent)

await runner.run()
```

Adding an agent with `add_workers()` attaches it to the runner's bus and registry, so agents do not take a bus in their constructor.

## Configuration

<ParamField path="name" type="str | None" default="None">
  Unique name for this runner. Defaults to a UUID-based name. Must be unique
  across all runners in a distributed setup.
</ParamField>

<ParamField path="bus" type="WorkerBus | None" default="None">
  The [`WorkerBus`](/api-reference/server/bus/bus#workerbus) instance. Creates
  an [`AsyncQueueBus`](/api-reference/server/bus/bus#asyncqueuebus) if not
  provided.
</ParamField>

<ParamField path="handle_sigint" type="bool" default="True">
  Whether to automatically handle SIGINT signals for graceful shutdown.
</ParamField>

<ParamField path="handle_sigterm" type="bool" default="False">
  Whether to automatically handle SIGTERM signals for graceful shutdown.
</ParamField>

<ParamField path="force_gc" type="bool" default="False">
  Whether to force garbage collection after the main worker completes.
</ParamField>

<ParamField path="loop" type="asyncio.AbstractEventLoop | None" default="None">
  Event loop to use. If `None`, uses the current running loop.
</ParamField>

## Properties

### bus

```python theme={null}
runner.bus -> WorkerBus
```

The bus this runner hosts, shared across all added agents.

### registry

```python theme={null}
runner.registry -> WorkerRegistry
```

The shared agent registry this runner owns.

## Methods

### add\_workers

```python theme={null}
async def add_workers(self, *workers: BaseWorker) -> None
```

Add one or more agents to this runner. Each agent is attached to the runner's bus and registry and started in the background. Can be called before or after `run()`. When called after `run()` has started, each agent starts immediately; otherwise agents are queued and started during run setup.

| Parameter  | Type                                                      | Description               |
| ---------- | --------------------------------------------------------- | ------------------------- |
| `*workers` | [`BaseWorker`](/api-reference/server/workers/base-worker) | One or more agents to add |

### run

```python theme={null}
async def run(self, worker: BaseWorker | None = None, *, auto_end: bool = True) -> None
```

Run all added agents and block until the runner is stopped. By default (`auto_end=True`), the runner ends once every root agent has finished. For long-lived hosts that add and remove agents over many sessions, pass `auto_end=False` so the runner does not exit when no agents are left.

| Parameter  | Type                 | Default | Description                                                                                                                     |
| ---------- | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `worker`   | `BaseWorker \| None` | `None`  | Optional agent to run. Deprecated -- register with `add_workers()` before calling `run()` instead.                              |
| `auto_end` | `bool`               | `True`  | When `True`, the runner ends once every root agent has finished. When `False`, it blocks until `end()` or `cancel()` is called. |

### end

```python theme={null}
async def end(self, reason: str | None = None) -> None
```

Gracefully end all agents and shut down. Ends root agents first; parent agents propagate shutdown to their children automatically. Idempotent.

| Parameter | Type          | Default | Description                      |
| --------- | ------------- | ------- | -------------------------------- |
| `reason`  | `str \| None` | `None`  | Human-readable reason for ending |

### cancel

```python theme={null}
async def cancel(self, reason: str | None = None) -> None
```

Immediately cancel all agents and shut down. Cancels root agents first; parent agents propagate cancellation to their children automatically. Idempotent.

| Parameter | Type          | Default | Description                          |
| --------- | ------------- | ------- | ------------------------------------ |
| `reason`  | `str \| None` | `None`  | Human-readable reason for cancelling |

## Event Handlers

```python theme={null}
@runner.event_handler("on_ready")
async def on_ready(runner):
    print("All agents started")

@runner.event_handler("on_error")
async def on_error(runner, error):
    print(f"Runner error: {error}")
```

| Event      | Description                                                                 |
| ---------- | --------------------------------------------------------------------------- |
| `on_ready` | Fired after the runner has finished setup and any added agents have started |
| `on_error` | Fired when starting an added agent fails                                    |
