@iceinvein/agent-skills 0.23.7 → 0.23.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iceinvein/agent-skills",
3
- "version": "0.23.7",
3
+ "version": "0.23.8",
4
4
  "description": "Install agent skills into AI coding tools",
5
5
  "author": "iceinvein",
6
6
  "license": "MIT",
package/skills/index.json CHANGED
@@ -295,7 +295,7 @@
295
295
  "name": "sluice",
296
296
  "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 nine 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, one status command and a SessionStart hook can answer where the run is (the hook prints a live run at every session start, compaction included), lists every live deep run and routed fast or main session on the machine in one board.sh view (drawn once, watched, or as JSON), 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. Two Stop hooks hold a handback: one refuses a tree that moved since its last recorded check, the other refuses a changed existing test not proven to fail on the session's starting code (or recorded with a reason). Claude Code only; stands down where the superpowers pipeline governs the repo.",
297
297
  "type": "prompt",
298
- "version": "0.26.1"
298
+ "version": "0.27.0"
299
299
  },
300
300
  {
301
301
  "name": "temporal-coupling-detector",
@@ -132,6 +132,14 @@ the design's shape turns on a fork only your partner can settle, ask that one
132
132
  question through `AskUserQuestion`, with your recommendation, before the design
133
133
  is written. `references/deep-channel.md` has the test for what counts.
134
134
 
135
+ The design carries a `## Trace` section before it goes up for sign-off: the
136
+ request's own example, quoted, walked through the data as it stands, with what
137
+ each reused function requires and writes read from the code. Per-task reviews
138
+ never run that example and the hunt runs it only once every task is built, so
139
+ a design checked only against the shape of the code is wrong for a whole plan
140
+ before anything catches it.
141
+ `references/deep-channel.md` has what the section holds.
142
+
135
143
  Take the design stop through the harness's plan mode where there is one. Its
136
144
  gate is enforced rather than requested and it holds edits shut while it is open,
137
145
  so nothing gets built against a design nobody signed. It carries the first stop
@@ -1,6 +1,6 @@
1
1
  # sluice evals
2
2
 
3
- Twenty-one cases for `claude plugin eval`. Fourteen pin the routing decision: which
3
+ Twenty-two cases for `claude plugin eval`. Fifteen pin the routing decision: which
4
4
  channel the run names, and whether the behaviour that channel owes actually
5
5
  happened. Seven pin what a deep run does after pre-flight, where the question is
6
6
  no longer which channel but whether the run keeps going.
@@ -12,6 +12,7 @@ no longer which channel but whether the run keeps going.
12
12
  | `main-new-interface` | Adds a port the repo does not have | Main channel; shape stated with a recommendation before building |
13
13
  | `deep-plan-across-subsystems` | A plan asked for, three subsystems | Deep channel; design written to `docs/specs/`; stops before code |
14
14
  | `deep-plan-asks-the-fork` | The same plan with nothing saying where the counters can live | One question with a recommendation before any design; no spec yet |
15
+ | `deep-plan-traces-the-example` | A ticket whose own example the obvious design fails: the lookup it says to reuse matches accepted slides, and the smoke deck has none | A `## Trace` section in the spec that walks the example through the smoke deck, a lookup designed around what it found, and no write under `src/` or `tests/` |
15
16
  | `explicit-instruction-collapses-to-fast` | Main-shaped work plus "just do it" | Collapses to fast; no design, no proposal |
16
17
  | `superpowers-conflict-stands-down` | Repo mandates the superpowers sequence | Stands down once, names no channel |
17
18
  | `announcement-reaches-the-ledger` | A flag that a surface test turns into a new export | `status.sh route main` before any write under `src/` and before any fast or deep route |
@@ -36,7 +37,7 @@ Execution, where the run is already past both stops:
36
37
 
37
38
  ## Running
38
39
 
39
- Twenty cases scaffold a small Node repo and then change it, so they need the
40
+ Twenty-one cases scaffold a small Node repo and then change it, so they need the
40
41
  scaffold flag and a tool grant. Pin the model, because the eval child does not
41
42
  inherit it, and pin the judge, because `--model` does not reach it and the
42
43
  `llm` graders otherwise run on Haiku. From the repo root:
@@ -0,0 +1,4 @@
1
+ schema_version: "1.1"
2
+ name: deep-plan-traces-the-example
3
+ context:
4
+ scaffold_script: fixture.sh
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env bash
2
+ # A deck app where the ticket's own example fails the obvious design. The deck
3
+ # store looks slides up by the title of their accepted version, and only the
4
+ # canvas ever accepts one, so the smoke deck, built in chat, has no accepted
5
+ # slides and the lookup the ticket says to reuse finds nothing. Nothing in the
6
+ # code is wrong; the trap is in designing from which functions exist instead of
7
+ # walking the example through the data. The README fixes where the design goes, so the graders can read it,
8
+ # what an unaccepted slide is called, and what writes slide text, because
9
+ # without them each is a fork the run rightly asks before writing any design.
10
+ set -euo pipefail
11
+
12
+ mkdir -p src/chat src/deck src/canvas data/decks tests docs/specs
13
+
14
+ cat > package.json <<'JSON'
15
+ {
16
+ "name": "decks",
17
+ "version": "0.9.0",
18
+ "type": "module",
19
+ "scripts": {
20
+ "test": "node --test \"tests/*.test.js\""
21
+ }
22
+ }
23
+ JSON
24
+
25
+ cat > src/deck/store.js <<'JS'
26
+ import { readFileSync, writeFileSync } from "node:fs";
27
+
28
+ const path = (id) => new URL(`../../data/decks/${id}.json`, import.meta.url);
29
+
30
+ export function loadDeck(id) {
31
+ return JSON.parse(readFileSync(path(id), "utf8"));
32
+ }
33
+
34
+ export function saveDeck(deck) {
35
+ writeFileSync(path(deck.id), JSON.stringify(deck, null, 2) + "\n");
36
+ }
37
+
38
+ // A slide's title is the title of the version the user accepted on the canvas.
39
+ export function findSlideByTitle(deck, title) {
40
+ const wanted = title.trim().toLowerCase();
41
+ return deck.slides.find((slide) => {
42
+ const accepted = slide.versions[slide.accepted];
43
+ return accepted !== undefined && accepted.title.toLowerCase() === wanted;
44
+ });
45
+ }
46
+ JS
47
+
48
+ cat > src/deck/redraft.js <<'JS'
49
+ // Appends a new version; the canvas decides whether the user accepts it.
50
+ export function redraftSlide(slide, draft) {
51
+ slide.versions.push({ title: draft.title, body: draft.body });
52
+ return slide.versions.length - 1;
53
+ }
54
+ JS
55
+
56
+ cat > src/deck/draft.js <<'JS'
57
+ // Slide text comes from the model; callers pass the completion so tests can stub it.
58
+ export async function draftSlide(version, instruction, complete) {
59
+ const text = await complete(
60
+ `Rewrite this slide. ${instruction}\nTitle: ${version.title}\nBody: ${version.body}`,
61
+ );
62
+ const [title, ...body] = text.trim().split("\n");
63
+ return { title: title.replace(/^Title:\s*/, ""), body: body.join("\n").replace(/^Body:\s*/, "") };
64
+ }
65
+ JS
66
+
67
+ cat > src/canvas/accept.js <<'JS'
68
+ export function accept(slide, versionIndex) {
69
+ if (slide.versions[versionIndex] === undefined) {
70
+ throw new Error(`no version ${versionIndex} on slide ${slide.id}`);
71
+ }
72
+ slide.accepted = versionIndex;
73
+ }
74
+ JS
75
+
76
+ cat > src/chat/build-deck.js <<'JS'
77
+ export function buildDeck(id, outline) {
78
+ return {
79
+ id,
80
+ slides: outline.map((item, index) => ({
81
+ id: `s${index + 1}`,
82
+ accepted: null,
83
+ versions: [{ title: item.title, body: item.body }],
84
+ })),
85
+ };
86
+ }
87
+ JS
88
+
89
+ cat > src/chat/router.js <<'JS'
90
+ export function route(message) {
91
+ if (/^(prepare|build|make)\b.*\bslides?\b/i.test(message)) {
92
+ return { intent: "build-deck" };
93
+ }
94
+ return { intent: "chat" };
95
+ }
96
+ JS
97
+
98
+ cat > data/decks/smoke.json <<'JSON'
99
+ {
100
+ "id": "smoke",
101
+ "slides": [
102
+ {
103
+ "id": "s1",
104
+ "accepted": null,
105
+ "versions": [{ "title": "Why a pilot", "body": "Three sites asked for it." }]
106
+ },
107
+ {
108
+ "id": "s2",
109
+ "accepted": null,
110
+ "versions": [{ "title": "Pilot Stages", "body": "Recruit, run for six weeks, review." }]
111
+ },
112
+ {
113
+ "id": "s3",
114
+ "accepted": null,
115
+ "versions": [{ "title": "Next steps", "body": "Pick the sites by May." }]
116
+ }
117
+ ]
118
+ }
119
+ JSON
120
+
121
+ cat > tests/store.test.js <<'JS'
122
+ import assert from "node:assert/strict";
123
+ import { test } from "node:test";
124
+ import { findSlideByTitle } from "../src/deck/store.js";
125
+
126
+ test("a slide is found by the title of its accepted version", () => {
127
+ const deck = { slides: [{ id: "s1", accepted: 0, versions: [{ title: "Pilot Stages" }] }] };
128
+ assert.equal(findSlideByTitle(deck, "pilot stages").id, "s1");
129
+ });
130
+ JS
131
+
132
+ cat > README.md <<'MD'
133
+ # decks
134
+
135
+ Chat builds a deck (`src/chat/build-deck.js`), the canvas lets a user accept a
136
+ slide version (`src/canvas/accept.js`), and the deck store reads and writes
137
+ `data/decks/<id>.json`. Until a user accepts a version, a slide shows, and is
138
+ called by, its latest one. Slide text, for a new deck or a redraft, comes from
139
+ `draftSlide` in `src/deck/draft.js`. `data/decks/smoke.json` is the smoke deck QA runs
140
+ tickets against. `npm test` runs the suite.
141
+
142
+ ## Designs
143
+
144
+ A ticket's design goes in `docs/specs/<ticket>.md`, for example
145
+ `docs/specs/DEK-12.md`, and its plan in `docs/plans/<ticket>.md`.
146
+ MD
147
+ touch docs/specs/.gitkeep
148
+
149
+ git init --quiet
150
+ git add -A
151
+ git -c user.email=fixture@example.com -c user.name=fixture commit --quiet -m "decks 0.9.0"
@@ -0,0 +1,12 @@
1
+ ---
2
+ type: regex
3
+ # The trace carries SKILL.md's own routing table, which names every channel, so
4
+ # `contains` passes whenever the skill loads. Anchor on the two ways the agent
5
+ # routes instead, the same ones run-stats.sh meters: a Bash call that invokes
6
+ # `status.sh route deep` (a quoted mention, as in a grep, does not count), or the
7
+ # words opening an assistant message or following a label such as "Sluice:".
8
+ pattern: '"command":"(?:(?:[^"\\]|\\.)*?(?:[\s/]|\\[nt]))?status\.sh(?:\\"|'')?(?:\s|\\[nt])+route(?:\s|\\[nt])+deep(?:\s|\\[nt]|[;&|]|")|"text":"(?:[^.!?\n"]{0,100}[:=]\s*)?[\s*_#>\\]*deep channel'
9
+ flags: i
10
+ target: trace
11
+ weight: 2
12
+ ---
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: file_exists
3
+ path: 'docs/specs/DEK-41.md'
4
+ weight: 2
5
+ ---
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: tool_used
3
+ # The run plans and stops for sign-off, so no Edit may land under src/ or
4
+ # tests/. Bash is left out of the case's tools, so these two are the only ways
5
+ # code could change.
6
+ tool: Edit
7
+ input_match: '"file_path"\s*:\s*"(?:[^"]*/)?(?:src|tests)/'
8
+ min: 0
9
+ max: 0
10
+ weight: 2
11
+ ---
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: tool_used
3
+ # The run plans and stops for sign-off, so no Write may land under src/ or
4
+ # tests/. Bash is left out of the case's tools, so these two are the only ways
5
+ # code could change.
6
+ tool: Write
7
+ input_match: '"file_path"\s*:\s*"(?:[^"]*/)?(?:src|tests)/'
8
+ min: 0
9
+ max: 0
10
+ weight: 2
11
+ ---
@@ -0,0 +1,5 @@
1
+ ---
2
+ type: tool_used
3
+ tool: Skill
4
+ input_match: '"skill"\s*:\s*"(?:[\w-]+:)?sluice"'
5
+ ---
@@ -0,0 +1,7 @@
1
+ ---
2
+ type: regex
3
+ pattern: '^#{2,3}\s*Trace\b'
4
+ flags: m
5
+ target: { source: file, path: docs/specs/DEK-41.md }
6
+ weight: 2
7
+ ---
@@ -0,0 +1,8 @@
1
+ ---
2
+ type: llm
3
+ ---
4
+
5
+ The agent was asked to plan a ticket that spans the chat router, the deck store and the redraft path.
6
+
7
+ PASS if the final message hands a written design back for sign-off: it says where the design was written and asks for approval, or otherwise makes clear it is waiting before any code is written.
8
+ FAIL if the final message reports implementation work as done, moves straight into building, or presents the design as settled with no sign-off asked for.
@@ -0,0 +1,27 @@
1
+ ---
2
+ type: llm
3
+ focus: { source: file, path: docs/specs/DEK-41.md }
4
+ weight: 3
5
+ ---
6
+
7
+ This is the design for a ticket whose example is "Redraft the Pilot Stages
8
+ slide to lead with the pilot outcome" on the smoke deck. In the repo,
9
+ `findSlideByTitle` matches only on the title of a slide's accepted version,
10
+ only the canvas ever sets `accepted`, and every slide in
11
+ `data/decks/smoke.json` has `"accepted": null`. So the lookup the ticket says
12
+ to reuse finds no slide for the ticket's own example.
13
+
14
+ Judge the section under the design's Trace heading for the walk, and the rest
15
+ of the design only for the lookup it settles on.
16
+
17
+ PASS if the Trace section quotes the ticket's example, walks it through the
18
+ smoke deck's actual data, and records there that its slides have no accepted
19
+ version (so the existing lookup returns nothing), and the design builds the
20
+ slide lookup around that, consistent with the
21
+ README (an unaccepted slide is called by its latest version): for example,
22
+ matching the accepted version's title when there is one and the latest
23
+ version's otherwise.
24
+ FAIL if there is no Trace section, if the accepted-slide finding appears only
25
+ outside it, if the design reuses `findSlideByTitle` or the accepted version as
26
+ it stands, or if the accepted state is mentioned only as a general risk
27
+ without saying what the smoke deck holds.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: deep-plan-traces-the-example
3
+ description: A deep plan whose ticket example contradicts the obvious design. Pins a Trace section in the spec that walks the example through the fixture's real data before sign-off.
4
+ tags: [routing, deep, write]
5
+ max_turns: 25
6
+ timeout_seconds: 900
7
+ allowed_tools: [Read, Glob, Grep, Skill, Write]
8
+ expected_outcome: Announces the deep channel, writes docs/specs/DEK-41.md with a Trace section that runs the ticket's sentence against the smoke deck, finds its slides have no accepted version, designs around that, and stops for sign-off without code.
9
+ ---
10
+
11
+ Plan DEK-41 for us.
12
+
13
+ > Let people revise a single slide from chat. Example, on the smoke deck:
14
+ > "Redraft the Pilot Stages slide to lead with the pilot outcome" should redraft
15
+ > that slide and leave the rest alone. The chat router needs a revise intent;
16
+ > finding the slide and saving the redraft should reuse what the deck store and
17
+ > the redraft path already do.
@@ -31,7 +31,8 @@
31
31
  "origin": "docs/specs/2026-08-07-sluice-design.md",
32
32
  "cases": [
33
33
  "deep-plan-across-subsystems",
34
- "deep-plan-asks-the-fork"
34
+ "deep-plan-asks-the-fork",
35
+ "deep-plan-traces-the-example"
35
36
  ]
36
37
  },
