Skip to content

sluice

A merge queue for agents working in parallel worktrees. Agents submit. sluice tests each submission exactly as it would land, names the one that broke the build, and moves the branch only to code that passed.

sluice: a merge queue for agents in worktrees Three agents, each in its own worktree, submit their work and never merge. sluice forms candidates branch plus A, branch plus A plus B, and branch plus A plus B plus C, and tests them at once. Branch plus A plus B fails, so B is the one culprit and only agent B is told. A lands as a merge commit; C is re-formed on the branch without B, mostly replays from the cache, passes and lands. The branch moves only to what passed. sluice a merge queue for agents in worktrees AGENTS · EACH IN A WORKTREE SLUICE · QUEUE OF bolt/pay entries THE BRANCH agent A worktree unit/auth building… submitted · waiting landed agent B worktree unit/ledger building… submitted · waiting told: pkg-x:test failed agent C worktree unit/export building… submitted · waiting landed A B C branch + A testing… passed landed branch + A + B testing… failed: pkg-x:test B removed: culprit branch + A + B + C branch + A + C testing… discarded: B is ahead re-formed · 9 of 11 replay passed landed before merge Averdict in trailers merge Cverdict in trailers bolt/pay moved only by sluice, from the revision the candidate was formed on 1Agents submit their work.None of them merges. 2Each candidate is testedexactly as it would land. 3A failure has one culprit,and only its agent is told. 4The branch moves onlyto what passed.

In a Claude Code session in a terminal, install the plugin, then ask Claude to set sluice up in your repository. It installs the sluice binary too, asking first.

/plugin install sluice --marketplace agentplot/sluice

Neither? Install by hand and follow the walkthrough.

Run ten coding agents in ten worktrees and each one’s tests pass on its own. Merge them and the branch breaks, because nobody tested the combination. Let the agents merge for themselves and they race, rebase over each other’s work, and can’t tell whose change broke the build.

sluice takes merging away from the agents. Each one finishes its work and submits it. sluice queues the submissions, tests each one on top of everything queued ahead of it, and lands it only if that exact combination passes.

  1. Submit

    An agent finishes its work in its own worktree and submits it to a branch. The submission joins that branch’s queue. No agent merges.

  2. Combine

    Each submission is tested on top of everything queued ahead of it: the branch, plus every submission ahead, plus this one, checked out fresh in its own worktree. Several combinations run at once.

  3. Blame one

    When a combination fails, sluice waits for a result on every combination ahead, works out the one submission at fault and tells only that agent, with the failing tests and their logs. The rest are formed again without it, and the tests that already passed are replayed, not run.

  4. Land

    A combination that passes lands as a merge commit carrying exactly the tree that passed. A git hook refuses every other update to the branch, and sluice moves it only from the revision it tested on.

Try what landed

sluice preview brings a revision the branch landed up on your repository’s own stack, at addresses a person opens, and keeps it until it is released. One per landing, side by side, nothing kept checked out by hand. Previews.

No daemon

sluice keeps nothing running itself. A waiting sluice submit drives the queue while it waits; sluice run, or sluice step from cron, does the same for a host. What a preview leaves up, your own tools keep until it is released. Every decision is written to plain files before it is acted on, so a crash at any point resumes from the files.

sluice is the family’s landing step. headwater and eddy notice what changed, millpond keeps the inbox, flume launches the work in a worktree and sounding works a question through; sluice lands what they make. Each tool stands alone, and sluice is the one in use today.

