@iceinvein/agent-skills 0.5.1 → 0.7.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 +1 -1
- package/skills/sluice/SKILL.md +31 -15
- package/skills/sluice/references/deep-channel.md +40 -15
- package/skills/sluice/references/meter.md +14 -2
- package/skills/sluice/references/review.md +14 -9
- package/skills/sluice/scripts/run-stats.sh +107 -29
- package/skills/sluice/skill.json +1 -1
package/package.json
CHANGED
package/skills/index.json
CHANGED
|
@@ -283,7 +283,7 @@
|
|
|
283
283
|
"name": "sluice",
|
|
284
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 every dispatched agent cost. Claude Code only; conflicts with the superpowers plugin.",
|
|
285
285
|
"type": "prompt",
|
|
286
|
-
"version": "0.
|
|
286
|
+
"version": "0.4.0"
|
|
287
287
|
},
|
|
288
288
|
{
|
|
289
289
|
"name": "temporal-coupling-detector",
|
package/skills/sluice/SKILL.md
CHANGED
|
@@ -20,10 +20,13 @@ announcement is how your partner redirects you without being asked.
|
|
|
20
20
|
| `main` | Adds an interface, or crosses subsystems | + agree intent, review before merge | "Main channel, new interface. Agreeing the shape first." |
|
|
21
21
|
| `deep` | Several subsystems, or a plan was asked for | + written design and plan | "Deep channel, several subsystems. Design before code." |
|
|
22
22
|
|
|
23
|
+
Two subsystems is `main`; the third is what makes it `deep`.
|
|
24
|
+
|
|
23
25
|
`bypass`, `fast`, and `main` proceed without stopping for approval; only
|
|
24
|
-
`deep` stops
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
`deep` stops: once for design sign-off before code, once for the plan and
|
|
27
|
+
pre-flight together before Task 1. A stop ends your turn. Asking a question
|
|
28
|
+
with a tool is not one, however many options it carried: the answer comes
|
|
29
|
+
back to you and the run never left your hands.
|
|
27
30
|
|
|
28
31
|
Name the channel and the signal that actually routed you there. The strings above
|
|
29
32
|
are examples, not fixed copy, and a channel with a two-part signal should say
|
|
@@ -36,6 +39,9 @@ account for. An integration event, merging, pushing, or opening a PR, triggers
|
|
|
36
39
|
the second. Handing the work back triggers the third, whether or not it ever
|
|
37
40
|
reaches an integration event. The first two fire in every channel, `bypass`
|
|
38
41
|
included; `meter` cannot, because `bypass` announces nothing to measure from.
|
|
42
|
+
A question that turns on how something looks is triggered the same way and in
|
|
43
|
+
any channel: `references/show-or-say.md` decides whether to show it or say it,
|
|
44
|
+
and `bypass` is where it comes up most.
|
|
39
45
|
|
|
40
46
|
## The rules
|
|
41
47
|
|
|
@@ -79,18 +85,23 @@ Design to `docs/specs/YYYY-MM-DD-<topic>.md`, plan to
|
|
|
79
85
|
`docs/plans/YYYY-MM-DD-<topic>.md`, unless the repo has a convention or
|
|
80
86
|
your partner states a preference. Get the design signed off before code.
|
|
81
87
|
|
|
82
|
-
The plan
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
The plan gets a stop of its own, whoever executes it. Dispatched agents each
|
|
89
|
+
see only their own task, so nobody reads it whole; executing it yourself is
|
|
90
|
+
the weaker case rather than the exempt one, because then nobody reads it but
|
|
91
|
+
its author.
|
|
85
92
|
|
|
86
93
|
Order the plan so the tasks that change nothing come first, and mark the one
|
|
87
94
|
task that turns the new behaviour on. Then a late re-baseline, re-blessed
|
|
88
95
|
snapshots, regenerated fixtures, attributes to that one point instead of to
|
|
89
96
|
the branch at large.
|
|
90
97
|
|
|
91
|
-
|
|
92
|
-
whether the work runs in a worktree. Ask
|
|
93
|
-
|
|
98
|
+
Pre-flight rides in the plan's stop: which flagged tasks get a reviewer, and
|
|
99
|
+
whether the work runs in a worktree. Ask them as choices with the counts in
|
|
100
|
+
them, never as a paragraph, then end the turn on the answers rather than
|
|
101
|
+
opening Task 1 with them. A session that dispatches only when asked has not
|
|
102
|
+
ruled dispatch out, it has made this question the place to ask. Genuine
|
|
103
|
+
unavailability is the tool not being there at all, which is a different case
|
|
104
|
+
and a different paragraph. Review that turns out to be missing is only
|
|
94
105
|
actionable while the plan can still change.
|
|
95
106
|
|
|
96
107
|
Read the plan as a graph rather than a list. `Needs` and `Offers` are
|
|
@@ -98,8 +109,8 @@ dependency edges and `Touches` says what cannot overlap, so which tasks may
|
|
|
98
109
|
run at once is derivable rather than guessed. Fan out wherever that graph
|
|
99
110
|
allows; serial is the fallback for where it doesn't, not the default.
|
|
100
111
|
|
|
101
|
-
Then read `references/deep-channel.md` for the plan format, that
|
|
102
|
-
the dispatch rules, and when a task actually needs a reviewer. Three that
|
|
112
|
+
Then read `references/deep-channel.md` for the plan format, that stop, the run
|
|
113
|
+
record, the dispatch rules, and when a task actually needs a reviewer. Three that
|
|
103
114
|
catch people out: concurrent implementers need a worktree each and the flip
|
|
104
115
|
runs alone, review is tiered rather than automatic, and a `deep` run that
|
|
105
116
|
cannot dispatch has to replace the review tier with something, not quietly
|
|
@@ -107,7 +118,12 @@ ship without one.
|
|
|
107
118
|
|
|
108
119
|
## Conflicts
|
|
109
120
|
|
|
110
|
-
Sluice cannot run alongside the superpowers
|
|
111
|
-
own fixed
|
|
112
|
-
software does, not just code edits, and that
|
|
113
|
-
outright
|
|
121
|
+
Sluice cannot run alongside the superpowers pipeline. Superpowers requires its
|
|
122
|
+
own fixed sequence up front for anything that adds to or changes what the
|
|
123
|
+
software does, not just code edits, and that sequence overrides this router
|
|
124
|
+
outright.
|
|
125
|
+
|
|
126
|
+
The test is whether that pipeline governs the work in front of you, not whether
|
|
127
|
+
a plugin is installed. A repo whose own instructions mandate the sequence rules
|
|
128
|
+
this router out exactly as the plugin does, with the plugin disabled or absent.
|
|
129
|
+
Stand down and say so once, in the same breath you would have named a channel.
|
|
@@ -60,11 +60,20 @@ Split it. A plan with none is not a `deep` plan: nothing in it does anything.
|
|
|
60
60
|
|
|
61
61
|
## Pre-flight
|
|
62
62
|
|
|
63
|
-
Design signed off, plan written, nothing built yet. Before Task 1,
|
|
64
|
-
and settle two things with your partner. Ask them as questions with
|
|
65
|
-
not as a paragraph they have to reply to in prose: what you are after
|
|
66
|
-
decision, and a wall of considerations asks them to extract the decision
|
|
67
|
-
it first.
|
|
63
|
+
Design signed off, plan written, nothing built yet. Before Task 1, hand back
|
|
64
|
+
once and settle two things with your partner. Ask them as questions with
|
|
65
|
+
options, not as a paragraph they have to reply to in prose: what you are after
|
|
66
|
+
is a decision, and a wall of considerations asks them to extract the decision
|
|
67
|
+
from it first.
|
|
68
|
+
|
|
69
|
+
This handback is the plan's sign-off as well, so it ends your turn, and a
|
|
70
|
+
question tool does not end it for you. That tool returns an answer without
|
|
71
|
+
returning control: two options came back, the plan itself did not, and your
|
|
72
|
+
partner reads the summary of it in the same message as Task 1's first edit,
|
|
73
|
+
by which point their only remaining move is to interrupt. Ask the questions,
|
|
74
|
+
then end the turn on the answers and let the next instruction start the
|
|
75
|
+
build. If the answers arrive with that instruction already attached, you have
|
|
76
|
+
your sign-off and Task 1 begins.
|
|
68
77
|
|
|
69
78
|
**Review.** Name the tasks the table below sends to a reviewer, each with the
|
|
70
79
|
trigger that qualified it, and say how many of the rest skip with a ledger
|
|
@@ -98,6 +107,21 @@ review options are. Skipping it is how "review outstanding" first appears in
|
|
|
98
107
|
the closing summary, at the one moment your partner can no longer do anything
|
|
99
108
|
about it.
|
|
100
109
|
|
|
110
|
+
## The run record
|
|
111
|
+
|
|
112
|
+
A `deep` run outlives its own context, so what it learns has to sit on disk
|
|
113
|
+
rather than in the session. Keep one file for the run and write it as you go.
|
|
114
|
+
It holds what a stranger resuming tomorrow would need and you would otherwise
|
|
115
|
+
be recalling: the base each task was dispatched from, each task with its status
|
|
116
|
+
and its commits, the review decisions pre-flight settled and the reason each
|
|
117
|
+
one was settled that way, and any finding belonging to a task other than the
|
|
118
|
+
one that surfaced it.
|
|
119
|
+
|
|
120
|
+
Where it goes follows the repo if the repo has a convention, and
|
|
121
|
+
`docs/plans/YYYY-MM-DD-<topic>-record.md` if it does not. Assembling it at
|
|
122
|
+
handback defeats it: a record written from memory is memory, which is the one
|
|
123
|
+
thing the file exists to replace.
|
|
124
|
+
|
|
101
125
|
## Dispatch rules
|
|
102
126
|
|
|
103
127
|
Read the plan as a graph before you read it as a list. `Needs` and `Offers`
|
|
@@ -112,8 +136,8 @@ Derive the sets at dispatch rather than writing wave numbers into the plan. A
|
|
|
112
136
|
declared schedule is wrong the moment one task lands late or comes back with a
|
|
113
137
|
blocking finding. A derived one just recomputes.
|
|
114
138
|
|
|
115
|
-
- One
|
|
116
|
-
outlives compaction; your memory doesn't.
|
|
139
|
+
- One line per task in the run record, marked in progress then complete as it
|
|
140
|
+
moves. That state outlives compaction; your memory doesn't.
|
|
117
141
|
- Each task goes to a fresh agent with that task's text and nothing else.
|
|
118
142
|
What this session accumulated is yours to hold, not theirs.
|
|
119
143
|
- **Fan out wherever the graph allows.** Work that does not write is always
|
|
@@ -159,10 +183,11 @@ unavailable, where there is nothing to ask.
|
|
|
159
183
|
say so is the routing announcement, where your partner can still act on it,
|
|
160
184
|
not the summary at the end where it reads as an excuse.
|
|
161
185
|
|
|
162
|
-
Three things change. The plan
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
Three things change. The plan stops being a brief for strangers and becomes
|
|
187
|
+
your own worklist, which makes its handback the only outside read it will ever
|
|
188
|
+
get rather than a formality on the way to dispatch. Task isolation is gone, so
|
|
189
|
+
the run record now carries all of the state that outlives compaction and
|
|
190
|
+
matters more, not less. And fresh context is unavailable, which was the entire thing
|
|
166
191
|
review was buying.
|
|
167
192
|
|
|
168
193
|
One thing does not change: the work still owes a review. Reading your own diff
|
|
@@ -215,8 +240,8 @@ a reviewer writes nothing, so it collides with nothing. The final review is
|
|
|
215
240
|
the only one that waits, because it is the only one that needs everything to
|
|
216
241
|
have landed.
|
|
217
242
|
|
|
218
|
-
Record the base in the
|
|
219
|
-
agent's first commit lands. Recovering it afterwards is archaeology, and the
|
|
243
|
+
Record the base against that task in the run record when you dispatch, before
|
|
244
|
+
the agent's first commit lands. Recovering it afterwards is archaeology, and the
|
|
220
245
|
answer you will guess at is `HEAD~1`, which `references/review.md` already
|
|
221
246
|
names as the standing mistake.
|
|
222
247
|
|
|
@@ -250,8 +275,8 @@ Contracts mean tasks are built blind, so a reviewer reading Task 6 will
|
|
|
250
275
|
sometimes be right about Task 2. That finding fits neither destination: Task
|
|
251
276
|
6's agent cannot act on it, and it does not quietly become yours to fix.
|
|
252
277
|
|
|
253
|
-
Record it
|
|
254
|
-
agent as well if that agent is still live. If it invalidates an `Offers` that
|
|
278
|
+
Record it against the earlier task in the run record, and send it to that
|
|
279
|
+
task's agent as well if that agent is still live. If it invalidates an `Offers` that
|
|
255
280
|
later tasks have already built against, it has stopped being a finding and
|
|
256
281
|
become a plan change, which is your partner's call rather than something to
|
|
257
282
|
absorb into the next task's brief.
|
|
@@ -33,12 +33,24 @@ chain and a finding for one whose graph was not, so read it against the plan
|
|
|
33
33
|
rather than on its own. Nine agents at 1.0× on a plan with four independent
|
|
34
34
|
tasks in it is a run that took four times longer than it needed to.
|
|
35
35
|
|
|
36
|
+
An agent dispatched into the background is handed back before it runs, so the
|
|
37
|
+
result the session sees carries no cost at all. The ledger reads that agent's
|
|
38
|
+
own transcript instead, which is why a plan run entirely on dispatched agents
|
|
39
|
+
still prices. Agent rows count output tokens, the same unit the run reports for
|
|
40
|
+
itself, so they can be read against each other and against the run.
|
|
41
|
+
|
|
42
|
+
Where that log has been cleaned up the row reads "cost not reported", the
|
|
43
|
+
totals leave it out, and the agent line carries the count. That is a gap in
|
|
44
|
+
what could be measured rather than a cheap run, and it needs a sentence from
|
|
45
|
+
you: a smaller total must not be allowed to stand for the whole.
|
|
46
|
+
|
|
36
47
|
Read it before you paste it. A row showing an agent that errored, or an agent
|
|
37
48
|
whose token count dwarfs every other row, is a finding about the run and
|
|
38
49
|
belongs in your prose, not left for your partner to spot in a table.
|
|
39
50
|
|
|
40
|
-
Exit 2 means
|
|
41
|
-
|
|
51
|
+
Exit 2 means neither an announcement nor an invocation of this skill was found,
|
|
52
|
+
so there was no run to report. That is a fact about the work, not a failure: do
|
|
53
|
+
not synthesise a ledger to fill the gap.
|
|
42
54
|
|
|
43
55
|
The friction line: "I know roughly what this cost." Roughly is the problem.
|
|
44
56
|
Every number here is already on disk, and the remembered version is reliably
|
|
@@ -47,18 +47,23 @@ reviews, and it spends context the plan still needs.
|
|
|
47
47
|
|
|
48
48
|
## When you cannot dispatch
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
Separate the two cases before you say anything. A session that grants subagents
|
|
51
|
+
only on request has not withheld them: asking is the whole procedure, and a
|
|
52
|
+
claim that you cannot dispatch is false there. A session that withholds them
|
|
53
|
+
outright is the one this section is about. The review is owed either way.
|
|
54
|
+
`deep` has its own treatment in `references/deep-channel.md`, where there is a
|
|
55
|
+
plan to shrink and a tier table to argue from; this is the `main` case, which
|
|
56
|
+
has neither.
|
|
54
57
|
|
|
55
58
|
Say it twice, and only twice.
|
|
56
59
|
|
|
57
|
-
The first time is the routing announcement, in the same breath as the channel
|
|
58
|
-
"Main channel, new interface. I cannot dispatch a reviewer in this
|
|
59
|
-
this merges unreviewed unless you want one."
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
The first time is the routing announcement, in the same breath as the channel.
|
|
61
|
+
Withheld: "Main channel, new interface. I cannot dispatch a reviewer in this
|
|
62
|
+
session, so this merges unreviewed unless you want one." On request: "Main
|
|
63
|
+
channel, new interface. A reviewer is one dispatch away if you want one, and
|
|
64
|
+
without it this merges unreviewed." Either way, that is the moment it is still
|
|
65
|
+
a decision. Your partner can authorise the dispatch, split the change, or
|
|
66
|
+
accept the gap knowingly. The same words at the end are a disclaimer.
|
|
62
67
|
|
|
63
68
|
The second is the integration event, where `references/finish.md` puts the
|
|
64
69
|
three options. Review status belongs beside them, because it is part of what
|
|
@@ -46,7 +46,32 @@ if [ -z "$TRANSCRIPT" ] || [ ! -f "$TRANSCRIPT" ]; then
|
|
|
46
46
|
exit 1
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
# An agent handed back before it ran leaves no cost on its tool result, but it
|
|
50
|
+
# keeps a transcript of its own beside the session. That file is the only place
|
|
51
|
+
# a backgrounded agent's cost is ever written down, so read it rather than
|
|
52
|
+
# reporting the work as free.
|
|
53
|
+
SUBS="$(dirname "$TRANSCRIPT")/$(basename "$TRANSCRIPT" .jsonl)/subagents"
|
|
54
|
+
COSTS='{}'
|
|
55
|
+
if [ -d "$SUBS" ]; then
|
|
56
|
+
COSTS="$(
|
|
57
|
+
for f in "$SUBS"/agent-*.jsonl; do
|
|
58
|
+
[ -e "$f" ] || continue
|
|
59
|
+
id="$(basename "$f" .jsonl)"; id="${id#agent-}"
|
|
60
|
+
jq -s --arg id "$id" '
|
|
61
|
+
def ts: sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601;
|
|
62
|
+
[ .[] | select(.timestamp) ] as $t
|
|
63
|
+
| { ($id): {
|
|
64
|
+
tokens: ([ .[] | .message.usage.output_tokens // 0 ] | add // 0),
|
|
65
|
+
tools: ([ .[] | .message.content[]? | select(.type == "tool_use") ] | length),
|
|
66
|
+
model: ([ .[] | .message.model // empty ] | last // "?"),
|
|
67
|
+
starts: (if ($t | length) > 0 then ($t[0].timestamp | ts) else 0 end),
|
|
68
|
+
ends: (if ($t | length) > 0 then ($t[-1].timestamp | ts) else 0 end) } }' "$f"
|
|
69
|
+
done | jq -s 'add // {}'
|
|
70
|
+
)"
|
|
71
|
+
fi
|
|
72
|
+
[ -n "$COSTS" ] || COSTS='{}'
|
|
73
|
+
|
|
74
|
+
SUMMARY="$(jq -s --argjson costs "$COSTS" '
|
|
50
75
|
# ---- what counts as a real turn ----------------------------------------
|
|
51
76
|
# Transcript stamps carry milliseconds, which fromdateiso8601 will not take.
|
|
52
77
|
def ts: sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601;
|
|
@@ -56,12 +81,27 @@ SUMMARY="$(jq -s '
|
|
|
56
81
|
# opens the message. Anchoring there is what separates it from prose that
|
|
57
82
|
# merely discusses a channel, which a session about sluice is full of.
|
|
58
83
|
def marker: "^[*_#>[:space:]]*(?<c>fast|main|deep)[[:space:]]+channel";
|
|
84
|
+
# Real announcements carry a lead-in the anchor above misses: "Sluice: **deep
|
|
85
|
+
# channel**", "Tier 2 (new contract surface) = **deep channel**". Emphasis is
|
|
86
|
+
# what still separates one from prose naming a channel, and holding it to the
|
|
87
|
+
# opening line keeps a session reviewing sluice from starting a run per quote.
|
|
88
|
+
def emph: "\\*\\*[[:space:]]*(?<c>fast|main|deep)[[:space:]]+channel";
|
|
89
|
+
def head_line: texts | split("\n") | (.[0] // "");
|
|
59
90
|
def announces: (.type == "assistant") and (is_meta | not)
|
|
60
|
-
and (texts | test(marker; "i"));
|
|
61
|
-
def chan: texts |
|
|
91
|
+
and ((texts | test(marker; "i")) or (head_line | test(emph; "i")));
|
|
92
|
+
def chan: (if (texts | test(marker; "i")) then (texts | capture(marker; "i"))
|
|
93
|
+
else (head_line | capture(emph; "i")) end) | .c | ascii_downcase;
|
|
94
|
+
def invokes_sluice: (.type == "assistant") and (is_meta | not) and ([
|
|
95
|
+
.message.content[]? | select(.type == "tool_use" and .name == "Skill")
|
|
96
|
+
| select((.input.skill // "") == "sluice")
|
|
97
|
+
] | length > 0);
|
|
98
|
+
# A call carrying --transcript is reading another run rather than closing
|
|
99
|
+
# this one. Without that exception, a session working on the ledger
|
|
100
|
+
# clips its own run at the last session it tested against.
|
|
62
101
|
def is_stats_call: (.type == "assistant") and ([
|
|
63
102
|
.message.content[]? | select(.type == "tool_use" and .name == "Bash")
|
|
64
103
|
| select((.input.command // "") | test("run-stats\\.sh"))
|
|
104
|
+
| select((.input.command // "") | test("--transcript") | not)
|
|
65
105
|
] | length > 0);
|
|
66
106
|
# Waiting is any turn the partner had to take: a prompt, or an answer to a
|
|
67
107
|
# question you put to them. Leaving the latter out understates the wait on
|
|
@@ -74,7 +114,11 @@ SUMMARY="$(jq -s '
|
|
|
74
114
|
|
|
75
115
|
. as $all
|
|
76
116
|
| [ range(0; $all | length) ] as $ix
|
|
77
|
-
| [ $ix[] | select($all[.] | announces) ] as $
|
|
117
|
+
| [ $ix[] | select($all[.] | announces) ] as $said
|
|
118
|
+
# A run whose announcement never matched is still a run when the skill was
|
|
119
|
+
# invoked by name. Anchoring there beats reporting the work as nothing.
|
|
120
|
+
| [ $ix[] | select($all[.] | invokes_sluice) ] as $called
|
|
121
|
+
| (if ($said | length) > 0 then $said else $called end) as $ann
|
|
78
122
|
| if ($ann | length) == 0 then { empty: true } else
|
|
79
123
|
|
|
80
124
|
# A previous ledger closes the run before it. The call running right now has
|
|
@@ -87,7 +131,7 @@ SUMMARY="$(jq -s '
|
|
|
87
131
|
| [ $all[$from:][] | select(.timestamp) ] as $run
|
|
88
132
|
|
|
89
133
|
# ---- channel, and the trail if it escalated ----------------------------
|
|
90
|
-
| ([ $
|
|
134
|
+
| ([ $said[] | select(. >= $from) | $all[.] | chan ]
|
|
91
135
|
| reduce .[] as $c ([]; if (. | last) == $c then . else . + [$c] end)) as $trail
|
|
92
136
|
|
|
93
137
|
# ---- clocks ------------------------------------------------------------
|
|
@@ -114,20 +158,39 @@ SUMMARY="$(jq -s '
|
|
|
114
158
|
| from_entries) as $labels
|
|
115
159
|
# toolUseResult is whatever the tool returned: object, array or string.
|
|
116
160
|
| [ $run[] | select((.toolUseResult | type) == "object") | select(.toolUseResult.agentId)
|
|
117
|
-
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
161
|
+
| . as $e
|
|
162
|
+
# Inline cost when the agent ran to completion here, its own transcript
|
|
163
|
+
# when it was handed back before it ran, and neither only when the file
|
|
164
|
+
# has been cleaned up. Priced at zero it would understate the run and drag
|
|
165
|
+
# the concurrency factor to a number the ledger has no meaning for.
|
|
166
|
+
| ($costs[$e.toolUseResult.agentId] // null) as $c
|
|
167
|
+
# The log wins where there is one. The two sources count different things,
|
|
168
|
+
# the inline total being the harness accounting and the log being output
|
|
169
|
+
# tokens, and rows drawn from different bases cannot be read against each
|
|
170
|
+
# other. Output tokens is also the unit the run reports for itself.
|
|
171
|
+
| (if $c == null then $e.toolUseResult.totalDurationMs
|
|
172
|
+
else (($c.ends - $c.starts) * 1000) end) as $ms
|
|
173
|
+
| ($c.tokens // $e.toolUseResult.totalTokens) as $tokens
|
|
174
|
+
| { label: ($labels[[ $e.message.content[]? | select(.type == "tool_result") | .tool_use_id ][0]]
|
|
175
|
+
// $e.toolUseResult.commandName // "agent"),
|
|
176
|
+
model: ($c.model // $e.toolUseResult.resolvedModel // "?"),
|
|
177
|
+
status: ($e.toolUseResult.status // "?"),
|
|
178
|
+
measured: (($ms != null) or ($tokens != null)),
|
|
179
|
+
tokens: ($tokens // 0),
|
|
180
|
+
ms: ($ms // 0),
|
|
181
|
+
# The session transcript timestamps when an agent returned, not when
|
|
182
|
+
# it began, so that start is back-derived from its own duration. An
|
|
183
|
+
# agent log of its own carries both ends directly.
|
|
184
|
+
ends: (if $c != null then $c.ends else ($e.timestamp | ts) end),
|
|
185
|
+
starts: (if $c != null then $c.starts
|
|
186
|
+
else (($e.timestamp | ts) - (($ms // 0) / 1000)) end),
|
|
187
|
+
tools: ($c.tools // $e.toolUseResult.totalToolUseCount // 0) } ] as $agents
|
|
188
|
+
|
|
189
|
+
| [ $agents[] | select(.measured) ] as $priced
|
|
127
190
|
|
|
128
191
|
# Union of the agent intervals: sum the merged runs rather than the raw ones,
|
|
129
192
|
# so overlapping agents are counted once against the clock they shared.
|
|
130
|
-
| ([ $
|
|
193
|
+
| ([ $priced[] | { s: .starts, e: .ends } ] | sort_by(.s)
|
|
131
194
|
| reduce .[] as $i ([];
|
|
132
195
|
if (length == 0) or (.[-1].e < $i.s)
|
|
133
196
|
then . + [$i]
|
|
@@ -135,17 +198,18 @@ SUMMARY="$(jq -s '
|
|
|
135
198
|
| map(.e - .s) | add // 0) as $agent_span
|
|
136
199
|
|
|
137
200
|
| { empty: false,
|
|
138
|
-
trail: ($trail | join(" → ")),
|
|
201
|
+
trail: (if ($trail | length) == 0 then "not announced" else ($trail | join(" → ")) end),
|
|
139
202
|
elapsed: $elapsed, waiting: $waiting,
|
|
140
203
|
tool_total: ($tools | length),
|
|
141
204
|
tool_top: ([ $tools | group_by(.)[] | { n: length, name: (.[0] | ascii_downcase | split("__") | last) } ]
|
|
142
205
|
| sort_by(-.n) | .[0:3]),
|
|
143
206
|
out_tok: $out_tok, cache_tok: $cache_tok,
|
|
144
207
|
agents: $agents,
|
|
145
|
-
|
|
146
|
-
|
|
208
|
+
unmeasured: (($agents | length) - ($priced | length)),
|
|
209
|
+
agent_tokens: ([ $priced[].tokens ] | add // 0),
|
|
210
|
+
agent_ms: ([ $priced[].ms ] | add // 0),
|
|
147
211
|
concurrency: (if $agent_span > 0
|
|
148
|
-
then (([ $
|
|
212
|
+
then (([ $priced[].ms ] | add // 0) / 1000) / $agent_span
|
|
149
213
|
else 0 end) }
|
|
150
214
|
end
|
|
151
215
|
' "$TRANSCRIPT" 2>/dev/null)"
|
|
@@ -229,24 +293,38 @@ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
|
229
293
|
fi
|
|
230
294
|
|
|
231
295
|
count=$(g '.agents | length')
|
|
296
|
+
unmeasured=$(g '.unmeasured')
|
|
232
297
|
if [ "$count" -eq 0 ]; then
|
|
233
298
|
printf 'agents none dispatched\n'
|
|
234
299
|
else
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
300
|
+
if [ "$count" -eq "$unmeasured" ]; then
|
|
301
|
+
# Every agent was handed back before it ran, so there is no cost to report
|
|
302
|
+
# and none to invent. Saying so beats a row of zeroes that reads as a total.
|
|
303
|
+
printf 'agents %s dispatched · cost not reported\n' "$count"
|
|
304
|
+
else
|
|
305
|
+
# 1.0× means every agent had the clock to itself. On a plan whose graph had
|
|
306
|
+
# independent tasks in it, that number is the finding.
|
|
307
|
+
printf 'agents %s dispatched · %s tok · %s wall · %s× concurrent' \
|
|
308
|
+
"$count" "$(tok "$(g '.agent_tokens')")" "$(dur "$(( $(g '.agent_ms') / 1000 ))")" \
|
|
309
|
+
"$(printf '%.1f' "$(g '.concurrency')")"
|
|
310
|
+
[ "$unmeasured" -gt 0 ] && printf ' · %s unmeasured' "$unmeasured"
|
|
311
|
+
printf '\n'
|
|
312
|
+
fi
|
|
240
313
|
|
|
241
314
|
# Up to a dozen rows read as the narrative of the plan. Past that the order
|
|
242
315
|
# stops helping, so show what the run actually spent on and say what is cut.
|
|
243
316
|
if [ "$count" -le 12 ]; then rows='.agents[]'; else rows='(.agents | sort_by(-.tokens) | .[0:10][])'; fi
|
|
244
|
-
while IFS=$'\t' read -r label model status tokens ms tools; do
|
|
317
|
+
while IFS=$'\t' read -r label model status tokens ms tools measured; do
|
|
245
318
|
model="${model#claude-}"; model="$(sed 's/-[0-9]\{8\}$//' <<<"$model")"
|
|
246
319
|
[ "$status" = "completed" ] && status="" || status=" ($status)"
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
320
|
+
if [ "$measured" = "true" ]; then
|
|
321
|
+
printf ' %-22.22s %-10s %6s %7s %s tools%s\n' \
|
|
322
|
+
"$label" "$model" "$(tok "$tokens")" "$(dur "$((ms / 1000))")" "$tools" "$status"
|
|
323
|
+
else
|
|
324
|
+
printf ' %-22.22s %-10s %6s %7s %s%s\n' \
|
|
325
|
+
"$label" "$model" "-" "-" "cost not reported" "$status"
|
|
326
|
+
fi
|
|
327
|
+
done < <(g "$rows | [.label, .model, .status, .tokens, .ms, .tools, .measured] | @tsv")
|
|
250
328
|
|
|
251
329
|
if [ "$count" -gt 12 ]; then
|
|
252
330
|
printf ' +%s more · %s tok (dearest 10 shown)\n' \
|
package/skills/sluice/skill.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sluice",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"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 every dispatched agent cost. Claude Code only; conflicts with the superpowers plugin.",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|