ADR 0068: sluice stays a plain command line that needs no daemon; a host may run one driver, which waits follow; a submission's outcome is pushed to its submitter and kept until told
Status: accepted · Date: 2026-10-27
Status: accepted by the user on 2026-10-28, on their card (“Approved”), after a revision on their note of the same day and an amendment naming the carriers.
Amended 2026-10-28 by record 0070, accepted by the user: told and untold are delivered and pending, the one command a session’s start uses is sluice inbox, and a push is a notice; the record’s field is delivered, the former told still read.
Deciders: the user, on the record’s first card (2026-10-28): “We want Sleuth to be easy for new people to adopt and telling them they have to set up a daemon is probably not what I want. It should be able to work as a simple CLI”, which settles that nothing of sluice’s need run for sluice to work and that no adopter is told to set up a daemon; the user, in swancloud-ops’s pane the same night (afterthought/crew-state, swancloud/main, signal 2026-10-28-swancloud-ops-4f509aa5/01-waits-are-pushed-and-reconnect-after-restart): “If our records already know about sluice submissions, crew units, and chores, then if we restarted a Claude Code session, it should be able to come back up and reconnect with those watchers (either through the mod or through some instruction)”, which settles that an outcome reaches a session by a push the session picks up again from the records after a restart; madswan-design for the shape; the user’s yes is asked on the record’s card. swancloud-design holds the design across crew, Flume and sluice (crew record 0046).
Sources: README.md on main at 2026-10-27, “No daemon”: sluice keeps nothing running itself, a waiting submit drives the queue while it waits, sluice run or sluice step from cron does the same for a host; statement clauses 20, 26, 50, 51, 71, 129, 131 and the C.5 worktrunk row; rules core.4, core.11, core.25; ADRs 0011, 0041, 0056 (which declined a per-host service for the same reason); crates/sluice-core/src/records.rs (told on a submission); swancloud’s reading of deneb on 2026-10-28 (signal 2026-10-28-swancloud-ops-cc4c8120/01: the host saturated by watchers and waits).
Context and problem statement
Section titled “Context and problem statement”sluice has always kept nothing running: a repository’s owner installs a command line, writes a policy, and submits. A branch’s rounds, the forming, testing and landing of its candidates, are run by whoever waits, a waiting sluice submit or a sluice wait, and sluice run or sluice step from cron is there for a host that wants its queues moved while nobody waits (core.4, ADR 0011, 0041). That is the principle a new adopter meets first, and it stands.
The fleet’s hosts strain it. On deneb many agents each poll their own submission every few seconds and each run rounds, and the queue stops moving the moment the last of them stops. The outcome is told by the round that decides it, to the session’s pane through the multiplexer (20, 50, C.5), and sluice wait reports it as its exit; an agent whose session restarted between its submit and the outcome has lost its wait and learns nothing until it asks again. The user asks that the outcome reach the agent by a push it picks up again after a restart, from the records, which already hold it; and that whatever the fleet does about its waits, sluice itself must work as a simple CLI with no daemon to set up.
The first draft of this record made a standing driver per host the design, started by what the host binds. The user read it as a service every adopter would be told to run, which is what the README has refused from the start.
As built on main at 2026-10-28, the core keeps an outbox per branch: a step tells each decided outcome through the driver’s notify (50) and marks the entry told when notify returns. The worktrunk driver’s notify delivers nothing, so every entry is marked told with nobody told; the pull-request driver’s posts the outcome on the request. An entry records its submitter’s agent, worktree and path, no session. The Claude Code board wakes its own session with a turn for each outcome of its submissions, from a told list of its own in the plugin’s state, and the herdr plugin toasts the user from a told list of its own; neither marks sluice’s records. swancloud-design asked on 2026-10-28 which of the board’s wake and the round’s push delivers and marks told (signal 2026-10-28-swancloud-design-38c5f39f/01 on swancloud/main), recommending the board.
Considered options
Section titled “Considered options”- As built: every wait drives the rounds and reads its own outcome;
sluice runwhere someone starts it; the outcome told once by the deciding round and otherwise found by asking. - A standing driver per host as the design, started by what the host binds, a service on a managed host or a plugin’s lease (this record’s first draft).
- sluice stays a plain command line: nothing of sluice’s need run, and a host that runs nothing moves its queues by its waiting submits and waits as today. Where a host chooses to run
sluice run, by hand, from cron, by a fleet’s service or by a plugin’s lease, it is the host’s one reader (129), and a wait or a watch that finds it live follows it and runs no round. The outcome is pushed into the submitter’s session through the multiplexer where one exists, recorded as told when delivered, and told again by a command to a session that starts with it untold. - The gate box’s driver alone (swancloud record 0039), every other host’s sessions following the records over the remote.
Decision outcome
Section titled “Decision outcome”Option 3.
What changes against what is built. The principle, that sluice is a plain command line and no adopter is told to run a daemon, is what sluice already is: the README has said “No daemon” from the start, and this record adds no process. It writes the principle into the statement (135) so no later record reads it away, as this one’s first draft did. Three behaviours change. Today every sluice wait and waiting submit runs the rounds itself, beside sluice run where a host runs one, and on deneb dozens ran at once; under this record a wait or a watch that finds the host’s sluice run live follows it and runs no round, so one process moves a repository’s queues on a host. Today nothing of sluice’s tells a session its outcome: the record is marked told while the worktrunk driver delivers nothing (submission 234 on 2026-10-28 reads told with nobody told), the Claude Code board wakes its session from a list of its own, and a shell pane learns nothing until it asks; under this record the round that decides pushes the outcome into the submitter’s pane through the multiplexer, the record says told only when it was, and the board carries sluice’s telling only where there is no multiplexer. Today a session that restarts between its submit and the outcome has lost its wait and finds out by asking status; under this record it asks one command at its start for every outcome untold to it.
A plain command line first. Nothing in a repository’s policy or a host’s configuration requires anything of sluice’s to run. A host with nothing running moves its queues as it always has: a waiting submit or a sluice wait runs the rounds (core.4), and a laptop, a new adopter’s or anyone’s, is as it was. The README’s “No daemon” stands as written. This is the principle; what follows is an option a host may take.
A host may run one driver, and waits follow it. A host may run sluice run, by hand, from cron, by a fleet’s service or by a plugin’s lease; the fleet’s hosts will, as swancloud decides for them. Where one runs it is the host’s one reader (129), so a repository has one process on the host reading its records and moving its queues; a wait or a watch that finds it live follows the document it writes and runs no round, and the host’s bound on runs (71) is that one process’s to keep rather than a count across waiters. A wait that finds none runs rounds as before. Nothing asks the adopter to know which case they are in.
An outcome is pushed, recorded as told, and told again to a session that comes back. The round that decides an outcome, whatever process ran it, pushes it into the submitter’s session through the host’s multiplexer where it has one (20, 50, C.5) and records on the submission that it was told, and when; a sluice wait that reports it records the same. An outcome not yet told stands in the records as decided and untold, and a session that starts, after a restart or on a new host, asks by one command for every untold outcome of the submissions it made, found by the submitter the submission recorded, and is told them; so no wait need stand for an outcome to arrive, and an agent that waits does so by choice. sluice wait keeps its exits and its --timeout (ADR 0041) for a session that chooses to block, and for every host where that is all there is.
One teller, and the carriers. sluice alone marks an entry told, on the word of the carrier that delivered its outcome, and no carrier keeps a told list of its own: the outbox as built is the teller, and a notify that delivered nothing marks nothing, which the worktrunk driver’s does today against clause 51. An entry records the session that submitted it as the host’s multiplexer names it, where the submit ran in one, and no session where it ran in none. Where it recorded one, the round’s push through the multiplexer is the delivery, the fleet’s case under herdr, and the board in that session is a reading there, as crew record 0048 has it. Where it recorded none, a laptop running Claude Code with no multiplexer, the submitter’s own harness carries it: the board, seeing an outcome of its session’s entry that the records show untold, asks sluice by the one command a session’s start uses to tell this session its untold outcomes, and starts the turn with sluice’s words; sluice tells once and answers nothing for an outcome already told, so the push, an ask and a reporting wait never deliver one outcome twice. The herdr plugin’s toast and row are the user’s surfaces, not the submitter’s session, and mark nothing. The board is chosen as a carrier of sluice’s telling rather than a deliverer of its own because a deliverer that marks told must write sluice’s records, which a plugin does only through a sluice command (ADR 0023), and because a submitter with no board, a shell pane or another harness, must be told the same way; the round’s push is kept as the first carrier because it is made by the command that decides the fact, through the one hub, as record 0048’s sixth pattern asks, and reaches every pane whatever runs in it.
Why not the others. Option 1 leaves the fleet’s load as measured, a queue that stops when its last waiter does, and a restarted session that learns nothing. Option 2 is right for the fleet and wrong as sluice’s design: it told every adopter to run a service, which the README refused and record 0056 refused again. Option 4 alone leaves a host that submits with no process to take its intake or read for its sessions.
Consequences
Section titled “Consequences”- Clause 135 of the statement states the principle first, that nothing of sluice’s need run, and then the option: a host may run one driver, which is its reader, and waits and watches follow it. Clause 51 says the outcome is pushed, recorded as told and told again to a session that starts. The C.5 worktrunk row says
sluice waitfollows a driver where one lives and runs rounds itself where none does. Rule core.31 is drawn from them. - The README’s “No daemon” paragraph stands and gains one sentence: where
sluice runis running on a host, waits and watches follow it and run no rounds of their own. - Binding
sluice runas a service on the fleet’s hosts is swancloud’s (crew record 0046); sluice ships nothing that starts it. - The Claude Code board, which already follows the reader’s document, gives up its own told list and its turn made from it: it asks sluice to tell its session the untold outcomes of the session’s entries, at its start and when the document shows one, and starts the turn with sluice’s words; under a multiplexer that push has come and sluice answers nothing. The herdr plugin keeps the user’s toast and row and marks nothing. What crew does with a told outcome is crew’s, as the wrapper.
- The worktrunk driver’s notify delivers through the multiplexer the entry recorded, or reports that there is none, and the entry is marked told only on a delivery; an entry submitted outside any multiplexer stands untold until an ask or a wait tells it.
- The submission record’s
toldnames when and to which session the outcome was delivered; a record without it is an untold outcome.