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

# Runner Pools

> Hosted and self-hosted runner pools share one job model. Hosted bills sim minutes; self-hosted is free of compute. The job_router picks where a job lands based on capability and policy.

# Runner Pools

A **runner pool** is a named, capability-tagged group of runners that pulls jobs from Roboticks. Every test job carries a set of requirements — ROS distro, simulator, GPU, network posture — and the `job_router` dispatches it to the pool that fits.

There are two pool types. Same wire contract, same job payload, different fulfillment.

<CardGroup cols={2}>
  <Card title="Hosted pools" icon="cloud">
    Roboticks operates them. ECS Fargate Spot for ROS2 CPU, EC2 G4dn Spot for Gazebo Harmonic, mixed for Webots. Billed per sim minute.
  </Card>

  <Card title="Self-hosted pools" icon="server">
    You operate them via the [`roboticks-runner`](https://github.com/roboticks-io/roboticks-runner) Go binary v2. Free of compute charges. Required for air-gapped.
  </Card>
</CardGroup>

## Hosted pool catalog

| Pool                | Backing                                | Typical use                                         | Indicative price |
| ------------------- | -------------------------------------- | --------------------------------------------------- | ---------------- |
| `hosted-ros2-cpu`   | Fargate Spot, 4 vCPU / 8 GB            | pytest, gtest, launch\_testing on a ROS2 node graph | \~\$0.02 / min   |
| `hosted-gazebo-gpu` | EC2 G4dn.xlarge Spot Fleet (NVIDIA T4) | Gazebo Harmonic worlds, sensor simulation           | \~\$0.10 / min   |
| `hosted-webots-cpu` | Fargate Spot, 8 vCPU / 16 GB           | Webots scenes without GPU shaders                   | \~\$0.04 / min   |
| `hosted-webots-gpu` | EC2 G4dn.xlarge Spot Fleet             | Webots with GPU rendering                           | \~\$0.10 / min   |

Spot interruption is handled by the platform — interrupted jobs requeue automatically. See [Pricing](/pricing) for the canonical rate card.

## Self-hosted pool model

You declare a pool in the dashboard or via `rbtk pool create`, mint a registration token, then run `rbtk-runner register` on each machine that should join. The runner polls `/internal/runners/poll`, declares its capabilities (ROS distros installed, sim engines available, GPU model, max concurrent jobs), and heartbeats every 15 seconds with token rotation.

```mermaid theme={null}
%%{init: {"theme": "neutral", "themeVariables": {"primaryColor": "#4040ff"}} }%%
flowchart LR
    Job["Test job<br/>(requires_sim, ROS humble, GPU)"] --> Router["job_router"]
    Router -->|airgapped flag| SH["Self-hosted only"]
    Router -->|GPU + self-hosted capacity| SH
    Router -->|GPU, no self-hosted| H["hosted-gazebo-gpu"]
    Router -->|plain ROS2 test| Bal["Self-hosted then hosted<br/>(load balance)"]
    SH --> Runner1["roboticks-runner v2"]
    H --> Fargate["Fargate / G4dn Spot"]
    Bal --> Runner1
    Bal --> Fargate
```

## Routing rules

The `job_router` resolves each job against pool capabilities in this order:

1. **`project.airgapped == true`** — only self-hosted pools in the project's namespace are considered. Hosted pools are excluded even if they match capabilities.
2. **`requires_sim` + self-hosted GPU capacity available** — prefer the self-hosted pool (free of compute).
3. **`requires_sim` + no self-hosted GPU capacity** — fall back to a hosted GPU pool. Pre-MVP customers can require explicit opt-in via `project.hosted_fallback = true`.
4. **Plain ROS2 test (no simulator)** — load-balance: try self-hosted first, then hosted. The router prefers warm runners over cold-start hosted Fargate tasks.

Capabilities are matched **all-or-nothing**: a job needing `ros: humble` and `sim: gazebo-harmonic` will skip a runner that only declares `ros: iron`.

## How Roboticks differs from GitHub-Actions self-hosted runners

You may already know the GitHub self-hosted runner. `roboticks-runner` is purpose-built for the V\&V loop:

|                 | GH Actions runner          | `roboticks-runner` v2                                   |
| --------------- | -------------------------- | ------------------------------------------------------- |
| Auth scope      | Repo or org level          | **Project-scoped** — one token per project pool         |
| ROS2 preinstall | None                       | Humble / Iron / Rolling images bundled                  |
| Sim engines     | None                       | **Gazebo Harmonic and Webots** preconfigured            |
| MCAP capture    | Custom action required     | **Direct presigned-URL upload to S3**                   |
| Traceability    | None                       | Reads `@confirms` from pytest output, emits link rows   |
| Network egress  | GitHub + arbitrary         | Roboticks platform only (air-gapped mode locks this in) |
| Distribution    | GitHub-tarball, opaque     | **Cosign-signed**, cross-platform GitHub Releases       |
| Updates         | Auto, sometimes disruptive | Drain-then-replace; pinned versions supported           |

## Why a pool, not just a runner

Pools let you declare **policy** at one level and let many machines fulfill it:

* A single `prod-gpu-farm` pool can have 12 machines, each declaring its GPU model. The router fans out across all of them.
* Quotas and concurrency caps live on the pool, not the runner.
* Air-gapped, network-isolated, and license-restricted (e.g., LDRA-licensed-host) jobs share one routing primitive.

## Next steps

<CardGroup cols={2}>
  <Card title="Install a runner" icon="download" href="/runners/installation">
    Linux, macOS, Windows. Cross-arch binaries from GitHub Releases.
  </Card>

  <Card title="Create a pool" icon="layer-group" href="/runners/pool-management">
    Dashboard or CLI. Registration tokens, rotation, revoking.
  </Card>

  <Card title="GPU setup" icon="microchip" href="/runners/gpu-setup">
    nvidia-container-toolkit, multi-GPU, capability declaration.
  </Card>

  <Card title="Air-gapped mode" icon="lock" href="/runners/air-gapped">
    On-prem only. Enterprise tier. No GitHub connectivity required.
  </Card>
</CardGroup>
