Executors and systems
sluice on one host keeps each branch’s queue in the repository’s git directory, and runs every check itself. That stays true until a policy names signers. This guide moves a branch to many hosts: agents on any machine submit to one queue, a box you keep running takes the checks, and an agent can submit and switch its host off. No server takes part: every host runs the same sluice, and the queue lives on the git remote.
One host, as today
Section titled “One host, as today”Nothing here changes a policy with no [signers] table. Each host keeps
its own queue, runs its own checks, and a branch’s
trust lists executors, as
before.
What moves to the remote
Section titled “What moves to the remote”A branch with a remote, in a policy with signers, keeps its queue on
that remote under refs/sluice/
(state).
Every host that submits to the branch reads and writes the same queue.
One host at a time keeps the branch, and another takes it over once the
queue has stood still for that host’s
[peers] lease with work to
do. Runs are claimed: a host with room takes the earliest open run of a
system it runs, and a claim lapses once its host has shown no sign of
life for [peers] alive.
Because any host can write the queue, a result counts only when a signer the branch trusts signed it. A record that only says it came from a confined container counts for nothing.
Signers
Section titled “Signers”Give each host that runs checks an SSH key of its own, kept on that host:
ssh-keygen -t ed25519 -f ~/.config/sluice/signing -N ""Name it in that host’s config, ~/.config/sluice/config.toml, or where
the host’s configuration is managed
(who writes it):
[signing]signer = "box"key = "~/.config/sluice/signing"List its public half in the policy, and trust it on the branches it may decide:
[signers.box]ssh = "exec@build-1 ssh-ed25519 AAAA..."confined = truesystems = ["linux-x64"]
[signers.sessions]ssh = ".config/sluice.sessions" # one line per agent host's keyconfined = false
[branches."feature/*"]remote = "origin"trust = ["sessions", "box"]
[branches.main]remote = "origin"trust = ["box"]confined = trueconfined = true on a signer is a claim you make for it: no agent can
reach the checkouts its runs use, or what they wrote. Say it only of a
host that runs no agents, where each run gets a fresh container.
sluice never works it out.
A branch with confined = true counts only results from signers you
said that of.
Agents’ hosts sign as sessions here. Their results land work on the
feature branches, where reviewers trust them, and never on main, whose gate
trusts only the box. A host signs with its own key, and sluice run on
it claims only runs of branches that trust its signer.
A box kept warm
Section titled “A box kept warm”A standing executor is a host you keep running with sluice run, under
whatever keeps services running there. Its build cache stays warm
between runs, so it is the cheapest place for a check. Its config says
what it signs as, how many runs it holds, and which systems it runs:
[signing]signer = "box"key = "~/.config/sluice/signing"
[runs]max = 4systems = ["linux-x64"]sluice run serves every branch with records, those on the remote
included. On a branch another host keeps, it claims open runs it may
take, runs them, signs what they found and adds it to
refs/sluice/runs/box. It refuses to start when [runs] systems names
a system it isn’t.
Before it claims anything after coming back, a host releases the checkouts it left behind. A run whose claim lapsed while it was away has already gone to another host, and the late result is never written.
Choosing systems per check
Section titled “Choosing systems per check”A repository that ships for several systems names them, and a branch says which each check must pass on:
[systems]linux-x64 = { os = "linux", arch = "x86_64" }macos-arm64 = { os = "macos", arch = "aarch64" }
[branches.main]systems = ["linux-x64"]
[branches.main.systems_for]"cli:build" = ["linux-x64", "macos-arm64"]A pass on one system never stands for another. Each combination becomes
one run per system, each run holding only the checks that need it, and
a host takes only runs of its own system. A run no host can take
fails the combination when the branch’s timeout passes, naming the
check and the system it never ran on. Name a system only for the checks
that need it: Parallel and
batch counts
what each costs.
When no box has room
Section titled “When no box has room”A run waits until a host of its system that the branch trusts has room, and claims go earliest combination first. GitHub Actions as a pool of machines that takes a burst, or a system no box runs, is designed, not built.
Watching it
Section titled “Watching it”sluice overview lists the hosts serving a remote, by their last sign
of life: the signer, the system, the runs held, the room left, and a
host whose sign of life has stood still past alive. sluice step <branch> says led on a host that does not keep the branch, and still
takes its runs. sluice status <branch> reads the queue from the remote.
When the remote is out of reach, it shows the queue as last fetched and
says so.
Moving a branch that has a queue
Section titled “Moving a branch that has a queue”The landing that adds [signers] moves each branch with a remote. The
first host to take a branch pushes its own queue there as the start.
Another host whose queue wasn’t first submits its queued work again, and
sluice status <old id> names the new one. Results recorded before the
move were nobody’s signature, so each check runs once more under a
signer.