CI Runner

Bithyle runners execute CI jobs defined in .forge/pipeline.toml. You can run a public runner (serves all namespaces) or a namespace runner (scoped to your namespace's repos).

Installation

Install the runner binary via the install script or download it directly. The bithyle-runner binary is included in the standard tarball.

Registration

Namespace Runner (recommended)

Generate a registration token from your namespace settings:

# Via CLI (requires admin access to the namespace)
curl -X POST https://bithyle.com/api/v1/yournamespace/runners/token \
  -H "Authorization: BITHYLE1-HMAC-SHA256 ..."

Or generate the token from the web UI at https://bithyle.com/yournamespace/runners.

Then register:

curl -X POST https://bithyle.com/api/v1/yournamespace/runners/register \
  -H "X-Registration-Token: <token>" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-runner", "labels": ["linux", "x86_64"]}'

The response contains runner_id and token -- save both.

Public Runner

Public runners use the global registration token (set via BITHYLE_RUNNER_REGISTRATION_TOKEN on the server):

curl -X POST https://bithyle.com/api/v1/runners/register \
  -H "X-Registration-Token: <global-token>" \
  -H "Content-Type: application/json" \
  -d '{"name": "public-runner", "labels": ["linux"]}'

Running

Daemon Mode

The standard way to operate a runner. Set environment variables and start:

export BITHYLE_FORGE_URL="https://bithyle.com"
export BITHYLE_RUNNER_ID="<runner-id>"
export BITHYLE_RUNNER_TOKEN="<token>"
export BITHYLE_WORK_DIR="/tmp/bithyle-runner"  # optional, this is the default

bithyle-runner

The daemon:

  • Sends heartbeats every 60 seconds
  • Long-polls for jobs (30s server-side wait)
  • Executes jobs as they arrive
  • Reports results back to the forge

One-Shot Mode

For ephemeral environments (VMs, containers). Execute a single pre-claimed job:

export BITHYLE_FORGE_URL="https://bithyle.com"
export BITHYLE_JOB_ID="<job-id>"
export BITHYLE_CLAIM_TOKEN="<claim-token>"

bithyle-runner

The runner fetches the job payload, executes, reports done, and exits.

Job Execution

When a runner picks up a job, it:

  1. Clones the repository at the specified commit
  2. Downloads dependency artifacts (if any)
  3. Runs each command sequentially
  4. Streams output to the forge in real-time
  5. Uploads artifacts (if configured)
  6. Reports pass/fail

Container Jobs

Jobs with an image field run in rootless Podman containers:

podman run --rm -v <job_dir>:/work -w /work <image> sh -c "<command>"

The runner must have Podman installed for container jobs. Jobs without image run natively via sh -c.

Labels

Runners declare labels at registration time (e.g., ["linux", "x86_64", "gpu"]). Jobs can require labels, and the server only assigns jobs to runners whose labels are a superset of the job's requirements.

Environment Variables

Variable Required Default Description
BITHYLE_FORGE_URL yes -- Forge server URL
BITHYLE_RUNNER_ID daemon -- Runner ID from registration
BITHYLE_RUNNER_TOKEN daemon -- Bearer token from registration
BITHYLE_JOB_ID one-shot -- Job ID for one-shot execution
BITHYLE_CLAIM_TOKEN one-shot -- Claim token for the job
BITHYLE_WORK_DIR no /tmp/bithyle-runner Working directory for clones

Monitoring

The forge tracks runner health:

  • Runners send heartbeats every 60 seconds
  • If a heartbeat is missed for >120 seconds, the runner is marked offline
  • Running jobs on offline runners are automatically failed

View runner status at https://bithyle.com/yournamespace/runners or via the admin panel at /admin/runners.

Security

  • Namespace runners can only see jobs from their namespace
  • Public runners can see jobs from any namespace
  • Each job gets a unique claim token for authentication
  • Secrets are injected as environment variables and scrubbed from log output
  • Container jobs provide process isolation via rootless Podman