Switchyard Rails · CI for conductor hosts

The build is the evidence.

Rails runs your pipeline on agents you host, posts one commit status per step, and answers the conductor’s head-check read natively — so a pull request is green because a check ran and passed, not because an agent said it did.

push → build → rails/<pipeline>/<step> → merge lane
switch · clear rails/switchyard-rails · success PR #7 · conductor/a1f3/sr-4-hosting PR #2208 · conductor/a1f3/prd-699 rails/switchyard · pending · test 4/6 → staging one head, one status
two pull requests, two builds, one line onto staging — the switch clears when the status is green

Four things it owns, and nothing else

One Go binary, one SQLite file, agents on your machines. Everything a conductor needs to trust a head is one of these four.

  1. 1
    The pipeline file
    .swrails.yml is Buildkite-shaped: command, wait, block, input, trigger and group steps; depends_on, if:, matrix, retry, soft-fail and concurrency groups. A step can upload more pipeline mid-build.
  2. 2
    Agents on your hosts
    A tagged agent claims the jobs its tags match, streams the log, and drains before it upgrades itself — only to a release whose SHA-256 the server pinned. A failed upgrade is declined for an hour, not retried blind.
  3. 3
    One status per step
    GitHub sees rails/<pipeline> for the build and rails/<pipeline>/<step> for each job, through an outbox that dedupes and backs off. Fork pull requests never build.
  4. 4
    The conductor’s read
    GET /api/v1/checks names the SHA it is answering for and where that SHA came from, so the conductor falls back to GitHub unless the answer is about the exact head it asked for.
How it works

Nothing self-certifies

A conductor merges on CI plus a finished review. Rails is the CI half: it decides from evidence — the exit code, the status it posted, the SHA it built — and keeps the record where the conductor can read it back.

conductor → HeadChecks → rails → sha_source: push
  • A job token dies with its job
    Every job gets its own bearer for meta-data, artifacts and annotations. When the job finishes, the token is gone; a leaked log line buys nothing.
  • Retry is a conductor verb
    The conductor’s rework lane calls POST /builds/{id}/retry-failed; only the failed steps run again, under the same build, and the statuses update in place.
  • Secrets are references
    Config holds env:NAME or file:/path, never a value; the loader refuses an inline one. The log stream masks any secret-named variable before it is stored.
  • One file, backed up online
    SQLite in WAL mode behind one writer. Backups are taken with VACUUM INTO while serving, checked with integrity_check, rotated, and reported on /metrics.

What you can go and check

Each claim below names the mechanism behind it. If the mechanism is not there, the claim is false.

  • Webhooks are verified
    Every GitHub delivery is HMAC-checked against the server’s webhook secret before anything is scheduled. A bad signature is a 401 and no build.
  • Lost agents are reaped
    A job whose agent stops heartbeating is failed as lost, its status goes red, and it can be retried. Nothing waits on a machine that is gone.
  • Upgrades are pinned
    The server offers one version with one checksum per platform. The agent downloads, verifies, swaps the binary and re-executes — or declines and says why.
  • Paths stay in the tree
    Cache keys and artifact paths refuse any .. segment, on the agent and on the server. A pipeline cannot write outside its checkout.
Install

Two commands to a working agent

The installer fetches the current release for your platform from this site, verifies it against checksums.txt, and puts swrails on your path. Then point it at this server with the agent token.

Every platform and the releases
curl -fsSL https://rails.switchyard.work/install.sh | sh

swrails agent \
  --endpoint https://rails.switchyard.work \
  --token file:/etc/swrails/agent.token \
  --tags os=linux,arch=arm64,role=conductor
current release v0.1.0 · linux, darwin · amd64, arm64 · sha256 in checksums.txt

Point a conductor at it

Add a rails block to the conductor config with this server’s URL and a token reference. The next pull request it opens is built here.