Skip to content

Deploy Runner

Run GitHub Actions jobs on Skippr-managed Linux runners. Keep workflow YAML in GitHub; point runs-on at a Skippr label. When GitHub queues a matching job, Skippr starts a runner for that session.

Runner is part of Deploy. Preview runners are Linux x86_64 only. macOS and Windows labels are not offered.

Status: Preview. See the API action reference for the full command list.

Before you start

  • Sign in with skippr login. See Cloud User Directory.
  • Ensure your policy allows the deploy actions you need. Owner and Admin already permit Deploy actions. Developer includes create, update, and list; ReadOnly includes get and list.
  • Install the Skippr Cloud Runners GitHub App on the GitHub organization that owns the repository. After install, copy the numeric installation id from GitHub. Do not paste a webhook secret; GitHub delivers to Skippr's platform hostname.

Steps 1–3 below show the same provisioning flow as CLI, Terraform, CDKTF TypeScript, or CDKTF Python. For provider credentials and the shared cloud provider block, see Terraform and CDKTF.

1. Record the GitHub App installation

bash
skippr deploy runner create-github-installation --input - <<JSON
{
  "installationId": "12345678",
  "accountLogin": "acme",
  "accountType": "Organization"
}
JSON
hcl
resource "cloud_deploy_runner_github_installation" "app" {
  installation_id = "12345678"
  account_login   = "acme"
  account_type    = "Organization"
}
ts
import { CloudProvider, CloudDeployRunnerGithubInstallation } from "@skippr/provider-cloud";

const cloud = new CloudProvider(this, "cloud", { region: "eu-central-1" });

const installation = new CloudDeployRunnerGithubInstallation(this, "app", {
  installationId: "12345678",
  accountLogin: "acme",
  accountType: "Organization",
  provider: cloud,
});
python
from skippr_cdktf import CloudProvider, CloudDeployRunnerGithubInstallation

cloud = CloudProvider(self, "cloud", region="eu-central-1")

CloudDeployRunnerGithubInstallation(
    self,
    "app",
    installation_id="12345678",
    account_login="acme",
    account_type="Organization",
    provider=cloud,
)

2. Bind a repository

Use the numeric GitHub repository id as repoId:

bash
skippr deploy runner create-repository-binding --input - <<JSON
{
  "repoId": "987654321",
  "installationId": "12345678",
  "owner": "acme",
  "name": "app",
  "defaultBranch": "main"
}
JSON
hcl
resource "cloud_deploy_runner_repository_binding" "app" {
  repo_id         = "987654321"
  installation_id = cloud_deploy_runner_github_installation.app.installation_id
  owner           = "acme"
  name            = "app"
  default_branch  = "main"
}
ts
import { CloudDeployRunnerRepositoryBinding } from "@skippr/provider-cloud";

const binding = new CloudDeployRunnerRepositoryBinding(this, "app", {
  repoId: "987654321",
  installationId: installation.installationId,
  owner: "acme",
  name: "app",
  defaultBranch: "main",
  provider: cloud,
});
python
from skippr_cdktf import CloudDeployRunnerRepositoryBinding

CloudDeployRunnerRepositoryBinding(
    self,
    "app",
    repo_id="987654321",
    installation_id=installation.installation_id,
    owner="acme",
    name="app",
    default_branch="main",
    provider=cloud,
)

Optional siteId attaches Site preview URLs for that repository. Leave it unset unless the repo publishes a Site.

3. Create a runner pool

bash
skippr deploy runner create-runner-pool --input - <<JSON
{
  "poolId": "ci",
  "installationId": "12345678",
  "repositoryId": "987654321",
  "size": "linux_x64_2",
  "labels": ["self-hosted", "linux", "x64", "skippr-linux-x64-2"]
}
JSON
hcl
resource "cloud_deploy_runner_pool" "ci" {
  pool_id         = "ci"
  installation_id = cloud_deploy_runner_github_installation.app.installation_id
  repository_id   = cloud_deploy_runner_repository_binding.app.repo_id
  size            = "linux_x64_2"
  labels          = ["self-hosted", "linux", "x64", "skippr-linux-x64-2"]
}
ts
import { CloudDeployRunnerPool } from "@skippr/provider-cloud";

new CloudDeployRunnerPool(this, "ci", {
  poolId: "ci",
  installationId: installation.installationId,
  repositoryId: binding.repoId,
  size: "linux_x64_2",
  labels: ["self-hosted", "linux", "x64", "skippr-linux-x64-2"],
  provider: cloud,
});
python
from skippr_cdktf import CloudDeployRunnerPool

CloudDeployRunnerPool(
    self,
    "ci",
    pool_id="ci",
    installation_id=installation.installation_id,
    repository_id=binding.repo_id,
    size="linux_x64_2",
    labels=["self-hosted", "linux", "x64", "skippr-linux-x64-2"],
    provider=cloud,
)

Sizes are linux_x64_1, linux_x64_2, linux_x64_4, linux_x64_8, linux_x64_16, and linux_x64_32. The public label is skippr-linux-x64-{n}. skippr-linux-x64 aliases skippr-linux-x64-2.

4. Target the pool from GitHub Actions

Keep using GitHub Actions YAML. Point runs-on at the pool labels:

yaml
jobs:
  test:
    runs-on: [self-hosted, skippr-linux-x64-2]
    steps:
      - uses: actions/checkout@v4
      - run: cargo test

When GitHub queues a matching workflow_job, Skippr starts a new runner from the managed image for that session. The previous job's disk is not reused. List sessions with skippr deploy runner list-runner-sessions. Cancel an in-flight session with skippr deploy runner cancel-runner-session. Deleting a pool stops in-flight sessions, then removes the pool.

Limits and errors

  • Preview image is Linux x86_64. Other runner OSes are not available.
  • Fork pull requests are denied unless the pool fork policy allows them.
  • If the pool is already at maxConcurrent in-flight sessions, Skippr rejects the job until a session finishes. Raise maxConcurrent so the account can run many jobs at once; Skippr starts them until that ceiling or available capacity. Duplicate deliveries redrive the existing session.
  • Duplicate webhook deliveries are ignored.
  • CloudMachines.* is not available. Do not create fleets to host runners.