Skip to content

Releases: hamish-mackie/sloop

0.4.0-rc.1 - 2026-07-25

Pre-release

Choose a tag to compare

@github-actions github-actions released this 25 Jul 09:08

Release Notes

Added

  • result_check: { panel: {...} } puts 2 to 5 independent reviewers on a stage
    and derives its verdict from a quorum of their reports: Pass iff at least
    quorum seats reported Pass. Reviewers run one at a time in the run
    worktree with one shared prompt, so a panel never exceeds
    max_parallel_tasks, and their spawns count towards the worst-case execution
    budget a flow is admitted against. Each seat gets one-shot credentials bound
    to (run, stage, attempt, reviewer), so which report a sloop verdict call
    lands on comes from the credential and never from its arguments. A reviewer
    that exits without reporting counts as a Fail with no verdict reported.
    The aggregate is never stored — one append-only evidence row per reviewer is,
    and the verdict is recomputed from those rows by a pure function, so a
    restarted daemon reaches the same reading.
  • sloop verdict takes --confidence low|medium|high, defaulting to medium.
    It is recorded as evidence and never weighted into a panel's aggregation;
    floats are rejected. sloop show <run> lists each panel seat's verdict,
    confidence, and reason under its stage, silent seats included.
  • A new { builtin: sync } action merges the default branch into the run
    branch, inside the run worktree. It passes when that merge commits cleanly or
    there was nothing to integrate, and fails on a conflict — aborting the merge
    so a return_to target starts from a clean tree, with git's conflict output
    captured in the run log and so in the re-entered agent's prompt. Any number
    of sync stages, anywhere before the merge; the shared default-branch checkout
    is only ever read.
  • The merge stage takes { builtin: merge, ff_only: true }, which refuses the
    merge commit: the default branch either fast-forwards to the run branch head,
    or the stage fails having touched nothing. Absent, the merge policy is
    unchanged. ff_only is meaningful nowhere else and is a parse error on any
    other action.
  • sloop init writes a train flow beside default.yaml, opt-in with
    flow: train. It is the merge train: build → sync → verify → ff_only merge, with fail_action: { return_to: sync } on the merge, so a default
    branch that moves between the verification and the merge loops the train
    rather than landing a tree no stage tested. Its verify stage uses the
    repository's configured flow.test_cmd when it has one.
  • Flow stages can now bind the two fail_action forms that previously parsed
    but were rejected. fail_action: continue makes a stage advisory: its
    failure is recorded and visible in sloop show, the walk carries on, and the
    run's outcome is unchanged. fail_action: { return_to: <stage>, attempts: N }
    is a bounded backward edge: the walk re-enters an earlier stage and re-runs
    the whole span from there, so no verdict earned before the loop can reach the
    merge. Edges must point backwards, attempts is capped at 3, and a flow
    whose budgets could execute more than 32 stages is refused at parse time.
  • A re-entered agent stage is told why it is running again. Sloop appends a
    delimited previous attempt failed block to its prompt — after the ticket
    body and the worker instructions — naming the stage that failed, its resolved
    reason, and the last 100 lines of that execution's captured output. The block
    is rebuilt from the run's persisted evidence, so a daemon that restarts
    mid-loop composes the identical prompt. exec actions are handed nothing:
    their command line is fixed by the flow.
  • sloop show renders each stage execution separately, suffixing re-runs with
    their attempt (build, build#2), and a non-merged run's derived reason
    names the failure the walk actually stopped on rather than one a later
    attempt superseded.
  • sloop show tells an advisory failure apart from the one that ended the run:
    the stage table marks it advisory and the scan strip marks it warn rather
    than FAIL. A run's derived reason never names an advisory stage, since
    the walk provably continued past it, and a terminal run whose only failures
    were advisory says so. Stage rows carry a new advisory field.
  • A run whose walk stopped short says which halt it was. sloop show <run>
    appends ; return_to budget spent or ; the stage log does not replay against this flow to the derived reason where the failed stage alone does
    not explain the ending, and value.halt carries the same distinction as a
    stable token (fail_action, return_budget_exhausted, corrupt_log). It is
    re-derived by replaying the walk's own fold, so it cannot disagree with the
    driver.
  • sloop logs --stage accepts <stage>#<attempt>, selecting one execution of a
    stage a return_to edge re-entered. Parsing happens in the daemon, so every
    socket client gets it; a bare stage name still selects every execution. Log
    lines label re-runs the same way ([agent:build#2]), so the label sloop show prints is the selector to type next.

Changed

  • What Sloop called an activation is now a trigger. The scheduling model
    has three nouns — a ticket is what to do, a run is one attempt at it, and the
    third is the durable record that demand exists, the thing that makes the
    dispatcher pick a ticket up. "Activation" named the act of activating rather
    than the row waiting in a queue, so every mention of it had to be glossed
    first; "the trigger fired" and "the trigger is pinned to TICK-63" read without
    one. Scheduling, selection, claiming, and rearm behaviour are unchanged.

    Operator-visible consequences: sloop run prints trigger TR91 queued (now, ticket TICK-63); trigger ids widen from A<ordinal> to TR<ordinal>,
    because T91 reads as a ticket id beside TICK-91; and the dashboard field
    queued_activations becomes queued_triggers. On the wire, post and run
    take a trigger argument where they took activation, and post answers
    with trigger and trigger_suppressed. See "The activation → trigger
    rename" in docs/protocol.md for the full field-by-field table.

    Upgrading rewrites the database in place, ids and all. Queued triggers are
    pending work recorded in no committed file and no commit, so sloop reindex
    cannot rebuild one; the migration carries every row across instead.

  • sloop verdict --confidence on a reported stage is now recorded rather
    than discarded, so the flag means the same thing from a stage worker as from
    a panel reviewer. sloop show <run> prints it beside that stage's verdict
    source, and the stage row carries a new confidence field.

  • sloop template flow prints the current grammar as its canonical example:
    action, result_check, and fail_action written out on every stage, with
    one return_to edge, one advisory stage, and a commented panel block. The
    pre-action kind:/verdict: spelling and the deprecated on_fail are
    demoted to a short "legacy spellings" note, and sloop template ticket names
    the two flows that ship with the binary. sloop verdict --help and sloop logs --help now document who may call them and what their selectors accept.

  • Denials and parse errors use one vocabulary for one concept: a stage that
    cannot take a report says it does not use result_check: reported rather
    than naming a "verdict policy".

  • The ticket-state table in sloop --help --all states the trigger
    precondition first: ready said it was "eligible for dispatch once a run is
    queued", which reads as a caveat on a state that sounds like a promise. It
    now leads with the fact that a ready ticket runs only once a trigger is
    queued for it, and failed names both halves of the recovery — sloop retry
    returns it to ready, sloop run starts it again.

  • Captured output records, stage-process checkpoints, agent-exit checkpoints,
    and reported verdicts are all scoped to (stage, attempt) rather than stage
    alone, so a re-entered stage gets its own output, its own worker report, and
    its own exit checkpoint instead of inheriting an earlier attempt's.

Deprecated

  • The queued_activations field on status and on the show dashboard, in
    favour of queued_triggers. Both are emitted carrying the identical value,
    following the precedent set by the listshow aliases;
    queued_activations is removed in 0.5.0. The other envelope fields the
    rename touched are swaps rather than aliases — see docs/protocol.md.
  • on_fail repair blocks. fail_action: { return_to: <stage> } covers the
    same ground with the flow's own stages — a failing check stage returning to
    the stage it guards — and the daemon now logs a flow_on_fail_deprecated
    note when it admits a run whose flow uses on_fail. Nothing is removed:
    existing flows keep parsing, repairing, and settling exactly as before.

Fixed

  • A daemon spawned by a client command now calls setsid, so it leads its own
    session and process group instead of inheriting them from that client. The
    client exits as soon as its request is answered, so a daemon that stayed in
    its session died to any signal aimed at that short-lived process — a terminal
    hangup, or a supervisor reaping a finished command's process group — and the
    next client command silently started a replacement. The symptom was a daemon
    that vanished with no daemon_stopped record, and, if a run was in flight at
    the time, lost work.
  • sloop post accepts an absolute path to a ticket that reaches the repository
    through a symlink. The repository root is always canonicalized, but the path
    the operator typed was compared to it unresolved, so on macOS — where /tmp
    and /var/folders are both links into /private — posting a ticket by
    absolute path was rejected as "outside the repository". Both sides now
    resolve before the comparison. A ticket file that does not exist yet is
    unaffected: the longest existing ancestor resolves and ...
Read more

0.3.0

Choose a tag to compare

@github-actions github-actions released this 21 Jul 08:58

Release Notes

Added

  • The read surface is now one verb. Bare sloop or sloop show prints a
    dashboard: daemon status, scheduler state, and recent activity.
    sloop show <REF> resolves ticket IDs, ticket names, run IDs and aliases,
    unique run-id prefixes, and project IDs; an exact reference always wins.
    Anything else becomes a case-insensitive ticket pattern over IDs and
    names — a substring by default, an unanchored regular expression when the
    text contains regex metacharacters — rendered as a ticket list.
    -n/--limit N or the shorthand -N caps list rows. --follow streams
    the shown scope's events; ticket and run followers exit when the subject
    settles, and --follow --quiet returns only the outcome for scripting.
    Exit codes are stable: 0 for success or a merged subject, 1 for
    another terminal outcome or a daemon error, 2 for usage errors.
    sloop show --help documents the whole resolution ladder. Pattern
    resolution happens in the daemon: the show verb accepts patterns, the
    events verb gained an optional scope, and the list verb gained an
    optional limit, all additive within protocol version 1.
  • sloop template <kind> prints fully commented canonical templates for
    the config, flow, project, and ticket files, so a working example is
    always one command away.
  • sloop show <TICKET> now lists the ticket's runs, newest attempt first:
    alias, outcome, wall-clock span, and a strip of the run's flow stages
    marked ok, FAIL, .. (running), or - (not reached). A ticket that
    has never run prints runs: none.
  • sloop show <RUN> now shows the run's timeline, a per-stage table (state,
    attempts including on_fail retries, duration, exit code, and verdict
    source), and a derived reason for any non-merged terminal run — for
    example stage `test` failed (exit 1) after agent completed with commits. The reason comes from the stored stage and evidence rows, never
    from an agent's own claim about its work. Stage names come from the run's
    admitted flow snapshot, so a run reports the stages it actually had even
    after the flow file changes.
  • The show response gained value.runs on tickets and value.stages,
    value.attempt, value.agent_exit_code, and the timeline fields on runs,
    all additive within protocol version 1.
  • sloop logs gained --stage <NAME>, --tail <N>, and --follow.
    --stage selects one flow stage by the name the flow gives it, including
    the agent stage, and rejects a name the run's flow does not define instead
    of returning an empty page. --tail keeps the last N entries; --follow
    streams new entries until the run settles. The three combine, so
    sloop logs <RUN> --stage test --tail 50 answers "why did the test stage
    fail" in one command. Filtering happens in the daemon: the logs verb
    gained stage, tail, and after arguments and a terminal response
    field, all additive within protocol version 1.

Changed

  • The default flow's review stage is now a real gate. It previously
    inherited verdict: exit and passed whenever the reviewer process exited
    zero, so every fresh sloop init deployment silently approved all work.
    The shipped stage now uses verdict: reported, and the review prompt
    requires the reviewer to call sloop verdict pass|fail --reason exactly
    once; the command, not the prose, decides the stage.
  • Compact sloop --help now lists only the everyday operator commands
    (init, template, daemon, post, show, logs). Everything else,
    including the worker verb brief, remains available and documented under
    sloop --help --all.
  • sloop show <RUN> labels the agent stage's exit as agent exit: rather
    than a bare exit:, which could read as "the whole run passed" on a run
    whose later stage failed. The JSON exit_code field is unchanged.
  • Ticket lists — the dashboard, pattern results, and the deprecated list
    alias — order tickets by registration time, newest first, instead of
    oldest first, so recently posted and currently running work leads the
    output. State does not affect the order. Tickets registered in the same
    millisecond fall back to their id's numeric ordinal, newest first.
  • sloop post now reports every problem with a ticket file in a single
    invalid_arguments error, one per line under the file path, instead of
    stopping at the first one. A file whose frontmatter cannot be parsed at
    all still fails fast with the parse error, and a file with exactly one
    problem reads as it always has.

Deprecated

  • status, list, watch, and wait remain accepted as hidden
    deprecated aliases of sloop show. They no longer appear in normal help,
    and each invocation writes a note to stderr naming its replacement:
    status and list point to sloop show, watch to sloop show --follow (its optional scope and tail still work), and wait to
    sloop show --follow --quiet (its run and timeout still work). The
    aliases will be removed in a future release.

Fixed

  • sloop reindex now recognizes patch-equivalent merges. A run branch
    whose commits were squashed or rebased onto the default branch is
    detected with git cherry and indexed as merged; previously only true
    ancestor merges counted, and reindex flipped squash-merged tickets to
    needs_review.

Install sloop 0.3.0

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/hamish-mackie/sloop/releases/download/v0.3.0/sloop-installer.sh | sh

Install prebuilt binaries via Homebrew

brew install sloop

Download sloop 0.3.0

File Platform Checksum
sloop-aarch64-apple-darwin.tar.gz Apple Silicon macOS checksum
sloop-x86_64-apple-darwin.tar.gz Intel macOS checksum
sloop-aarch64-unknown-linux-musl.tar.gz ARM64 MUSL Linux checksum
sloop-x86_64-unknown-linux-musl.tar.gz x64 MUSL Linux checksum

Verifying GitHub Artifact Attestations

The artifacts in this release have attestations generated with GitHub Artifact Attestations. These can be verified by using the GitHub CLI:

gh attestation verify <file-path of downloaded artifact> --repo hamish-mackie/sloop

You can also download the attestation from GitHub and verify against that directly:

gh attestation verify <file-path of downloaded artifact> --bundle <file-path of downloaded attestation>

0.2.1

Choose a tag to compare

@github-actions github-actions released this 20 Jul 09:01

Release Notes

Fixed

  • Keep worker socket paths within the 104-byte macOS socket path limit by
    placing them directly in the runtime directory under the short run id.
    On macOS the previous layout exceeded the limit, every agent spawn failed
    at socket bind, and no run could start.

Install sloop 0.2.1

Install prebuilt binaries via shell script

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/hamish-mackie/sloop/releases/download/v0.2.1/sloop-installer.sh | sh

Install prebuilt binaries via Homebrew

brew install sloop

Download sloop 0.2.1

File Platform Checksum
sloop-aarch64-apple-darwin.tar.gz Apple Silicon macOS checksum
sloop-x86_64-apple-darwin.tar.gz Intel macOS checksum
sloop-aarch64-unknown-linux-musl.tar.gz ARM64 MUSL Linux checksum
sloop-x86_64-unknown-linux-musl.tar.gz x64 MUSL Linux checksum

Verifying GitHub Artifact Attestations

The artifacts in this release have attestations generated with GitHub Artifact Attestations. These can be verified by using the GitHub CLI:

gh attestation verify <file-path of downloaded artifact> --repo hamish-mackie/sloop

You can also download the attestation from GitHub and verify against that directly:

gh attestation verify <file-path of downloaded artifact> --bundle <file-path of downloaded attestation>