This is a self-hosting guide. The hosted product at https://www.orcapods.ai needs none of this — sign in and go.
Why Multiple Runners?
Running multiple runners lets you:- Scale horizontally — more runners = more concurrent sessions
- Specialize by runtime — dedicate runners to specific LLM providers
- Isolate workloads — separate runners for different tenants or use cases (future)
- Improve resilience — conductor routes away from unhealthy runners
How Session Routing Works
Each runner has a hash derived from itsRUNNER_BASE_URL:
sess-<hash>-<8hex>
When any conductor receives a request targeting a session, it extracts the hash,
looks it up in its remote.Pool, and routes directly to the owning runner.
Routing is stateless by session ID, but membership changes are currently held
in each conductor process; horizontally replicated conductors must therefore
reconcile their registries independently.
Basic Two-Runner Setup
Capability-Based Routing
Runners advertise their capabilities. The conductor only routes sessions to runners that support the requested runtime: Set capabilities viaRUNNER_CAPABILITIES (comma-separated):
Sidecar Configuration per Runner
Each runner can have different sidecars for different runtimes:
Per-runtime sidecars (recommended for production):
Checking Topology
TheGET /api/topology endpoint shows all runners, their capabilities, health,
membership state, process footprint, session breakdown, and the sidecar worker
instances observed beneath each runner:
process, sessionsByRuntime, and sidecars can be null when a runner does
not answer its topology probe. sidecars[].observedInstances is a lower bound
on worker replicas, not a count, and cold means an idle or scaled-to-zero
sidecar rather than a fault. The dashboard Runtime page displays these
values and refreshes them manually because each read probes the fleet.
Runner Health & Failover
The conductor probes each runner at startup and during reconcile, and records a membership state. An individual runner that is unreachable during startup no longer prevents the conductor from booting when at least one runner answers; it remains visible asunreachable and is excluded from new session routing
until a successful reconcile. A runner that is deliberately draining is also
excluded from new sessions, while sessions it already owns remain routed by
their session ID. Boot still fails when no runner answers at all.
Multi-Host Deployment
When runners run on different hosts,RUNNER_BASE_URL must be a routable URL that all conductors can reach:
Never use
localhost for RUNNER_BASE_URL in multi-host setups. It needs to be a URL that resolves from the conductor’s network.Adding Runners at Runtime
To add a new runner to a live cluster using the internal service plane:- Start the new runner with a unique
RUNNER_BASE_URL - Call
POST /internal/topology/reconcileon every conductor replica with the updated URL list, or omit the body to re-read that replica’sRUNNER_URLS
POST /internal/topology/drain with its hash, wait
for its active session count to reach zero, then call
POST /internal/topology/remove. reconcile does not remove URLs that have
disappeared from its input. These operations are per-replica and require the
internal signing-plane authentication; they are not a shared autoscaling
registry.
Runner-Specific Tool Configuration
Different runners can have different tools available. For example:- Runner A has
TAVILY_API_KEYset →web_searchandweb_extractwork - Runner B does not → those tools return errors