@iceinvein/agent-skills 0.8.5 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/index.json +2 -2
- package/skills/sluice/SKILL.md +15 -4
- package/skills/sluice/references/deep-channel.md +106 -24
- package/skills/sluice/references/status.md +213 -0
- package/skills/sluice/scripts/plan.sh +524 -0
- package/skills/sluice/scripts/status.sh +549 -0
- package/skills/sluice/skill.json +2 -2
package/package.json
CHANGED
package/skills/index.json
CHANGED
|
@@ -281,9 +281,9 @@
|
|
|
281
281
|
},
|
|
282
282
|
{
|
|
283
283
|
"name": "sluice",
|
|
284
|
-
"description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries seven rules as one-liners in the router and the full treatment in references read only on friction, and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Claude Code only; stands down where the superpowers pipeline governs the repo.",
|
|
284
|
+
"description": "Routes work by change shape into four channels (bypass, fast, main, deep) and applies only the rules each channel needs, so a one-line fix does not pay the cost of a multi-subsystem build. Carries seven rules as one-liners in the router and the full treatment in references read only on friction. Checks the finished plan with plan.sh validate rather than trusting it to memory, seeds the run state from it, keeps a deep run's task breakdown in .sluice/run.json so a statusline segment and one status command can answer where the run is, and closes each run with a ledger read out of the session transcript: elapsed, tools, tokens, and what each dispatched agent cost where the transcript recorded it. Claude Code only; stands down where the superpowers pipeline governs the repo.",
|
|
285
285
|
"type": "prompt",
|
|
286
|
-
"version": "0.
|
|
286
|
+
"version": "0.12.0"
|
|
287
287
|
},
|
|
288
288
|
{
|
|
289
289
|
"name": "temporal-coupling-detector",
|
package/skills/sluice/SKILL.md
CHANGED
|
@@ -90,6 +90,16 @@ Design to `docs/specs/YYYY-MM-DD-<topic>.md`, plan to
|
|
|
90
90
|
`docs/plans/YYYY-MM-DD-<topic>.md`, unless the repo has a convention or
|
|
91
91
|
your partner states a preference. Get the design signed off before code.
|
|
92
92
|
|
|
93
|
+
Take the design stop through the harness's plan mode where there is one. Its
|
|
94
|
+
gate is enforced rather than requested and it holds edits shut while it is open,
|
|
95
|
+
so nothing gets built against a design nobody signed. It carries the first stop
|
|
96
|
+
only; pre-flight still wants answers, and an approval is not one.
|
|
97
|
+
|
|
98
|
+
The run's state goes in `.sluice/run.json`, written a command at a time by
|
|
99
|
+
`scripts/status.sh`. That is what makes the breakdown readable from outside the
|
|
100
|
+
session running it: a statusline segment while it runs, `status.sh show` after a
|
|
101
|
+
compaction, and neither costing your partner a turn to ask. `references/status.md`
|
|
102
|
+
|
|
93
103
|
**Read `references/deep-channel.md` before you write the plan.** It carries the
|
|
94
104
|
plan format, the pre-flight questions, the run record, the dispatch rules and
|
|
95
105
|
the review tiers, and none of those are derivable from what is on this page.
|
|
@@ -141,10 +151,11 @@ this question the place to ask; genuine unavailability is the tool not being
|
|
|
141
151
|
there at all, which `references/deep-channel.md` handles separately. Review that
|
|
142
152
|
turns out to be missing is only actionable while the plan can still change.
|
|
143
153
|
|
|
144
|
-
All three answers go into the run record before Task 1's first
|
|
145
|
-
the reason
|
|
146
|
-
approval: one reply arrives for several
|
|
147
|
-
behind it signed off the plan and nothing
|
|
154
|
+
All three answers go into `run.json` and the run record before Task 1's first
|
|
155
|
+
edit, the answer in the first and the reason in the second. Those rows are what
|
|
156
|
+
discharge pre-flight, not the approval: one reply arrives for several
|
|
157
|
+
obligations, so a "yes" with no rows behind it signed off the plan and nothing
|
|
158
|
+
else.
|
|
148
159
|
|
|
149
160
|
Three from that file that catch people out: concurrent implementers need a
|
|
150
161
|
worktree each and the flip runs alone, review is tiered rather than automatic,
|
|
@@ -46,6 +46,16 @@
|
|
|
46
46
|
the instruction out again in full. "TBD" is another. So is naming a type
|
|
47
47
|
or a function that no task in the plan ever creates.
|
|
48
48
|
|
|
49
|
+
**Run `scripts/plan.sh validate <plan>` on the finished plan, before pre-flight.**
|
|
50
|
+
Most of what this section asks for needs no judgement to check: a `Needs` no
|
|
51
|
+
task `Offers`, a "TBD", a step deferring to a neighbour, a missing `Contract`,
|
|
52
|
+
a plan with no flip or two of them, a `Model` mark on a task the tier table
|
|
53
|
+
sends to tier 3. Those come back as errors with the task number on them. The
|
|
54
|
+
warnings are the judgement calls left to you: a step with no proof, a `Needs`
|
|
55
|
+
satisfied only by a later task, two tasks whose `Touches` overlap. Reading the
|
|
56
|
+
plan yourself catches these on a good day, and the point of a check is the
|
|
57
|
+
other kind of day.
|
|
58
|
+
|
|
49
59
|
```
|
|
50
60
|
# Plan: <topic>
|
|
51
61
|
## Ground Rules
|
|
@@ -72,14 +82,33 @@ Split it. A plan with none is not a `deep` plan: nothing in it does anything.
|
|
|
72
82
|
## The run record
|
|
73
83
|
|
|
74
84
|
A `deep` run outlives its own context, so what it learns has to sit on disk
|
|
75
|
-
rather than in the session.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
rather than in the session. That lands in two files, and which one a thing goes
|
|
86
|
+
in follows from who has to read it.
|
|
87
|
+
|
|
88
|
+
`.sluice/run.json` holds the state that moves: each task with its status, base
|
|
89
|
+
and commit, its tier, its `Model` mark and its `Flips` line, and the answers
|
|
90
|
+
pre-flight settled. `scripts/status.sh` writes and reads it, and
|
|
91
|
+
`references/status.md` carries the commands and the statusline segment that
|
|
92
|
+
makes a run visible without anyone asking. Open it with `init` when you open the
|
|
93
|
+
record, seed the rows with `scripts/plan.sh import <plan>` rather than typing a
|
|
94
|
+
command per task, then flip each task as it moves. It carries the ids, the names,
|
|
95
|
+
the flip, the model marks and the tiers, the last of these floored off `Touches`
|
|
96
|
+
and the contract graph rather than guessed. Import is safe to re-run: a status, a
|
|
97
|
+
review mark or a ratified model already recorded is left alone and a tier is only
|
|
98
|
+
ever raised, so resuming after a compaction cannot rewind the run.
|
|
99
|
+
|
|
100
|
+
The record is the other file, and it holds what a status cannot: the reason
|
|
101
|
+
review went the way it did, the reason a task was downshifted, the reason the
|
|
102
|
+
workspace answer went that way, any finding belonging to a task other than the
|
|
103
|
+
one that surfaced it, and whatever else a stranger resuming tomorrow would need
|
|
104
|
+
and could not derive. **It no longer carries task rows with statuses in them.**
|
|
105
|
+
Status written in both places drifts, and once it has there are two answers and
|
|
106
|
+
nothing to say which is stale.
|
|
107
|
+
|
|
108
|
+
Pre-flight lands in both, which is the one deliberate overlap: `run.json` holds
|
|
109
|
+
the answer, so the file can say whether the stop happened at all, and the record
|
|
110
|
+
holds the reason, so a reader can tell whether it should have gone that way.
|
|
111
|
+
Those rows come first and open the record for the same reason they always did.
|
|
83
112
|
|
|
84
113
|
Where it goes follows the repo if the repo has a convention, and
|
|
85
114
|
`docs/plans/YYYY-MM-DD-<topic>-record.md` if it does not. It belongs to you
|
|
@@ -88,11 +117,42 @@ task's `Touches` names it, and you commit it yourself alongside the plan.
|
|
|
88
117
|
Assembling it at handback defeats it: a record written from memory is memory,
|
|
89
118
|
which is the one thing the file exists to replace.
|
|
90
119
|
|
|
91
|
-
A file only outlives compaction if you go back to it.
|
|
92
|
-
dispatch whenever this session has been
|
|
93
|
-
what you remember, including where the
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
A file only outlives compaction if you go back to it. Run `status.sh show` and
|
|
121
|
+
read the record before the next dispatch whenever this session has been
|
|
122
|
+
summarised, and treat what they say over what you remember, including where the
|
|
123
|
+
two agree. Each task closes by writing its commit into `run.json`, which means
|
|
124
|
+
asking the implementer to report the SHA it committed and passing it to
|
|
125
|
+
`status.sh task <id> --status done --commit <sha>` rather than deriving it later.
|
|
126
|
+
|
|
127
|
+
## The design stop and plan mode
|
|
128
|
+
|
|
129
|
+
The design stop is a stop because a plan written against the wrong design wastes
|
|
130
|
+
a plan's worth of work. Sluice enforced it with a sentence, "a stop ends your
|
|
131
|
+
turn", which is the weakest gate available in a harness that has a real one.
|
|
132
|
+
|
|
133
|
+
Claude Code's plan mode is the real one. `EnterPlanMode` needs your partner's
|
|
134
|
+
consent to enter, `ExitPlanMode` will not proceed without their approval, and
|
|
135
|
+
edits are held shut in between, so the design cannot be quietly built against
|
|
136
|
+
while it is still a draft. Take the design stop through it.
|
|
137
|
+
|
|
138
|
+
What that changes: the design gets drafted in the plan file the harness names,
|
|
139
|
+
and `ExitPlanMode` is the sign-off rather than a paragraph asking for one.
|
|
140
|
+
|
|
141
|
+
What it does not replace is pre-flight. That stop wants three answers, and an
|
|
142
|
+
approval is not an answer to any of them, so it stays where it is, after plan
|
|
143
|
+
mode has exited and the plan is written. One enforced gate does not collapse two
|
|
144
|
+
stops into one; it only makes the first of them hold.
|
|
145
|
+
|
|
146
|
+
**The harness's plan file is not the artifact.** It belongs to the mode and not
|
|
147
|
+
to the run. On approval, write the design to `docs/specs/YYYY-MM-DD-<topic>.md`,
|
|
148
|
+
the plan to `docs/plans/YYYY-MM-DD-<topic>.md`, and open the run record and
|
|
149
|
+
`run.json`. Those are the durable files, the ones a session resuming next week
|
|
150
|
+
reads, and none of them is the one you drafted in.
|
|
151
|
+
|
|
152
|
+
Where plan mode is unavailable, the prose stop is what you have and it is the
|
|
153
|
+
same stop: end the turn on the design and let the next instruction start the
|
|
154
|
+
plan. Nothing else about this section changes, because the obligation was never
|
|
155
|
+
the mode's, only the enforcement was.
|
|
96
156
|
|
|
97
157
|
## Pre-flight
|
|
98
158
|
|
|
@@ -155,9 +215,10 @@ is the declared schedule the dispatch rules reject.
|
|
|
155
215
|
If one of the two has only one live answer, say which and ask the other. A stop
|
|
156
216
|
down to a single question is still a stop.
|
|
157
217
|
|
|
158
|
-
**Write the answers
|
|
159
|
-
|
|
160
|
-
|
|
218
|
+
**Write the answers down before Task 1's first edit.** Both files:
|
|
219
|
+
`status.sh preflight` for the answers, the run record for the reason each one
|
|
220
|
+
went that way. That pair is what discharges pre-flight, rather than the
|
|
221
|
+
approval you got, and the distinction is the whole point: a stop
|
|
161
222
|
that carries the plan and pre-flight together has one reply for two obligations,
|
|
162
223
|
so a bare "yes" satisfies the plan and leaves no trace either way of the
|
|
163
224
|
questions. Rows in a file leave that trace. If Task 1 is about to open and the
|
|
@@ -175,19 +236,32 @@ about it.
|
|
|
175
236
|
Read the plan as a graph before you read it as a list. `Needs` and `Offers`
|
|
176
237
|
are dependency edges, not only blindness insurance: a task is ready when every
|
|
177
238
|
`Needs` it names is offered by a task already done, and any two ready tasks
|
|
178
|
-
with disjoint `Touches` can go at the same time.
|
|
179
|
-
|
|
239
|
+
with disjoint `Touches` can go at the same time.
|
|
240
|
+
|
|
241
|
+
**`scripts/status.sh ready` does that read.** It prints the ready set, names which
|
|
242
|
+
of them share a path and so cannot go together, says which tasks are still waiting
|
|
243
|
+
on a contract and what for, and holds the flip out of every wave. Run it before
|
|
244
|
+
each wave rather than deriving it again by hand, and note that it also checks the
|
|
245
|
+
candidates against whatever is already `active` or in `review`: those hold their
|
|
246
|
+
paths too, and a wave checked only against itself reads as safe while colliding
|
|
247
|
+
with work in flight. A plan run in the order it happened to be written is a plan whose
|
|
180
248
|
graph nobody looked at, and inert-first ordering tends to put the independent
|
|
181
249
|
tasks at the front, so the opportunity is usually real.
|
|
182
250
|
|
|
183
251
|
Derive the sets at dispatch rather than writing wave numbers into the plan. A
|
|
184
252
|
declared schedule is wrong the moment one task lands late or comes back with a
|
|
185
|
-
blocking finding. A derived one just recomputes
|
|
253
|
+
blocking finding. A derived one just recomputes, which is the whole reason `ready`
|
|
254
|
+
reads the run state rather than the plan: it sees what has actually landed.
|
|
186
255
|
|
|
187
|
-
- One
|
|
256
|
+
- One row per task in `run.json`, flipped to `active` and then `done` as it
|
|
188
257
|
moves. That state outlives compaction; your memory doesn't.
|
|
189
258
|
- Each task goes to a fresh agent with that task's text and nothing else.
|
|
190
259
|
What this session accumulated is yours to hold, not theirs.
|
|
260
|
+
- **Label the dispatch `T<n>: <task name>`.** The harness lists running agents
|
|
261
|
+
under whatever label the dispatch gave them, so labelled by task that list
|
|
262
|
+
reads as the plan and labelled anything else it reads as a row of anonymous
|
|
263
|
+
agents. It costs nothing and it is the only place a partner can see which
|
|
264
|
+
task is in flight without asking.
|
|
191
265
|
- **Fan out wherever the graph allows.** Work that does not write is always
|
|
192
266
|
safe and always parallel: investigations, searches and reviewers, one agent
|
|
193
267
|
per question, all in one message so they run at once.
|
|
@@ -246,8 +320,8 @@ Three things change. The plan stops being a brief for strangers and becomes
|
|
|
246
320
|
your own worklist, so its stop is no longer buying alignment with the agents
|
|
247
321
|
who will carry it out, only your partner's read of work you will do yourself.
|
|
248
322
|
Task isolation is gone, so
|
|
249
|
-
the
|
|
250
|
-
|
|
323
|
+
`run.json` and the record now carry all of the state that outlives compaction
|
|
324
|
+
and matter more, not less. And fresh context is unavailable, which was the entire thing
|
|
251
325
|
review was buying.
|
|
252
326
|
|
|
253
327
|
One thing does not change: the work still owes a review. Reading your own diff
|
|
@@ -301,14 +375,22 @@ or four dispatches rather than nine. If most of your plan qualifies for a
|
|
|
301
375
|
dispatch, the tasks are interleaved rather than ordered, and reordering them
|
|
302
376
|
is cheaper than reviewing them.
|
|
303
377
|
|
|
378
|
+
**Mark each review with `status.sh task <id> --reviewed` when it comes back.**
|
|
379
|
+
What that buys is a count of what this table promised and nobody delivered: tasks
|
|
380
|
+
that are done, that qualified for a dispatch, and that carry no mark. `show` and
|
|
381
|
+
the statusline both carry it from the moment it exists, which is the whole point.
|
|
382
|
+
Unmarked, the count sits permanently non-zero and stops being a signal, and
|
|
383
|
+
"review outstanding" goes back to first appearing in the closing summary, at the
|
|
384
|
+
one moment your partner can no longer do anything about it.
|
|
385
|
+
|
|
304
386
|
Reviews are reads, so they are always parallel. Every review a wave earned
|
|
305
387
|
goes out in one message, and they run while the next wave's implementers work:
|
|
306
388
|
a reviewer writes nothing, so it collides with nothing. The final review is
|
|
307
389
|
the only one that waits, because it is the only one that needs everything to
|
|
308
390
|
have landed.
|
|
309
391
|
|
|
310
|
-
Record the base against that task
|
|
311
|
-
the agent's first commit lands. Recovering it afterwards is archaeology, and the
|
|
392
|
+
Record the base against that task with `status.sh task <id> --base <sha>` when
|
|
393
|
+
you dispatch, before the agent's first commit lands. Recovering it afterwards is archaeology, and the
|
|
312
394
|
answer you will guess at is `HEAD~1`, which `references/review.md` already
|
|
313
395
|
names as the standing mistake.
|
|
314
396
|
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Run state
|
|
2
|
+
|
|
3
|
+
The plan says what the tasks are. The run record says why each decision went
|
|
4
|
+
the way it did. Neither answers "where is this right now" to anything but a
|
|
5
|
+
model reading prose, which is why a `deep` run is invisible from outside the
|
|
6
|
+
session that is running it: your partner has to ask, and asking costs a turn
|
|
7
|
+
and gets an answer from memory.
|
|
8
|
+
|
|
9
|
+
`.sluice/run.json` is that answer in a form something else can read. One file
|
|
10
|
+
per tree, holding only what changes as the run moves.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
bash <skill-dir>/scripts/status.sh init --topic <t> --channel deep \
|
|
14
|
+
--plan docs/plans/<date>-<topic>.md --record docs/plans/<date>-<topic>-record.md
|
|
15
|
+
bash <skill-dir>/scripts/status.sh task 3 --name "adapter seam" --tier 1 --model cheap
|
|
16
|
+
bash <skill-dir>/scripts/status.sh task 3 --status active --base 75014c9
|
|
17
|
+
bash <skill-dir>/scripts/status.sh task 3 --status done --commit 2c7f261
|
|
18
|
+
bash <skill-dir>/scripts/status.sh task 3 --reviewed
|
|
19
|
+
bash <skill-dir>/scripts/status.sh preflight --review "tier 3 only" --model "6 of 9 cheap" \
|
|
20
|
+
--workspace "one worktree per implementer"
|
|
21
|
+
bash <skill-dir>/scripts/status.sh show
|
|
22
|
+
bash <skill-dir>/scripts/status.sh ready
|
|
23
|
+
bash <skill-dir>/scripts/status.sh line --full
|
|
24
|
+
bash <skill-dir>/scripts/status.sh close
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`--dir <path>` reads another tree, which is what the statusline uses. Statuses
|
|
28
|
+
are `todo`, `active`, `review`, `done` and `blocked`. A new id needs `--name`;
|
|
29
|
+
after that every call is a bare flip, so keeping it current costs one command
|
|
30
|
+
per transition rather than a paragraph. `close` archives the run under
|
|
31
|
+
`.sluice/archive/` and frees the tree for the next one.
|
|
32
|
+
|
|
33
|
+
A command that cannot finish leaves the state exactly as it found it, so a
|
|
34
|
+
failed `task` never costs you the rows already in the file. Two argument rules
|
|
35
|
+
follow from that being worth guaranteeing: a value beginning with `--` is
|
|
36
|
+
rejected rather than accepted as a value, and a flag with no value at all is
|
|
37
|
+
rejected rather than taking the next flag as one.
|
|
38
|
+
|
|
39
|
+
Gitignore `.sluice/`. It is working state, and everything durable in it lands
|
|
40
|
+
somewhere else anyway: the commits are in git and the reasons are in the record,
|
|
41
|
+
which is the file that does get committed.
|
|
42
|
+
|
|
43
|
+
Open it with `init` when you open the run record, at the same point and for the
|
|
44
|
+
same reason, then seed the rows with `plan.sh import <plan>` rather than a
|
|
45
|
+
command per task. The ids, names, the flip, the `Model` marks and the tiers are
|
|
46
|
+
all fixed the moment the plan is written and are already in the file, so typing
|
|
47
|
+
them again is transcription with a chance of error in it.
|
|
48
|
+
|
|
49
|
+
The tier import writes is a floor read off `Touches`: an `(edit)` means existing
|
|
50
|
+
code changed, no `(test)` means nothing executable covers the task, and `Flips`
|
|
51
|
+
or a `Review` flag is tier 3 outright. Raise one by hand with `--tier` where the
|
|
52
|
+
work is more delicate than its paths suggest; nothing lowers it for you, because
|
|
53
|
+
the tier table takes the highest row a task matches.
|
|
54
|
+
|
|
55
|
+
Re-importing is safe and is the right move after the plan changes. It refreshes
|
|
56
|
+
names, the contract graph and the flip, moving the flip when the plan moved it,
|
|
57
|
+
and it raises a tier without ever lowering one. A status, a review mark or a model
|
|
58
|
+
ratified at pre-flight is left alone, so resuming after a compaction cannot rewind
|
|
59
|
+
the run. The one consequence worth knowing: adding a missing `(test)` to a plan
|
|
60
|
+
will not drop a task from tier 2 back to tier 1, because the tier table takes the
|
|
61
|
+
highest row a task matches and nothing here can tell a correction from a
|
|
62
|
+
regression. Lower it by hand with `--tier` if that is what you mean.
|
|
63
|
+
|
|
64
|
+
## What goes where
|
|
65
|
+
|
|
66
|
+
**`run.json` owns status. The record owns why.** A status written into both
|
|
67
|
+
drifts, and the moment it does there are two answers and no way to tell which
|
|
68
|
+
is stale. So the record stops carrying task rows with statuses in them and
|
|
69
|
+
carries what a status cannot hold: the reason review went the way it did, the
|
|
70
|
+
reason a task was downshifted, a finding that belongs to a task other than the
|
|
71
|
+
one that surfaced it, and what a stranger resuming tomorrow would need and
|
|
72
|
+
could not derive.
|
|
73
|
+
|
|
74
|
+
Pre-flight answers land in both, and that is deliberate rather than an
|
|
75
|
+
exception: `run.json` holds the answer so the file can say whether the stop
|
|
76
|
+
happened, the record holds the reason so a reader can tell whether it should
|
|
77
|
+
have gone that way. Those are different claims.
|
|
78
|
+
|
|
79
|
+
## Reading it back
|
|
80
|
+
|
|
81
|
+
`show` prints the whole run: channel, topic, how many tasks are done, the plan
|
|
82
|
+
and record paths, the pre-flight answers, and a row per task with its base,
|
|
83
|
+
commit, tier and model. Run it after compaction instead of reconstructing the
|
|
84
|
+
run from what you remember, and run it in the message that hands the work back,
|
|
85
|
+
where "four of nine, task five blocked" is a fact your partner can act on.
|
|
86
|
+
|
|
87
|
+
`show --json` is the same state for another reader. `line` is the compact
|
|
88
|
+
one-line form and `line --full` the wide one; both exit 0 in silence on a missing
|
|
89
|
+
run, unreadable state or a missing jq, because their caller is a status bar with
|
|
90
|
+
nowhere to put an error.
|
|
91
|
+
|
|
92
|
+
`line --full` renders three rows: the run and its clock, the bar alone, then the
|
|
93
|
+
detail. The bar gets a row to itself so it never competes with text for width,
|
|
94
|
+
which is what lets a cell be wide enough to read as a block rather than a tick.
|
|
95
|
+
|
|
96
|
+
A group of cells per task, one repeated glyph each: `▰` done, `◈` active, `▨` in
|
|
97
|
+
review, `▮` blocked, `▱` still to do. The glyphs are distinct before they are
|
|
98
|
+
coloured, so the rows survive having their colour stripped. The width is chosen
|
|
99
|
+
from what the whole bar would occupy, gaps included, rather than from the task
|
|
100
|
+
count: keyed off the count alone the schedule was not monotonic, and thirty tasks
|
|
101
|
+
at two cells each ran wider than twelve at three.
|
|
102
|
+
|
|
103
|
+
**A done task still owed a review trails the review glyph**, `▰▰▨` against
|
|
104
|
+
`▰▰▰`. Debt then reads in position rather than only as a count at the end of the
|
|
105
|
+
row, which is the difference between knowing how much there is and knowing where.
|
|
106
|
+
Tier 0 was never owed a dispatch, so it reads as plainly done. On a plan long
|
|
107
|
+
enough to narrow cells to one, there is no trailing cell to give up and the
|
|
108
|
+
positional reading stops: the count in the third row is then the only carrier,
|
|
109
|
+
which is why it is printed whether or not the bar could show the same thing.
|
|
110
|
+
|
|
111
|
+
**The flip draws as a rule, `┃`, before its task.** Everything left of it is inert
|
|
112
|
+
and safe to leave landed; everything right of it is not. That is what the flip
|
|
113
|
+
means, and it is a boundary between tasks rather than a property of one, so a
|
|
114
|
+
name in the header could not say it. `plan.sh validate` rejects a plan with two
|
|
115
|
+
flips and `import` clears a stale one, so the bar is only ever asked to draw the
|
|
116
|
+
single legal case.
|
|
117
|
+
|
|
118
|
+
The third row carries the progress count, whichever task wants attention, and the
|
|
119
|
+
review debt. A blocked task displaces the active one there, being the one of the
|
|
120
|
+
two worth interrupting for, and a `+n` follows when more than one task shares that
|
|
121
|
+
state, since a plan running four wide has four actives by design.
|
|
122
|
+
|
|
123
|
+
Mark a review with `task <id> --reviewed` when a reviewer comes back. What that
|
|
124
|
+
buys is the debt count: a task that is done, that the tier table owed a dispatch,
|
|
125
|
+
and that nobody marked. Tier 0 is excluded, having only ever been owed a stat
|
|
126
|
+
read. Without it "review outstanding" first appears in the closing summary, at
|
|
127
|
+
the one moment your partner can no longer do anything about it, and `show` and
|
|
128
|
+
the statusline both carry it from the moment it exists.
|
|
129
|
+
|
|
130
|
+
## The next wave
|
|
131
|
+
|
|
132
|
+
`ready` answers the one question the other commands do not: not what the state is,
|
|
133
|
+
but what may go now. A task is ready when every symbol it `Needs` is offered by a
|
|
134
|
+
task already done, and two ready tasks are safe together when their `Touches` are
|
|
135
|
+
disjoint.
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
6 ready now · a worktree each
|
|
139
|
+
T1 extract the bundle writer src/cli/adapters/bundle.ts, …
|
|
140
|
+
T4 record what the harness offers skills/sluice/scripts/status.sh, …
|
|
141
|
+
T4 and T5 share skills/sluice/scripts/status.sh, so not together
|
|
142
|
+
|
|
143
|
+
2 waiting on a contract
|
|
144
|
+
T2 cursor and gemini write bundles needs writeBundle
|
|
145
|
+
|
|
146
|
+
the flip runs alone
|
|
147
|
+
T8 sluice installs on four harnesses
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
It reads the graph `plan.sh import` recorded, so a run seeded before that existed
|
|
151
|
+
says so and tells you to re-import rather than reporting everything ready. The
|
|
152
|
+
flip is held out of every wave whatever the graph says, because the invariant it
|
|
153
|
+
establishes is what the tasks after it are checked against.
|
|
154
|
+
|
|
155
|
+
Derive the wave here rather than writing wave numbers into the plan. A declared
|
|
156
|
+
schedule is wrong the moment one task lands late; this recomputes.
|
|
157
|
+
|
|
158
|
+
## Statusline
|
|
159
|
+
|
|
160
|
+
This is the part that makes a run visible without anyone asking. Give it rows of
|
|
161
|
+
its own rather than a segment among the badges: it then costs nothing when no run
|
|
162
|
+
is live and contends with nothing for width when one is, which is what lets the
|
|
163
|
+
bar be wide and the task carry its name rather than only its number.
|
|
164
|
+
|
|
165
|
+
Capture it wherever the statusline command builds its other lines, keyed off the
|
|
166
|
+
state file existing so a session with no run spawns no process at all:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
sluice_line=""
|
|
170
|
+
if [ -n "$cwd" ] && [ -f "$cwd/.sluice/run.json" ]; then
|
|
171
|
+
for sluice_sh in "$cwd/.claude/skills/sluice/scripts/status.sh" \
|
|
172
|
+
"$HOME/.claude/skills/sluice/scripts/status.sh"; do
|
|
173
|
+
[ -f "$sluice_sh" ] || continue
|
|
174
|
+
sluice_line=$(bash "$sluice_sh" line --full --dir "$cwd" 2>/dev/null)
|
|
175
|
+
break
|
|
176
|
+
done
|
|
177
|
+
fi
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
then print it last, after whatever else the command emits:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
if [ -n "$sluice_line" ]; then printf '%s\n' "$sluice_line"; fi
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`if` rather than `[ ... ] &&`: as the last command of a statusline script the
|
|
187
|
+
short form makes it exit 1 on every render with no run live, which is the common
|
|
188
|
+
case. `%s` rather than `%b`: the render already carries real escape bytes, and
|
|
189
|
+
`%b` would reinterpret a backslash inside a task name. `$cwd` is
|
|
190
|
+
`workspace.current_dir` from the JSON the harness sends on stdin. It renders as:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
⧗ deep · sluice-cross-harness ◷ 38m
|
|
194
|
+
▰▰▰ ▰▰▨ ▨▨▨ ◈◈◈ ▱▱▱ ▮▮▮ ▱▱▱ ┃ ▱▱▱ ▱▱▱
|
|
195
|
+
2/9 done · !T6 model tiers rather than model names +1 · ⟲1 unreviewed
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The colour comes out of the script rather than being applied by the caller,
|
|
199
|
+
because the mapping from state to colour belongs next to the state. A caller that
|
|
200
|
+
coloured the line itself would have to re-derive each cell's meaning from its
|
|
201
|
+
glyph, which is the same fact stored twice.
|
|
202
|
+
|
|
203
|
+
A run that is only visible to the session running it is a run your partner
|
|
204
|
+
cannot redirect. That is the same argument the channel announcement makes, and
|
|
205
|
+
the statusline is where it holds for the hour after the announcement scrolled
|
|
206
|
+
away.
|
|
207
|
+
|
|
208
|
+
## Friction
|
|
209
|
+
|
|
210
|
+
"I know which task I'm on." You do, until this session is summarised. The file
|
|
211
|
+
costs one command per transition and is the only thing in the run that survives
|
|
212
|
+
that, and a plan whose progress lives in one context window is a plan nobody
|
|
213
|
+
outside that window can read.
|