The Flywheel family: one loop from what is noticed to what landsheadwater reports a new release of mise and eddy lists a recorded planning call; each prints a capture, and millpond keeps both. The release is its own excerpt, so it becomes one signal; a reader reads the meeting into three signals. Curation joins two of them into one item and makes the third, a question, an item of its own. Each item runs down the flume, which launches one agent in one worktree for it: the bump in one worktree, the export in a planner's plan, and the question in a sounding, whose accepted conclusion comes back to millpond as a new item. sluice tests each change as merged and lands both on main, and flume tidies the bump's worktree. The landed bump moves the pin back to headwater, which stops reporting that release. Flywheel is the Method the whole loop belongs to.Flywheelthe Method all of it belongs to1NOTICE2INBOX3LAUNCH4WORK5LAND6THE LOOP CLOSESthe landed bump moves the pin to 2026.10.10headwatermise 2026.10.10new release · reportedpinned · not reportededdyWispr · planningrecorded · 32 minmillpondthe inboxcapturessignalsitemsown excerptreadercurationflumeone worktreean agent on one brancha planner's plana chore for a teamsoundingworks one questionconclusion acceptedlanded · tidiedsluicetests each as mergedlands what passedmiseCSVmainbump miseCSV exportkeep JSONParquet?releasemeetingsentsentbump miseCSV exportbump miseCSV export2 signalsParquet?Parquet
The Flywheel family: one loop from what is noticed to what landsheadwater reports a new release of mise and eddy lists a recorded planning call; each prints a capture, and millpond keeps both. The release is its own excerpt, so it becomes one signal; a reader reads the meeting into three signals. Curation joins two of them into one item and makes the third, a question, an item of its own. Each item runs down the flume, which launches one agent in one worktree for it: the bump in one worktree, the export in a planner's plan, and the question in a sounding, whose accepted conclusion comes back to millpond as a new item. sluice tests each change as merged and lands both on main, and flume tidies the bump's worktree. The landed bump moves the pin back to headwater, which stops reporting that release. Flywheel is the Method the whole loop belongs to.Flywheelthe Method all of it belongs to1NOTICE2INBOX3LAUNCH4WORK5LAND6THE LOOP CLOSESthe landed bump moves the pin to 2026.10.10headwatermise 2026.10.10new release · reportedpinned · not reportededdyWispr · planningrecorded · 32 minmillpondthe inboxcapturessignalsitemsown excerptreadercurationflumeone worktreean agent on one brancha planner's plana chore for a teamsoundingworks one questionconclusion acceptedlanded · tidiedsluicetests each as mergedlands what passedmiseCSVmainbump miseCSV exportkeep JSONParquet?releasemeetingsentsentbump miseCSV exportbump miseCSV export2 signalsParquet?Parquet
The Flywheel family: one loop from what is noticed to what landsheadwater reports a new release of mise and eddy lists a recorded planning call; each prints a capture, and millpond keeps both. The release is its own excerpt, so it becomes one signal; a reader reads the meeting into three signals. Curation joins two of them into one item and makes the third, a question, an item of its own. Each item runs down the flume, which launches one agent in one worktree for it: the bump in one worktree, the export in a planner's plan, and the question in a sounding, whose accepted conclusion comes back to millpond as a new item. sluice tests each change as merged and lands both on main, and flume tidies the bump's worktree. The landed bump moves the pin back to headwater, which stops reporting that release. Flywheel is the Method the whole loop belongs to.Flywheelthe Method all of it belongs to1NOTICE2INBOX3LAUNCH4WORK5LAND6THE LOOP CLOSESthe landed bump moves the pin to 2026.10.10headwatermise 2026.10.10new release · reportedpinned · not reportededdyWispr · planningrecorded · 32 minmillpondthe inboxcapturessignalsitemsown excerptreadercurationflumeone worktreean agent on one brancha planner's plana chore for a teamsoundingworks one questionconclusion acceptedlanded · tidiedsluicetests each as mergedlands what passedmiseCSVmainbump miseCSV exportkeep JSONParquet?releasemeetingsentsentbump miseCSV exportbump miseCSV export2 signalsParquet?Parquet

One loop, from what is noticed to what lands. Flywheel is the Method it belongs to.

  1. 1headwater and eddy notice events and print captures.
  2. 2millpond keeps them as an inbox: captures become signals, and curation joins signals into items.
  3. 3millpond sends each item down flume, which launches one agent in one worktree for it, and tidies the place once the work lands.
  4. 4An item is worked in its worktree or a planner's plan. A question goes to a sounding, whose conclusion comes back as new items.
  5. 5sluice tests the work as merged and lands it.
  6. 6The landed bump moves the pin, so headwater stops reporting that release.
Terminal window
nix profile install github:agentplot/sluice

Other ways: a release binary for macOS on Apple silicon and Linux on x86-64 and ARM, cargo install --locked --git https://github.com/agentplot/sluice sluice with Rust 1.98 or later, or the flake as an input. Each installs two executables: sluice, and wt-submit, which worktrunk runs as wt submit.

Terminal window
curl -fsSL https://github.com/agentplot/sluice/releases/latest/download/sluice-aarch64-darwin.tar.gz \
| tar -xz -C ~/.local/bin sluice wt-submit

1. Say what gates the branch. Commit .config/sluice.toml:

[tests]
runner = "command" # or "moon", to run only what a change affects
command = "make test"
[branches.main]
parallel = 4 # combinations under test at once

sluice reads this file from the branch itself, never from a submission, so no submission can loosen the rules that judge it.

2. Protect the branch, once per repository:

Terminal window
sluice protect

3. Submit from an agent’s worktree, with its work committed:

Terminal window
sluice submit main # or: wt submit main

It waits, and says what happened:

submission 3 to main · 1 queued ahead (#2)
testing main + #2 + #3 · 4 tasks to run, 2 replayed
passed · landed as 9f2c1e4

or, when this submission broke the combination:

failed: tests:t-cards
on main + #2 + #3 (5b81d07)
#2 passed on its own, so the failure is from this submission
log of tests:t-cards: /…/sluice/.logs/main/c4/tests:t-cards.log
fix it in your worktree and submit again

The exit code says the same:

exitmeaning
0landed
1failed
2a conflict or a refusal
130stopped with Ctrl-C; the submission stays queued

A complete setup, with moon, a sandbox, a build cache and two tiers of branches, is the walkthrough. The whole configuration is in the reference.