37
38
  {
@@ -63,7 +64,8 @@
63
64
  "origin": "docs/specs/2026-08-07-sluice-design.md",
64
65
  "cases": [
65
66
  "deep-plan-across-subsystems",
66
- "deep-plan-asks-the-fork"
67
+ "deep-plan-asks-the-fork",
68
+ "deep-plan-traces-the-example"
67
69
  ]
68
70
  },
69
71
  {
@@ -74,6 +76,14 @@
74
76
  "deep-plan-asks-the-fork"
75
77
  ]
76
78
  },
79
+ {
80
+ "id": "deep-design-traces-the-example",
81
+ "states": "SKILL.md: Deep channel",
82
+ "origin": "commit:7decf60",
83
+ "cases": [
84
+ "deep-plan-traces-the-example"
85
+ ]
86
+ },
77
87
  {
78
88
  "id": "deep-stops-for-plan-and-pre-flight",
79
89
  "states": "SKILL.md: Deep channel",
@@ -183,6 +183,44 @@ on it, and let the next instruction start the plan. Nothing else about this
183
183
  section changes, because the obligation was never the mode's, only the
184
184
  enforcement was.
185
185
 
186
+ ## The trace
187
+
188
+ A design written from the shape of the code (which functions exist, which slots
189
+ they fill) can be sound on paper and still fail the request's own example,
190
+ and nothing after it notices: per-task reviews read each task against its own
191
+ text, and the hunt runs once every task is done. So walk the request through
192
+ the system as it stands before you draft, and give the design a `## Trace`
193
+ section that records the walk (in the plan file under plan mode, carried into
194
+ the spec on approval):
195
+
196
+ 1. **The example, verbatim.** Quote the sentence, command or scenario the
197
+ request gives. Where it gives none, write the acceptance criterion as one
198
+ concrete case and say that you did.
199
+ 2. **Through the real data.** Follow that case step by step through the rows,
200
+ files or fixtures it would touch, as they exist now rather than as the
201
+ design assumes them: read the record, run the query, open the fixture, and
202
+ cite what each step read. "A deck built in chat has no accepted slides" is
203
+ a fact one read away, and a design keyed on accepted slides is wrong without
204
+ it.
205
+ 3. **What each reused path requires and writes.** For every function the
206
+ design reuses, its preconditions and its side effects, read from the code
207
+ and not from its name. Run the example a second time where the request
208
+ implies a repeat (a redraft of a redraft, an edit after an edit), because
209
+ what the first pass wrote is what the second pass reads.
210
+ 4. **What the walk ruled out.** Each place it contradicted the obvious design
211
+ (the reuse the request suggests, the first shape that came to mind), and
212
+ what the design does instead. An empty list is a result, not a skipped
213
+ step.
214
+
215
+ Walking first is also what puts a fork where **The design stop and plan mode**
216
+ wants it: one the walk turns up only your partner can settle is asked before
217
+ the design is written, and the trace goes into the design with the answer.
218
+
219
+ The trace is what the sign-off is signing: a design without the section is
220
+ incomplete, however good the rest reads. It is not a prototype and not a hunt;
221
+ anything that only shows at runtime (routing, timing, a renderer) stays with
222
+ the hunt after the flip.
223
+
186
224
  ## Pre-flight
187
225
 
188
226
  Design signed off, plan written, nothing built yet. Before Task 1, stop once
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sluice",
3
- "version": "0.26.1",
3
+ "version": "0.27.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 nine 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, one status command and a SessionStart hook can answer where the run is (the hook prints a live run at every session start, compaction included), lists every live deep run and routed fast or main session on the machine in one board.sh view (drawn once, watched, or as JSON), 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. Two Stop hooks hold a handback: one refuses a tree that moved since its last recorded check, the other refuses a changed existing test not proven to fail on the session's starting code (or recorded with a reason). Claude Code only; stands down where the superpowers pipeline governs the repo.",
5
5
  "author": "iceinvein",
6
6
  "type": "prompt",