Self-hosted CI runners
developerz.ai turns your VMs into JIT (just-in-time) GitHub Actions runners. Change one line in any workflow file:
jobs:
test:
runs-on: developerz-2vcpu # was: ubuntu-latest
That's it. The job runs on your own hardware, logs are stored for 72 hours, and your billing is whatever your VPS costs — not GitHub's metered per-minute runner fees. See the GitHub billing note below for the one private-repo exception, with current date-stamped terms.
Prerequisites
- A box enrolled in your fleet (see quickstart).
- The GitHub App installed on the repo.
- The box has the
cicapability (set automatically on enrollment; verify withbox fleet_statusin the MCP).
Runner labels
Labels map to hardware tiers. Use any label your box satisfies:
| Label | vCPU | RAM | Notes |
|---|---|---|---|
developerz-2vcpu |
2 | ≥ 2 GB | Standard workloads |
developerz-4vcpu |
4 | ≥ 4 GB | Build-heavy / parallel tests |
developerz-8vcpu |
8 | ≥ 8 GB | Large monorepos |
developerz-gpu |
any | ≥ 8 GB | GPU capability required |
developerz-arm64 |
any | any | ARM64 architecture |
A job whose label no box satisfies stays queued until a matching box is available or the workflow timeout fires. The assigner logs label-match failures in the audit trail.
Security model
Scoped installation token
Each CI job receives a short-lived GitHub installation token scoped to the repo the job belongs to. The token is:
- Minted just-in-time by the API when the job is assigned.
- Valid for 15 minutes (standard GitHub installation token TTL).
- Revoked on job completion (best-effort; GitHub expires it anyway).
The box never holds the GitHub App private key — only the API does.
Fork PR policy
Jobs triggered by fork pull requests never run on fleet boxes. A fork PR can carry an attacker-controlled workflow file, so the assigner refuses these jobs before they are ever placed on your hardware — there is no policy key to opt in. Run fork-PR checks on GitHub-hosted runners instead.
The related repo-wide fence is ci.public_repos in .maintainer.yml (default
false): even for same-repo PRs, CI on a public repo stays off until a
maintainer opts in, because a public repo lets anyone open a PR whose workflow
runs on your hardware.
# .maintainer.yml
ci:
enabled: true # default: true — kill switch for the whole CI lane
public_repos: false # default: false — must be true to run CI on a public repo
No App credentials on the box
The GitHub App private key is never placed on a runner. Boxes talk to the API over an authenticated control channel; the API holds all secrets and hands each job only its scoped, short-lived token.
Ephemeral containers
Each CI job runs inside an isolated container (Docker or Podman). The container is created fresh for the job and destroyed when it completes. No state persists between jobs on the same box.
Log retention
Logs are streamed to object storage (your BYO S3 or the platform bucket) in real time, compressed with zstd, and retained for 72 hours. After 72 hours the reaper deletes them automatically.
To download a log:
# MCP verb
ci log_url --ci-job-id <uuid>
# → { url: "https://…presigned…", expires_in_seconds: 3600 }
Or from the dashboard under Fleet → CI.
Idle AI devs as CI runners
Boxes that run AI coding tasks (the worker runner mode) also serve CI jobs when
idle. The assigner checks box presence and capacity before routing. This means
your AI dev fleet doubles as CI infrastructure with no additional cost — the
hardware is already running.
GitHub billing note
Private repos only. GitHub charges $0.002/minute for self-hosted runner minutes on private repositories (2026-03 terms — verify current terms before pricing). Public / OSS repositories are exempt. The developerz.ai platform fee does not include this charge; it appears on your GitHub bill. Check github.com/pricing for the latest terms.
Checking CI run status
# MCP — list recent runs
ci runs --repo owner/repo
# Filter by status
ci runs --status failed --repo owner/repo
# Get log URL
ci log_url --ci-job-id <uuid>
Full verb reference: MCP verb reference → ci.