GitHub integration
Setting up sluice lands on a branch in
the repository on your machine. Most teams’ main lives on GitHub
instead, and everyone pulls it from there. This guide makes sluice land
on GitHub’s main, still running everything on your one machine.
What changes
Section titled “What changes”One line in the branch’s policy, .config/sluice.toml:
[branches.main]remote = "origin"required = ["#check-fast", "#check-tools"]sluice reads the policy from main as it stands before a landing, so
the landing that adds remote lands on your machine only. Push main
to GitHub by hand that once; sluice pushes every landing after it.
With remote set, GitHub’s copy of main is the real one:
- Every round fetches it first. Whoever runs the round (a waiting
wt submit,sluice runorsluice step) fetchesmainfromoriginintoorigin/mainbefore reading the branch, and forms every combination on it. Fetching leaves your localmainwhere it is. - A landing is a push. When a combination passes, sluice pushes its
merge commit to GitHub’s
main, and the push only succeeds ifmainis still where the combination started. Then it moves your localmainto match. - Only the branch goes to GitHub. The queue, the test results and
the logs stay in
.git/sluice/on your machine, as before. On one machine nothing else needs them.
Nothing is rebased. A landing is the same merge commit as before, with the submission’s commits as its second parent and the result in its trailers.
sluice submit and wt submit report “landed” only once GitHub has
accepted the push.
Set up GitHub
Section titled “Set up GitHub”Keep everyone else’s pushes off main with a ruleset, in the
repository’s Settings › Rules › Rulesets › New branch ruleset:
| setting | value |
|---|---|
| target branches | main |
| restrict updates | on |
| block force pushes | on |
| bypass list | sluice’s GitHub App alone |
Leave GitHub’s own merge queue off, and don’t require status checks on
main: sluice’s gate is the check, and it runs before the push.
sluice pushes as its own GitHub App, which Give sluice its own GitHub
identity sets up. Only sluice’s own fetches
and pushes carry the app’s token, so the ruleset refuses every other
push to main, your agents’ included. Until the app is set up, sluice
pushes with the credentials your git push uses, the bypass list has
to hold your account, and sluice status says sluice has no identity of
its own. Your agents push with those credentials too, so keeping them
off main is then the job of the reference-transaction hook that
sluice protect installs, as in branch
protection.
A worktree with main checked out falls behind GitHub’s main on every
host that didn’t land, and sluice moves main under it on the host that
did. Keep a detached worktree at origin/main instead, as worktrees
beside sluice shows.
Bolts on GitHub
Section titled “Bolts on GitHub”A bolt is a branch sluice lands on like main. Give its pattern a
remote to keep it on GitHub too, so agents on any host can work on one:
[branches."bolt/*"]required = ["#check-fast"]remote = "origin"sluice makes the bolt there, at main’s revision on GitHub, and deletes
it once it has landed on main:
$ sluice branch create bolt/payments --from maincreated bolt/payments at 6ac0084c…, main's revision$ sluice branch delete bolt/payments --into maindeleted bolt/payments, which was at 9f2e1d0a…, landed into mainCut agents’ worktrees from origin/bolt/payments. A host that has only
fetched the bolt, with no local branch of it, submits to it all the same.
A submission to a bolt GitHub doesn’t have is refused, and the refusal
says to make it with sluice branch create.
Protect bolts as main is: one ruleset on bolt/* restricting
creations, updates, deletions and force pushes, with sluice’s app as
its only bypass. sluice forge check bolt/payments checks it.
Each host keeps its own queue for a bolt. The lease keeps every landing
safe, but two hosts landing on one bolt land in the order their pushes
reach GitHub, and sluice branch delete sees only this host’s queue.
When main moves under the queue
Section titled “When main moves under the queue”While the bypass is yours, before sluice has its app, your own push to
main still gets through, and so does a click of GitHub’s merge
button. sluice treats either as
main moving under its queue. Say someone pushes 4847258 to main
while submission 1’s push is on its way:
$ wt submit mainsubmission 1 to main · nothing queued aheadtesting main + #1 · 1 tasks to run, 0 replayedpassed · landed as f2a1614The push names the revision the combination started from, so GitHub
refuses it once main has moved. sluice records the refusal in the
branch’s log, lands nothing, and the next round forms every combination
again on the new main and tests it again. Nothing in the queue is
lost: f2a1614 is the combination tested on 4847258. The log says
what happened:
$ grep refused .git/sluice/main/log.jsonl{"schema":"sluice/log@1","at":"2026-10-14T20:02:23Z","event":"refused","ids":[1],"expected":"7c829a5…","found":"4847258…"}The same holds when the push fails for any other reason, a dropped
connection included: the next round fetches and finds out where main
is. If sluice stops between the push and recording it, it
fetches on restart, finds its landing on main, and records it. Your
local main catches up at the next landing.
When sluice lands submissions exactly as they were tested, the ones behind them keep their results and aren’t tested again. Only a move from outside the queue sends them back.
When GitHub can’t be reached
Section titled “When GitHub can’t be reached”A round that can’t fetch lands nothing, since it can’t know where
main is. It stops and says why:
$ wt submit mainsluice: fetching main from origin failed: ssh: Could not resolve hostname github.com: nodename nor servname provided, or not knownfatal: Could not read from remote repository.
Please make sure you have the correct access rightsand the repository exists.Run it again once GitHub answers. Tests already running keep running, and their results count when the next round reads them.
What everyone else does
Section titled “What everyone else does”Pull main as usual: git pull brings in each landing, one merge
commit per submission. To land work, submit it to sluice; the ruleset
refuses a direct push to main from anyone but the bypass.
Next: pull requests, so each submission has a page on GitHub and people can review it first.