Skip to content

Custom Profiles

A custom profile describes one specialized GitHub Actions worker pool.

Create the manifest

Create profile.json beside the profile's Dockerfile:

{
  "$schema": "../../runner-profile.schema.json",
  "schemaVersion": 1,
  "name": "browser-testing",
  "description": "Pinned browser-testing workers.",
  "image": "pitcrew-browser-testing:local",
  "labels": ["browser"],
  "replicas": 2,
  "pullImage": false,
  "disableDefaultLabels": true,
  "build": {
    "context": ".",
    "dockerfile": "Dockerfile",
    "args": {
      "BROWSER_VERSION": "123.0.0"
    }
  },
  "verificationCommands": [
    "browser --version"
  ]
}

Use -ProfilePath when the manifest is outside PitCrew's built-in profiles/<name>/ directory.

For a prebuilt image published by a workload repository, follow the complete Repository-Owned Worker Images lifecycle.

Build the image

When a manifest defines build, PitCrew builds the image before replacing the live profile. Build arguments are restricted to non-secret configuration.

Never place tokens, passwords, API keys, or private keys in a profile manifest or Docker build. Inject workload credentials through the GitHub Actions job.

Verify the image

Use verificationCommands to assert stable executable paths and pinned versions. PitCrew runs every command against the prepared image before stopping the current profile.

If verification fails, the existing profile remains online.

Autoscaled profiles must retain /actions-runner/bin/Runner.Listener. JIT workers bypass the image's normal entrypoint, so runtime prerequisites must be installed during the image build. PitCrew preserves the Dockerfile's declared user instead of overriding it.

Profiles that intentionally use a non-root USER must preconfigure writable tool and cache locations and must use labels that distinguish that reduced capability from the root-capable default profile. Do not route workflows that expect system package or SDK installation to an unprivileged image under the same labels.

Route jobs to the profile

Every named profile receives its profile name as a mandatory label:

jobs:
  browser-tests:
    runs-on: [linux, x64, browser-testing]

Keep disableDefaultLabels enabled unless broad self-hosted jobs are intentionally allowed to consume the profile.