1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# A flow is the ordered list of stages one run walks. The filename is the
# flow name: .agents/sloop/flows/release.yaml defines the flow `release`,
# and a ticket binds to it with `flow: release` or `sloop post --flow
# release`. Save this file as .agents/sloop/flows/<name>.yaml.
#
# The walk is linear and halts on the first failure: stages after a failed
# one are never requested. Evidence is persisted per stage, so a daemon
# restart resumes at the first stage without a recorded verdict.
#
# Structural rules the parser enforces:
# - The first stage must be an `agent` stage, and it is the only one
# allowed: additional agent stages are rejected.
# - At most one `merge` stage, and it must be last.
# - Stage names must be unique.
# - `exec` stages must define a non-empty `cmd`; `agent` and `merge`
# stages must not define `cmd` at all.
# - `merge` stages must not define `verdict`: the merge result is the
# verdict.
# - `on_fail` is rejected on the `agent` stage.
#
# The top level may be this `stages:` mapping or a bare YAML list of
# stages. Both parse identically.
stages:
# ---- kind: agent -----------------------------------------------------
# Spawns the ticket's agent target in the run worktree with the ticket
# body as its brief. Exactly one, always first.
- name: build
kind: agent
# verdict: commits
# Passes when the process exits 0 *and* Sloop observes at least one
# new commit on the run branch. This is the default for `agent`
# stages and is stated here only to show the policy; an agent that
# exits cleanly without committing leaves the branch for review
# rather than merging an empty change.
verdict: commits
# ---- kind: exec ------------------------------------------------------
# Runs an argv (no shell) in the run worktree. Any number of these, in
# order, between the agent stage and the merge stage.
- name: test
kind: exec
cmd:
# verdict: exit
# Passes when the stage process exits 0. This is the default for
# `exec` and `merge` stages.
verdict: exit
# ---- on_fail: repair and retry -------------------------------------
# When the stage fails, spawn a repair agent in the run worktree, then
# re-run this stage and re-apply its own verdict policy. The repair
# agent never produces the verdict, and never changes the stage's
# command or the flow's ordering. Allowed on `exec` and `merge`
# stages only.
on_fail:
# The prompt handed to the repair agent. Required and non-empty.
agent: "Tests are failing in this worktree. Fix them without weakening assertions, then commit."
# How many repair-then-retry cycles this stage may use per run.
# Optional, defaults to 1, and must be between 1 and 3.
attempts: 2
# Optional overrides for the repair worker only. `target` must name
# an entry under `agent.targets` in config.yaml; all three default
# to the ticket's own snapshotted values.
target: claude
model: haiku
effort: low
- name: lint
kind: exec
cmd:
# verdict: { check: [...] }
# Requires the stage process to exit 0, then runs a second command
# in the worktree and takes its exit code as the verdict. Use it
# when the thing that proves the stage is not the thing that does
# the work. The check command must be non-empty.
verdict:
- name: review
kind: exec
# verdict: reported
# The stage must call `sloop verdict pass|fail --reason <text>`
# exactly once. The first report is final, and a stage that ends
# without one fails with `no verdict reported`. This is the only
# policy that keeps SLOOP_SOCKET and SLOOP_TOKEN in the stage's
# environment, so it is the only way a command can grade itself.
# Under the `exit` default a reviewer that always exits 0 — as
# `claude --print` does — would approve every run.
verdict: reported
# `--allowedTools Bash` lets the reviewer run tests and `sloop
# verdict`; it deliberately omits Write/Edit so the reviewer can read
# and run but not rewrite the work. `--` ends the variadic tool list
# so the prompt stays a positional.
cmd:
- claude
- --print
- --allowedTools
- Bash
- --
- "Read .agents/sloop/prompts/review.md and follow its instructions."
# ---- kind: merge -----------------------------------------------------
# Applies the run branch to the default branch using Sloop's merge
# policy. Optional, at most one, and must be last. A flow without one
# leaves the branch for a human to integrate.
- name: merge
kind: merge
# No `verdict` key is allowed here. A conflicted merge parks the
# ticket in `needs_review` with the branch preserved, unless an
# `on_fail` repair resolves it first: for a merge stage the repair
# agent's job is to integrate the default branch *into* the run
# branch and resolve conflicts there.
on_fail:
agent: "This run branch conflicts with the default branch. Merge the default branch into it, resolve the conflicts, and commit."
attempts: 1
# `kind: build` is still accepted as a deprecated alias for `kind: agent`.
#
# A configured `aftercare.test_cmd` in config.yaml is inserted as an
# implicit `exit` stage named `test` right after the agent stage, so it
# cannot be combined with a flow that already has a stage named `test`.