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:
- Clones the repository at the specified commit
- Downloads dependency artifacts (if any)
- Runs each command sequentially
- Streams output to the forge in real-time
- Uploads artifacts (if configured)
- 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