@ikon85/agent-workflow-kit 0.31.0 → 0.32.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/.agents/skills/audit-skills/SKILL.md +34 -5
- package/.agents/skills/git-worktree-recover/SKILL.md +31 -10
- package/.agents/skills/orchestrate-wave/SKILL.md +43 -14
- package/.claude/skills/audit-skills/SKILL.md +34 -5
- package/.claude/skills/git-worktree-recover/SKILL.md +31 -10
- package/.claude/skills/orchestrate-wave/SKILL.md +43 -14
- package/README.md +9 -0
- package/agent-workflow-kit.package.json +7 -7
- package/package.json +1 -1
- package/scripts/test_skill_readiness_contract.py +127 -7
|
@@ -23,6 +23,35 @@ skills the other steps rely on drift, and nothing fixes them unless a recipe doe
|
|
|
23
23
|
Not for: rewriting a domain skill's content on demand (that is the skill itself),
|
|
24
24
|
or auditing application code (a code review or a diagnosis does that).
|
|
25
25
|
|
|
26
|
+
## Readiness preflight — first
|
|
27
|
+
|
|
28
|
+
<!-- readiness:optional-preflight:start -->
|
|
29
|
+
Before enumerating skills, launching research subagents, or editing any skill,
|
|
30
|
+
run this once from the project root:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
node scripts/readiness.mjs check --skill audit-skills --json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- `ready`: continue silently with the generic audit and the active
|
|
37
|
+
`projectChecks` block.
|
|
38
|
+
- `degraded`: keep the generic audit active, omit only `projectChecks`, and emit
|
|
39
|
+
exactly one concise summary: `Readiness degraded — inactive block
|
|
40
|
+
projectChecks (auditSkillsLayer: <state>). Run /setup-workflow, configure
|
|
41
|
+
docs/agents/skills/audit-skills.md, then rerun this skill.`
|
|
42
|
+
- `blocked`: stop before continuing and report the non-ready required capability
|
|
43
|
+
plus the exact `/setup-workflow` recovery path.
|
|
44
|
+
- Invalid evidence is always visible in that one summary; never interpret it as
|
|
45
|
+
an opt-out or invent project checks.
|
|
46
|
+
<!-- readiness:optional-preflight:end -->
|
|
47
|
+
|
|
48
|
+
<!-- readiness:block projectChecks -->
|
|
49
|
+
When `projectChecks` is active, read
|
|
50
|
+
`docs/agents/skills/audit-skills.md` and apply its concrete class assignments,
|
|
51
|
+
project-specific guard commands, and drift checks in addition to the generic
|
|
52
|
+
recipe below.
|
|
53
|
+
<!-- readiness:end -->
|
|
54
|
+
|
|
26
55
|
## Standing guards (run without this audit)
|
|
27
56
|
|
|
28
57
|
Two automatic nets catch the most common drift classes before an audit — this
|
|
@@ -31,7 +60,7 @@ recipe complements them, it does not replace them:
|
|
|
31
60
|
1. **A skill-sync test** — for any un-guessable enumeration a skill documents (a
|
|
32
61
|
status→bucket map, a design-token list), a test parses the value out of the
|
|
33
62
|
SKILL.md and asserts equality with the code constant. Drift breaks the build.
|
|
34
|
-
|
|
63
|
+
Run the concrete tests available in the repository.
|
|
35
64
|
2. **The drift-hint hook** (`.claude/hooks/skill-drift-hint.py`) + a per-skill
|
|
36
65
|
`SOURCES.txt`: at SessionStart it flags any skill whose declared source file
|
|
37
66
|
is newer in git than its SKILL.md.
|
|
@@ -79,8 +108,9 @@ plus the `SOURCES.txt` files. Sort every skill into one of three classes:
|
|
|
79
108
|
scripts or hooks with no `SOURCES.txt` and no hook net. No hook warns, so
|
|
80
109
|
re-check them manually each audit.
|
|
81
110
|
|
|
82
|
-
|
|
83
|
-
catches the next new skill that would
|
|
111
|
+
Derive each concrete skill's class from the manifest, its `SOURCES.txt`, and the
|
|
112
|
+
repository surfaces — a completeness gate catches the next new skill that would
|
|
113
|
+
otherwise stay invisible.
|
|
84
114
|
|
|
85
115
|
### 2. Audit in parallel — one subagent per skill
|
|
86
116
|
|
|
@@ -129,8 +159,7 @@ alongside the Claude source), sync the mirror in the **same** change — otherwi
|
|
|
129
159
|
the second surface rots silently. Mirror the body, but preserve each surface's
|
|
130
160
|
own frontmatter: a mirror's `description` may be deliberately condensed, so never
|
|
131
161
|
blind-copy the whole file over it. A `SOURCES.txt` is a plain anchor list and can
|
|
132
|
-
be mirrored verbatim.
|
|
133
|
-
transform.
|
|
162
|
+
be mirrored verbatim. Use the repository's declared surfaces and exact transform.
|
|
134
163
|
|
|
135
164
|
## Done
|
|
136
165
|
|
|
@@ -20,11 +20,36 @@ discipline and its guards) didn't stop it.
|
|
|
20
20
|
|
|
21
21
|
## Precondition
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
This generic recovery remains usable whether or not the project has prevention
|
|
24
|
+
guards or a custom worktree setup command.
|
|
25
|
+
|
|
26
|
+
## Readiness preflight — first
|
|
27
|
+
|
|
28
|
+
<!-- readiness:optional-preflight:start -->
|
|
29
|
+
Before assessing refs or moving a branch, run this once from the project root:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
node scripts/readiness.mjs check --skill git-worktree-recover --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- `ready`: continue silently with generic recovery and the active
|
|
36
|
+
`projectRecovery` block.
|
|
37
|
+
- `degraded`: keep generic reflog recovery active, omit only
|
|
38
|
+
`projectRecovery`, and emit exactly one concise summary: `Readiness degraded
|
|
39
|
+
— inactive block projectRecovery (worktreeRecoveryLayer: <state>). Run
|
|
40
|
+
/setup-workflow, configure docs/agents/skills/git-worktree-recover.md, then
|
|
41
|
+
rerun this skill.`
|
|
42
|
+
- `blocked`: stop before continuing and report the non-ready required capability
|
|
43
|
+
plus the exact `/setup-workflow` recovery path.
|
|
44
|
+
- Invalid evidence is always visible in that one summary; never interpret it as
|
|
45
|
+
an opt-out or invent a project command.
|
|
46
|
+
<!-- readiness:optional-preflight:end -->
|
|
47
|
+
|
|
48
|
+
<!-- readiness:block projectRecovery -->
|
|
49
|
+
When `projectRecovery` is active, read
|
|
50
|
+
`docs/agents/skills/git-worktree-recover.md` and apply its named prevention
|
|
51
|
+
guards and exact worktree setup command around the generic recovery below.
|
|
52
|
+
<!-- readiness:end -->
|
|
28
53
|
|
|
29
54
|
---
|
|
30
55
|
|
|
@@ -124,16 +149,12 @@ it.
|
|
|
124
149
|
|
|
125
150
|
## Phase 5 — Set up a worktree
|
|
126
151
|
|
|
127
|
-
Set the recovered branch up cleanly in its own worktree.
|
|
128
|
-
worktree-setup command, use it (it typically runs `git worktree add`, installs
|
|
129
|
-
deps and copies env files); otherwise:
|
|
152
|
+
Set the recovered branch up cleanly in its own worktree. The generic fallback is:
|
|
130
153
|
|
|
131
154
|
```bash
|
|
132
155
|
git worktree add <path> <recovered-branch>
|
|
133
156
|
```
|
|
134
157
|
|
|
135
|
-
Your project layer names the exact command and what it copies.
|
|
136
|
-
|
|
137
158
|
**Verify after setup:**
|
|
138
159
|
|
|
139
160
|
```bash
|
|
@@ -13,13 +13,46 @@ correctly, AFK. Subagents BUILD; **you** integrate + verify + land.
|
|
|
13
13
|
The anchor, its sub-issues and the locked plan doc contain the verbatim contracts
|
|
14
14
|
you must NOT paraphrase.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## Readiness preflight — first
|
|
17
|
+
|
|
18
|
+
<!-- readiness:optional-preflight:start -->
|
|
19
|
+
Before reading from the issue tracker, claiming a wave, creating worktrees, or
|
|
20
|
+
making any local or remote mutation, run this once from the project root:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
node scripts/readiness.mjs check --skill orchestrate-wave --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- `ready`: continue silently with the required tracker/board context and the
|
|
27
|
+
active `projectRecipe` block.
|
|
28
|
+
- `degraded`: required tracker and managed-board evidence is ready, so keep the
|
|
29
|
+
complete generic orchestration fallback active, omit only `projectRecipe`,
|
|
30
|
+
and emit exactly one concise summary: `Readiness degraded — inactive block
|
|
31
|
+
projectRecipe (orchestrateWaveRecipe: <state>); using the generic
|
|
32
|
+
orchestration fallback. Run /setup-workflow, configure
|
|
33
|
+
docs/agents/skills/orchestrate-wave.md, then rerun this skill.`
|
|
34
|
+
- `blocked`: `STOP` before tracker access, dispatch, claims, worktrees, or other
|
|
35
|
+
mutation. Report `issueTracker=<state>` and `managedBoard=<state>`, then give
|
|
36
|
+
exactly one recovery path: **Run `/setup-workflow`, then rerun
|
|
37
|
+
`/orchestrate-wave`.** Never fall back to bare tracker or board commands.
|
|
38
|
+
- `managedBoard=not-applicable`: `STOP` and report that `/orchestrate-wave` is
|
|
39
|
+
inapplicable without a managed board. This is a terminal project decision,
|
|
40
|
+
not invalid evidence and not a partially active mode.
|
|
41
|
+
- Invalid evidence is always visible and never treated as an opt-out.
|
|
42
|
+
<!-- readiness:optional-preflight:end -->
|
|
43
|
+
|
|
44
|
+
<!-- readiness:block projectRecipe -->
|
|
45
|
+
> **Phase 0 consumes the active project recipe.** Concrete tooling — exact test/verify
|
|
17
46
|
> commands, a DB/tunnel setup, a headless login recipe, brand checks, deploy
|
|
18
47
|
> lockstep — is project-specific and lives in a **project layer** this skill reads
|
|
19
48
|
> at runtime, not in this skeleton. The skeleton names the layer's sections
|
|
20
49
|
> (`§Setup`, `§Builder Commands`, `§Builder Hard Rules`, `§Integration Suites`,
|
|
21
50
|
> `§Verify Recipe`, `§Headless Login`, `§Landing`) and falls back to generic
|
|
22
51
|
> instructions when the layer is absent. See **Phase 0**.
|
|
52
|
+
>
|
|
53
|
+
> When `projectRecipe` is active, read the filled project layer before applying
|
|
54
|
+
> any phase-specific command below.
|
|
55
|
+
<!-- readiness:end -->
|
|
23
56
|
|
|
24
57
|
## Standing rules (all phases)
|
|
25
58
|
|
|
@@ -59,15 +92,11 @@ you must NOT paraphrase.
|
|
|
59
92
|
1. **Read everything**: the anchor body, every sub-issue body (each has a Handoff
|
|
60
93
|
block: scope, blast-radius, live-verify, PR line), and the locked plan /
|
|
61
94
|
plan-review doc in the planning worktree (file-exact).
|
|
62
|
-
2. **
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
treat the layer as **ABSENT** → use the generic fallback in each phase and warn
|
|
68
|
-
**once** that `/setup-workflow` plus project maintenance fill the layer (the
|
|
69
|
-
commands/tunnel/login can't be guessed). Never treat an empty heading as a
|
|
70
|
-
verify recipe.
|
|
95
|
+
2. **Select exact commands or the generic fallback.** If the readiness result
|
|
96
|
+
activated `projectRecipe`, use the loaded filled recipe wherever a phase below
|
|
97
|
+
points at a `§`-section. Otherwise use each phase's generic fallback; the
|
|
98
|
+
preflight's single degraded summary is the only warning. Never guess a project
|
|
99
|
+
command, tunnel, login, or verify recipe.
|
|
71
100
|
3. **Preflight — refuse a wave already in flight, otherwise claim it.** Before
|
|
72
101
|
dispatch, inspect all three same-machine collision signals: **(a)** an existing
|
|
73
102
|
`wave-active/<anchor>` tag; **(b)** any slice branch ahead of the wave's current
|
|
@@ -88,10 +117,10 @@ you must NOT paraphrase.
|
|
|
88
117
|
tunnel or service the live-verify depends on. Absent layer → start whatever your
|
|
89
118
|
live-verify environment requires before Phase 4.
|
|
90
119
|
|
|
91
|
-
**Done when:** anchor + every sub-issue + plan read ·
|
|
92
|
-
(
|
|
93
|
-
clean + this run's local claim planted · wave branch ff'd to
|
|
94
|
-
installed · project setup steps running.
|
|
120
|
+
**Done when:** anchor + every sub-issue + plan read · readiness result consumed
|
|
121
|
+
(active `projectRecipe` → exact recipe; inactive → generic fallback) · collision
|
|
122
|
+
preflight clean + this run's local claim planted · wave branch ff'd to
|
|
123
|
+
`origin/main` + deps installed · project setup steps running.
|
|
95
124
|
|
|
96
125
|
## Phase 1 — Disjointness recon (the load-bearing step)
|
|
97
126
|
|
|
@@ -23,6 +23,35 @@ skills the other steps rely on drift, and nothing fixes them unless a recipe doe
|
|
|
23
23
|
Not for: rewriting a domain skill's content on demand (that is the skill itself),
|
|
24
24
|
or auditing application code (a code review or a diagnosis does that).
|
|
25
25
|
|
|
26
|
+
## Readiness preflight — first
|
|
27
|
+
|
|
28
|
+
<!-- readiness:optional-preflight:start -->
|
|
29
|
+
Before enumerating skills, launching research subagents, or editing any skill,
|
|
30
|
+
run this once from the project root:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
node scripts/readiness.mjs check --skill audit-skills --json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- `ready`: continue silently with the generic audit and the active
|
|
37
|
+
`projectChecks` block.
|
|
38
|
+
- `degraded`: keep the generic audit active, omit only `projectChecks`, and emit
|
|
39
|
+
exactly one concise summary: `Readiness degraded — inactive block
|
|
40
|
+
projectChecks (auditSkillsLayer: <state>). Run /setup-workflow, configure
|
|
41
|
+
docs/agents/skills/audit-skills.md, then rerun this skill.`
|
|
42
|
+
- `blocked`: stop before continuing and report the non-ready required capability
|
|
43
|
+
plus the exact `/setup-workflow` recovery path.
|
|
44
|
+
- Invalid evidence is always visible in that one summary; never interpret it as
|
|
45
|
+
an opt-out or invent project checks.
|
|
46
|
+
<!-- readiness:optional-preflight:end -->
|
|
47
|
+
|
|
48
|
+
<!-- readiness:block projectChecks -->
|
|
49
|
+
When `projectChecks` is active, read
|
|
50
|
+
`docs/agents/skills/audit-skills.md` and apply its concrete class assignments,
|
|
51
|
+
project-specific guard commands, and drift checks in addition to the generic
|
|
52
|
+
recipe below.
|
|
53
|
+
<!-- readiness:end -->
|
|
54
|
+
|
|
26
55
|
## Standing guards (run without this audit)
|
|
27
56
|
|
|
28
57
|
Two automatic nets catch the most common drift classes before an audit — this
|
|
@@ -31,7 +60,7 @@ recipe complements them, it does not replace them:
|
|
|
31
60
|
1. **A skill-sync test** — for any un-guessable enumeration a skill documents (a
|
|
32
61
|
status→bucket map, a design-token list), a test parses the value out of the
|
|
33
62
|
SKILL.md and asserts equality with the code constant. Drift breaks the build.
|
|
34
|
-
|
|
63
|
+
Run the concrete tests available in the repository.
|
|
35
64
|
2. **The drift-hint hook** (`.claude/hooks/skill-drift-hint.py`) + a per-skill
|
|
36
65
|
`SOURCES.txt`: at SessionStart it flags any skill whose declared source file
|
|
37
66
|
is newer in git than its SKILL.md.
|
|
@@ -79,8 +108,9 @@ plus the `SOURCES.txt` files. Sort every skill into one of three classes:
|
|
|
79
108
|
scripts or hooks with no `SOURCES.txt` and no hook net. No hook warns, so
|
|
80
109
|
re-check them manually each audit.
|
|
81
110
|
|
|
82
|
-
|
|
83
|
-
catches the next new skill that would
|
|
111
|
+
Derive each concrete skill's class from the manifest, its `SOURCES.txt`, and the
|
|
112
|
+
repository surfaces — a completeness gate catches the next new skill that would
|
|
113
|
+
otherwise stay invisible.
|
|
84
114
|
|
|
85
115
|
### 2. Audit in parallel — one subagent per skill
|
|
86
116
|
|
|
@@ -129,8 +159,7 @@ alongside the Claude source), sync the mirror in the **same** change — otherwi
|
|
|
129
159
|
the second surface rots silently. Mirror the body, but preserve each surface's
|
|
130
160
|
own frontmatter: a mirror's `description` may be deliberately condensed, so never
|
|
131
161
|
blind-copy the whole file over it. A `SOURCES.txt` is a plain anchor list and can
|
|
132
|
-
be mirrored verbatim.
|
|
133
|
-
transform.
|
|
162
|
+
be mirrored verbatim. Use the repository's declared surfaces and exact transform.
|
|
134
163
|
|
|
135
164
|
## Done
|
|
136
165
|
|
|
@@ -26,11 +26,36 @@ discipline and its guards) didn't stop it.
|
|
|
26
26
|
|
|
27
27
|
## Precondition
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
This generic recovery remains usable whether or not the project has prevention
|
|
30
|
+
guards or a custom worktree setup command.
|
|
31
|
+
|
|
32
|
+
## Readiness preflight — first
|
|
33
|
+
|
|
34
|
+
<!-- readiness:optional-preflight:start -->
|
|
35
|
+
Before assessing refs or moving a branch, run this once from the project root:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
node scripts/readiness.mjs check --skill git-worktree-recover --json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- `ready`: continue silently with generic recovery and the active
|
|
42
|
+
`projectRecovery` block.
|
|
43
|
+
- `degraded`: keep generic reflog recovery active, omit only
|
|
44
|
+
`projectRecovery`, and emit exactly one concise summary: `Readiness degraded
|
|
45
|
+
— inactive block projectRecovery (worktreeRecoveryLayer: <state>). Run
|
|
46
|
+
/setup-workflow, configure docs/agents/skills/git-worktree-recover.md, then
|
|
47
|
+
rerun this skill.`
|
|
48
|
+
- `blocked`: stop before continuing and report the non-ready required capability
|
|
49
|
+
plus the exact `/setup-workflow` recovery path.
|
|
50
|
+
- Invalid evidence is always visible in that one summary; never interpret it as
|
|
51
|
+
an opt-out or invent a project command.
|
|
52
|
+
<!-- readiness:optional-preflight:end -->
|
|
53
|
+
|
|
54
|
+
<!-- readiness:block projectRecovery -->
|
|
55
|
+
When `projectRecovery` is active, read
|
|
56
|
+
`docs/agents/skills/git-worktree-recover.md` and apply its named prevention
|
|
57
|
+
guards and exact worktree setup command around the generic recovery below.
|
|
58
|
+
<!-- readiness:end -->
|
|
34
59
|
|
|
35
60
|
---
|
|
36
61
|
|
|
@@ -130,16 +155,12 @@ it.
|
|
|
130
155
|
|
|
131
156
|
## Phase 5 — Set up a worktree
|
|
132
157
|
|
|
133
|
-
Set the recovered branch up cleanly in its own worktree.
|
|
134
|
-
worktree-setup command, use it (it typically runs `git worktree add`, installs
|
|
135
|
-
deps and copies env files); otherwise:
|
|
158
|
+
Set the recovered branch up cleanly in its own worktree. The generic fallback is:
|
|
136
159
|
|
|
137
160
|
```bash
|
|
138
161
|
git worktree add <path> <recovered-branch>
|
|
139
162
|
```
|
|
140
163
|
|
|
141
|
-
Your project layer names the exact command and what it copies.
|
|
142
|
-
|
|
143
164
|
**Verify after setup:**
|
|
144
165
|
|
|
145
166
|
```bash
|
|
@@ -21,13 +21,46 @@ correctly, AFK. Subagents BUILD; **you** integrate + verify + land.
|
|
|
21
21
|
The anchor, its sub-issues and the locked plan doc contain the verbatim contracts
|
|
22
22
|
you must NOT paraphrase.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
## Readiness preflight — first
|
|
25
|
+
|
|
26
|
+
<!-- readiness:optional-preflight:start -->
|
|
27
|
+
Before reading from the issue tracker, claiming a wave, creating worktrees, or
|
|
28
|
+
making any local or remote mutation, run this once from the project root:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
node scripts/readiness.mjs check --skill orchestrate-wave --json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- `ready`: continue silently with the required tracker/board context and the
|
|
35
|
+
active `projectRecipe` block.
|
|
36
|
+
- `degraded`: required tracker and managed-board evidence is ready, so keep the
|
|
37
|
+
complete generic orchestration fallback active, omit only `projectRecipe`,
|
|
38
|
+
and emit exactly one concise summary: `Readiness degraded — inactive block
|
|
39
|
+
projectRecipe (orchestrateWaveRecipe: <state>); using the generic
|
|
40
|
+
orchestration fallback. Run /setup-workflow, configure
|
|
41
|
+
docs/agents/skills/orchestrate-wave.md, then rerun this skill.`
|
|
42
|
+
- `blocked`: `STOP` before tracker access, dispatch, claims, worktrees, or other
|
|
43
|
+
mutation. Report `issueTracker=<state>` and `managedBoard=<state>`, then give
|
|
44
|
+
exactly one recovery path: **Run `/setup-workflow`, then rerun
|
|
45
|
+
`/orchestrate-wave`.** Never fall back to bare tracker or board commands.
|
|
46
|
+
- `managedBoard=not-applicable`: `STOP` and report that `/orchestrate-wave` is
|
|
47
|
+
inapplicable without a managed board. This is a terminal project decision,
|
|
48
|
+
not invalid evidence and not a partially active mode.
|
|
49
|
+
- Invalid evidence is always visible and never treated as an opt-out.
|
|
50
|
+
<!-- readiness:optional-preflight:end -->
|
|
51
|
+
|
|
52
|
+
<!-- readiness:block projectRecipe -->
|
|
53
|
+
> **Phase 0 consumes the active project recipe.** Concrete tooling — exact test/verify
|
|
25
54
|
> commands, a DB/tunnel setup, a headless login recipe, brand checks, deploy
|
|
26
55
|
> lockstep — is project-specific and lives in a **project layer** this skill reads
|
|
27
56
|
> at runtime, not in this skeleton. The skeleton names the layer's sections
|
|
28
57
|
> (`§Setup`, `§Builder Commands`, `§Builder Hard Rules`, `§Integration Suites`,
|
|
29
58
|
> `§Verify Recipe`, `§Headless Login`, `§Landing`) and falls back to generic
|
|
30
59
|
> instructions when the layer is absent. See **Phase 0**.
|
|
60
|
+
>
|
|
61
|
+
> When `projectRecipe` is active, read the filled project layer before applying
|
|
62
|
+
> any phase-specific command below.
|
|
63
|
+
<!-- readiness:end -->
|
|
31
64
|
|
|
32
65
|
## Standing rules (all phases)
|
|
33
66
|
|
|
@@ -67,15 +100,11 @@ you must NOT paraphrase.
|
|
|
67
100
|
1. **Read everything**: the anchor body, every sub-issue body (each has a Handoff
|
|
68
101
|
block: scope, blast-radius, live-verify, PR line), and the locked plan /
|
|
69
102
|
plan-review doc in the planning worktree (file-exact).
|
|
70
|
-
2. **
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
treat the layer as **ABSENT** → use the generic fallback in each phase and warn
|
|
76
|
-
**once** that `/setup-workflow` plus project maintenance fill the layer (the
|
|
77
|
-
commands/tunnel/login can't be guessed). Never treat an empty heading as a
|
|
78
|
-
verify recipe.
|
|
103
|
+
2. **Select exact commands or the generic fallback.** If the readiness result
|
|
104
|
+
activated `projectRecipe`, use the loaded filled recipe wherever a phase below
|
|
105
|
+
points at a `§`-section. Otherwise use each phase's generic fallback; the
|
|
106
|
+
preflight's single degraded summary is the only warning. Never guess a project
|
|
107
|
+
command, tunnel, login, or verify recipe.
|
|
79
108
|
3. **Preflight — refuse a wave already in flight, otherwise claim it.** Before
|
|
80
109
|
dispatch, inspect all three same-machine collision signals: **(a)** an existing
|
|
81
110
|
`wave-active/<anchor>` tag; **(b)** any slice branch ahead of the wave's current
|
|
@@ -96,10 +125,10 @@ you must NOT paraphrase.
|
|
|
96
125
|
tunnel or service the live-verify depends on. Absent layer → start whatever your
|
|
97
126
|
live-verify environment requires before Phase 4.
|
|
98
127
|
|
|
99
|
-
**Done when:** anchor + every sub-issue + plan read ·
|
|
100
|
-
(
|
|
101
|
-
clean + this run's local claim planted · wave branch ff'd to
|
|
102
|
-
installed · project setup steps running.
|
|
128
|
+
**Done when:** anchor + every sub-issue + plan read · readiness result consumed
|
|
129
|
+
(active `projectRecipe` → exact recipe; inactive → generic fallback) · collision
|
|
130
|
+
preflight clean + this run's local claim planted · wave branch ff'd to
|
|
131
|
+
`origin/main` + deps installed · project setup steps running.
|
|
103
132
|
|
|
104
133
|
## Phase 1 — Disjointness recon (the load-bearing step)
|
|
105
134
|
|
package/README.md
CHANGED
|
@@ -348,6 +348,15 @@ concurrency-safe. Do not run manifest-mutating commands concurrently. Flags:
|
|
|
348
348
|
|
|
349
349
|
## Release notes
|
|
350
350
|
|
|
351
|
+
### 0.32.0
|
|
352
|
+
|
|
353
|
+
- changed: `.agents/skills/audit-skills/SKILL.md`
|
|
354
|
+
- changed: `.agents/skills/git-worktree-recover/SKILL.md`
|
|
355
|
+
- changed: `.agents/skills/orchestrate-wave/SKILL.md`
|
|
356
|
+
- changed: `.claude/skills/audit-skills/SKILL.md`
|
|
357
|
+
- changed: `.claude/skills/git-worktree-recover/SKILL.md`
|
|
358
|
+
- changed: `.claude/skills/orchestrate-wave/SKILL.md`
|
|
359
|
+
|
|
351
360
|
### 0.31.0
|
|
352
361
|
|
|
353
362
|
- changed: `.agents/skills/board-to-waves/SKILL.md`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"kitVersion": "0.
|
|
2
|
+
"kitVersion": "0.32.0",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"path": ".agents/skills/ask-matt/SKILL.md",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"ownerSkill": "audit-skills",
|
|
28
28
|
"surface": "codex",
|
|
29
29
|
"installRole": "consumer",
|
|
30
|
-
"sha256": "
|
|
30
|
+
"sha256": "662c4dec0c03716c468f202f73f52140ceba84e092873e6619692dde6d7ed0f2",
|
|
31
31
|
"mode": 420,
|
|
32
32
|
"origin": "kit"
|
|
33
33
|
},
|
|
@@ -197,7 +197,7 @@
|
|
|
197
197
|
"ownerSkill": "git-worktree-recover",
|
|
198
198
|
"surface": "codex",
|
|
199
199
|
"installRole": "consumer",
|
|
200
|
-
"sha256": "
|
|
200
|
+
"sha256": "1628f47a5b5f71b7596ec070c8f038a3ce98abe007fce1b7f5c21ea40858124d",
|
|
201
201
|
"mode": 420,
|
|
202
202
|
"origin": "kit"
|
|
203
203
|
},
|
|
@@ -417,7 +417,7 @@
|
|
|
417
417
|
"ownerSkill": "orchestrate-wave",
|
|
418
418
|
"surface": "codex",
|
|
419
419
|
"installRole": "consumer",
|
|
420
|
-
"sha256": "
|
|
420
|
+
"sha256": "7a94293b7db49f42497d34e6ae0fe9992ab1c770ae0766557618818d6d671c50",
|
|
421
421
|
"mode": 420,
|
|
422
422
|
"origin": "kit"
|
|
423
423
|
},
|
|
@@ -1189,7 +1189,7 @@
|
|
|
1189
1189
|
"ownerSkill": "audit-skills",
|
|
1190
1190
|
"surface": "claude",
|
|
1191
1191
|
"installRole": "consumer",
|
|
1192
|
-
"sha256": "
|
|
1192
|
+
"sha256": "dce7c13e9b9c2eb6fe9028f69fe2fe2d48ad50546327c9d9c1232191425f1b7c",
|
|
1193
1193
|
"mode": 420,
|
|
1194
1194
|
"origin": "kit"
|
|
1195
1195
|
},
|
|
@@ -1419,7 +1419,7 @@
|
|
|
1419
1419
|
"ownerSkill": "git-worktree-recover",
|
|
1420
1420
|
"surface": "claude",
|
|
1421
1421
|
"installRole": "consumer",
|
|
1422
|
-
"sha256": "
|
|
1422
|
+
"sha256": "3251c8db671286330e48748719e05ee3fdc0555d93d61d7fee3fc0e0d2868e92",
|
|
1423
1423
|
"mode": 420,
|
|
1424
1424
|
"origin": "kit"
|
|
1425
1425
|
},
|
|
@@ -1699,7 +1699,7 @@
|
|
|
1699
1699
|
"ownerSkill": "orchestrate-wave",
|
|
1700
1700
|
"surface": "claude",
|
|
1701
1701
|
"installRole": "consumer",
|
|
1702
|
-
"sha256": "
|
|
1702
|
+
"sha256": "9690ec772a99131c225037dd4bca884e899c133a8e460c36b26a25d6c6c797e1",
|
|
1703
1703
|
"mode": 420,
|
|
1704
1704
|
"origin": "kit"
|
|
1705
1705
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikon85/agent-workflow-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Portable AI-agent workflow skills (plan → execute → land → learn) for Claude Code & Codex — grilling, TDD, diagnosis, two-axis code review, cross-model Codex review, design & domain-modeling, plus a skill router (ask-matt). npx init/update/diff/uninstall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import re
|
|
7
|
+
import subprocess
|
|
7
8
|
import unittest
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
|
|
@@ -12,7 +13,8 @@ MANIFEST_PATH = ROOT / ".claude/skills/skill-manifest.json"
|
|
|
12
13
|
START = re.compile(r"^<!-- readiness:block ([a-z][A-Za-z0-9]*) -->$")
|
|
13
14
|
END = "<!-- readiness:end -->"
|
|
14
15
|
SURFACE = {"claude": ".claude/skills", "codex": ".agents/skills"}
|
|
15
|
-
|
|
16
|
+
FIXTURES = ROOT / "test/fixtures/readiness"
|
|
17
|
+
REQUIRED_V1 = {
|
|
16
18
|
"to-prd": ["issueTracker", "managedBoard"],
|
|
17
19
|
"to-issues": ["issueTracker", "managedBoard", "specCompleteness"],
|
|
18
20
|
"to-waves": ["issueTracker", "managedBoard", "specCompleteness"],
|
|
@@ -23,7 +25,7 @@ REQUIRED = {
|
|
|
23
25
|
"project-release": ["projectReleaseProfile"],
|
|
24
26
|
"security-audit": ["securityAuditRunbook"],
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
OPTIONAL_V1 = {
|
|
27
29
|
"wrapup": {"deployReport": "prodTarget"},
|
|
28
30
|
"orchestrate-wave": {"projectRecipe": "orchestrateWaveRecipe"},
|
|
29
31
|
"spec-self-critique": {"projectEnrichment": "specCritiqueLayer"},
|
|
@@ -32,6 +34,74 @@ OPTIONAL = {
|
|
|
32
34
|
"audit-skills": {"projectChecks": "auditSkillsLayer"},
|
|
33
35
|
"git-worktree-recover": {"projectRecovery": "worktreeRecoveryLayer"},
|
|
34
36
|
}
|
|
37
|
+
COMPAT_UPDATE_SCRIPT = r"""
|
|
38
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
39
|
+
import { join } from 'node:path';
|
|
40
|
+
import { pathToFileURL } from 'node:url';
|
|
41
|
+
const [repo, fixturePath] = process.argv.slice(-2);
|
|
42
|
+
const load = async (path) => import(pathToFileURL(join(repo, path)));
|
|
43
|
+
const { init } = await load('src/commands/init.mjs');
|
|
44
|
+
const { update } = await load('src/commands/update.mjs');
|
|
45
|
+
const { checkSkill } = await load('scripts/readiness.mjs');
|
|
46
|
+
const { makeKit, makeEmptyDir, cleanup } = await load('test/helpers.mjs');
|
|
47
|
+
const { PACKAGE_MANIFEST_NAME, readManifest, writeManifest } = await load('src/lib/manifest.mjs');
|
|
48
|
+
const { sha256 } = await load('src/lib/hash.mjs');
|
|
49
|
+
const readinessPath = '.claude/skills/skill-manifest.json';
|
|
50
|
+
const fixture = JSON.parse(await readFile(fixturePath, 'utf8'));
|
|
51
|
+
const current = JSON.parse(await readFile(join(repo, readinessPath), 'utf8'));
|
|
52
|
+
const previous = structuredClone(current);
|
|
53
|
+
for (const skill of Object.keys(fixture.readinessFixture.skills)) {
|
|
54
|
+
previous.skills[skill].readiness = {};
|
|
55
|
+
}
|
|
56
|
+
const kit = await makeKit({ '.claude/skills/to-prd/SKILL.md': 'fixture\n' });
|
|
57
|
+
const consumer = await makeEmptyDir();
|
|
58
|
+
async function setKitReadiness(manifest) {
|
|
59
|
+
const content = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
60
|
+
const path = join(kit, readinessPath);
|
|
61
|
+
await mkdir(join(kit, '.claude/skills'), { recursive: true });
|
|
62
|
+
await writeFile(path, content);
|
|
63
|
+
const pkg = await readManifest(join(kit, PACKAGE_MANIFEST_NAME));
|
|
64
|
+
const entry = pkg.files.find(({ path: candidate }) => candidate === readinessPath);
|
|
65
|
+
if (entry) entry.sha256 = sha256(content);
|
|
66
|
+
else pkg.files.push({ path: readinessPath, kind: 'doc', sha256: sha256(content), mode: 0o644, origin: 'kit' });
|
|
67
|
+
await writeManifest(join(kit, PACKAGE_MANIFEST_NAME), pkg);
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
await setKitReadiness(previous);
|
|
71
|
+
await init({ kitRoot: kit, consumerRoot: consumer });
|
|
72
|
+
for (const [relative, body] of Object.entries(fixture.readinessFixture.evidence)) {
|
|
73
|
+
const path = join(consumer, relative);
|
|
74
|
+
await mkdir(join(path, '..'), { recursive: true });
|
|
75
|
+
await writeFile(path, body);
|
|
76
|
+
}
|
|
77
|
+
const manifestPath = join(consumer, 'agent-workflow-kit.json');
|
|
78
|
+
const installed = await readManifest(manifestPath);
|
|
79
|
+
await writeManifest(manifestPath, {
|
|
80
|
+
...installed,
|
|
81
|
+
readinessDecisions: fixture.readinessDecisions ?? {},
|
|
82
|
+
readinessFixture: fixture.readinessFixture,
|
|
83
|
+
});
|
|
84
|
+
const before = {};
|
|
85
|
+
for (const skill of Object.keys(fixture.readinessFixture.skills)) {
|
|
86
|
+
before[skill] = await checkSkill({ root: consumer, skill, manifest: previous });
|
|
87
|
+
}
|
|
88
|
+
await setKitReadiness(current);
|
|
89
|
+
const identity = { name: '@ikon85/agent-workflow-kit', version: '0.1.0', tarballIntegrity: 'sha512-fixture', manifestSha256: 'fixture-manifest' };
|
|
90
|
+
const result = await update({
|
|
91
|
+
kitRoot: kit, consumerRoot: consumer,
|
|
92
|
+
releaseIdentities: { installed: { name: identity.name, version: identity.version, manifestSha256: identity.manifestSha256 }, npm: identity, github: identity },
|
|
93
|
+
verify: async () => {},
|
|
94
|
+
});
|
|
95
|
+
const afterManifest = await readManifest(manifestPath);
|
|
96
|
+
const after = {};
|
|
97
|
+
for (const skill of Object.keys(fixture.readinessFixture.skills)) {
|
|
98
|
+
after[skill] = await checkSkill({ root: consumer, skill, manifest: current });
|
|
99
|
+
}
|
|
100
|
+
console.log(JSON.stringify({ before, result, afterManifest, after }));
|
|
101
|
+
} finally {
|
|
102
|
+
await cleanup(kit, consumer);
|
|
103
|
+
}
|
|
104
|
+
"""
|
|
35
105
|
|
|
36
106
|
|
|
37
107
|
def load_manifest() -> dict:
|
|
@@ -100,11 +170,32 @@ class ReadinessContractTests(unittest.TestCase):
|
|
|
100
170
|
blocks = list(declaration.get("optionalBlocks", {}))
|
|
101
171
|
self.assertEqual(len(blocks), len(set(blocks)), skill)
|
|
102
172
|
|
|
103
|
-
def
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
173
|
+
def test_locked_v1_policy_cannot_disappear_from_the_manifest(self) -> None:
|
|
174
|
+
actual_required = {
|
|
175
|
+
skill: entry["readiness"]["required"]
|
|
176
|
+
for skill, entry in self.published.items()
|
|
177
|
+
if entry.get("readiness", {}).get("required")
|
|
178
|
+
}
|
|
179
|
+
actual_optional = {
|
|
180
|
+
skill: entry["readiness"]["optionalBlocks"]
|
|
181
|
+
for skill, entry in self.published.items()
|
|
182
|
+
if entry.get("readiness", {}).get("optionalBlocks")
|
|
183
|
+
}
|
|
184
|
+
self.assertEqual(actual_required, REQUIRED_V1)
|
|
185
|
+
self.assertEqual(actual_optional, OPTIONAL_V1)
|
|
186
|
+
|
|
187
|
+
def test_every_declared_consumer_has_the_standard_preflight(self) -> None:
|
|
188
|
+
consumers = {
|
|
189
|
+
skill: entry for skill, entry in self.published.items()
|
|
190
|
+
if entry.get("readiness")
|
|
191
|
+
}
|
|
192
|
+
self.assertGreater(len(consumers), 0)
|
|
193
|
+
for skill, entry in consumers.items():
|
|
194
|
+
expected = f"node scripts/readiness.mjs check --skill {skill} --json"
|
|
195
|
+
for surface in entry["surfaces"]:
|
|
196
|
+
path = ROOT / SURFACE[surface] / skill / "SKILL.md"
|
|
197
|
+
body = path.read_text(encoding="utf-8")
|
|
198
|
+
self.assertEqual(body.count(expected), 1, f"{surface}:{skill}")
|
|
108
199
|
|
|
109
200
|
def test_markers_are_balanced_declared_and_surface_equal_when_activated(self) -> None:
|
|
110
201
|
for skill, entry in self.published.items():
|
|
@@ -114,6 +205,7 @@ class ReadinessContractTests(unittest.TestCase):
|
|
|
114
205
|
path = ROOT / SURFACE[surface] / skill / "SKILL.md"
|
|
115
206
|
self.assertTrue(path.is_file(), f"missing published surface: {path}")
|
|
116
207
|
sequence = marker_sequence(path.read_text(encoding="utf-8"), declared)
|
|
208
|
+
self.assertEqual(set(sequence), declared, f"undeclared marker coverage: {surface}:{skill}")
|
|
117
209
|
sequences.append((surface, sequence))
|
|
118
210
|
if len(sequences) > 1:
|
|
119
211
|
validate_surface_sequences([sequence for _, sequence in sequences])
|
|
@@ -134,6 +226,34 @@ class ReadinessContractTests(unittest.TestCase):
|
|
|
134
226
|
with self.assertRaises(AssertionError):
|
|
135
227
|
validate_surface_sequences([["projectEnrichment"], []])
|
|
136
228
|
|
|
229
|
+
def test_legacy_and_current_consumers_keep_previously_ready_skill_cores(self) -> None:
|
|
230
|
+
fixtures = sorted(FIXTURES.glob("*/agent-workflow-kit.json"))
|
|
231
|
+
self.assertEqual([path.parent.name for path in fixtures], ["current", "legacy"])
|
|
232
|
+
for fixture_path in fixtures:
|
|
233
|
+
fixture = json.loads(fixture_path.read_text(encoding="utf-8"))
|
|
234
|
+
scenario = fixture["readinessFixture"]
|
|
235
|
+
with self.subTest(fixture=fixture_path.parent.name):
|
|
236
|
+
run = subprocess.run(
|
|
237
|
+
["node", "--input-type=module", "-e", COMPAT_UPDATE_SCRIPT,
|
|
238
|
+
str(ROOT), str(fixture_path)],
|
|
239
|
+
check=True, capture_output=True, text=True,
|
|
240
|
+
)
|
|
241
|
+
proof = json.loads(run.stdout)
|
|
242
|
+
self.assertEqual(proof["result"]["state"], "applied")
|
|
243
|
+
self.assertEqual(proof["result"]["availability"]["newlyBlocked"], [])
|
|
244
|
+
for skill, expected in scenario["skills"].items():
|
|
245
|
+
self.assertEqual(proof["before"][skill]["verdict"], "ready", skill)
|
|
246
|
+
verdict = proof["after"][skill]
|
|
247
|
+
self.assertNotEqual(verdict["verdict"], "blocked", skill)
|
|
248
|
+
self.assertEqual(verdict["verdict"], expected["verdict"], skill)
|
|
249
|
+
self.assertEqual(verdict["inactiveBlocks"], expected["inactiveBlocks"], skill)
|
|
250
|
+
self.assertEqual(
|
|
251
|
+
proof["afterManifest"].get("readinessDecisions", {}),
|
|
252
|
+
scenario["expectedDecisions"],
|
|
253
|
+
"unavailable behavior must not manufacture a decision",
|
|
254
|
+
)
|
|
255
|
+
self.assertEqual(proof["afterManifest"]["readinessFixture"], scenario)
|
|
256
|
+
|
|
137
257
|
|
|
138
258
|
if __name__ == "__main__":
|
|
139
259
|
unittest.main()
|