@ikon85/agent-workflow-kit 0.34.5 → 0.34.6

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.
@@ -1,14 +1,18 @@
1
1
  ---
2
2
  name: kit-release
3
- description: "Prepare and integrate a verified agent-workflow-kit release, then record separately confirmed publication intent with an annotated version tag and monitor npm/GitHub parity."
3
+ description: "Prepare, integrate and publish a verified agent-workflow-kit release: one confirmed Semver authorizes the annotated version tag, then monitor npm/GitHub parity to released."
4
4
  ---
5
5
 
6
6
  # Kit Release
7
7
 
8
8
  Prepare a release deterministically. This skill owns the shipped-delta decision,
9
- metadata preparation, verification, and the separate post-merge publication
10
- gate. It delegates commit, branch push, PR, merge, and cleanup to wrapup. It
11
- never publishes to a registry or creates a GitHub release directly.
9
+ metadata preparation, verification, and the post-merge publication intent. It
10
+ delegates commit, branch push, PR, merge, and cleanup to wrapup. It never
11
+ publishes to a registry or creates a GitHub release by hand — it records intent
12
+ with the annotated tag and lets the trusted workflow publish.
13
+
14
+ The release has **one** human gate: the confirmed Semver in step 2. Everything
15
+ after it — merge, tag, publish, parity check — is the agent's to carry out.
12
16
 
13
17
  ## Workflow
14
18
 
@@ -33,8 +37,8 @@ never publishes to a registry or creates a GitHub release directly.
33
37
  Do not turn a narrower build-only or single-action request into this
34
38
  authority.
35
39
 
36
- Both routes authorize one prepared target only. Neither authorizes
37
- publication.
40
+ Either route authorizes exactly one target and that authorization carries
41
+ through to its tag and publish. This is the release's single human gate.
38
42
 
39
43
  3. Prepare that authorized exact version:
40
44
 
@@ -52,21 +56,25 @@ never publishes to a registry or creates a GitHub release directly.
52
56
  `scripts/wrapup-land.py` exclusively own commit, push, PR creation, merge,
53
57
  and cleanup. Do not reproduce those operations here.
54
58
 
55
- 5. After merge, report the exact integrated version and commit as
56
- `awaiting-tag`. Merging integrates the prepared release; it cannot start
57
- publication. Creating and pushing the annotated `v<version>` tag requires a
58
- **separate explicit confirmation** to publish that exact version. The
59
- earlier Semver confirmation or AFK preparation mandate authorized metadata
60
- preparation, not publication.
61
-
62
- 6. After that confirmation, verify that the package version on current
63
- `origin/main` is exactly `<version>`. Create a matching annotated
64
- `v<version>` tag on that commit and push only that tag. A lightweight tag,
65
- mismatching version, or commit outside canonical `main` is invalid release
66
- intent. Never infer a tag target, move an existing tag, or tag an unmerged
67
- commit.
68
-
69
- 7. Monitor the tag-triggered `release.yml` workflow and inspect its externally
59
+ 5. Publish. Merging integrates the prepared release; only the annotated tag
60
+ starts publication. Verify that the package version on current `origin/main`
61
+ is exactly `<version>`, then create and push the matching annotated
62
+ `v<version>` tag **the confirmed Semver authorizes the whole release,
63
+ through tag and publish, so do this without asking again**. The target was
64
+ chosen once, at step 2; nothing between there and here produces information
65
+ a second gate could act on. Report the integrated commit as you tag it, not
66
+ as a question.
67
+
68
+ Publication is **irreversible** npm versions cannot be reused, and the
69
+ unpublish window is narrow and breaks consumers. The safety lives in gates
70
+ that already ran, not in a prompt: `release:guard`, `kit:staleness`, the full
71
+ suite and `npm pack --dry-run` before merge, then the workflow's own tag
72
+ identity, package version, main ancestry and artifact checks after it. A
73
+ lightweight tag, a mismatching version, or a commit outside canonical `main`
74
+ is invalid release intent. Never infer a tag target, move an existing tag, or
75
+ tag an unmerged commit.
76
+
77
+ 6. Monitor the tag-triggered `release.yml` workflow and inspect its externally
70
78
  reconstructable state:
71
79
 
72
80
  ```sh
@@ -1,14 +1,18 @@
1
1
  ---
2
2
  name: kit-release
3
- description: "Prepare and integrate a verified agent-workflow-kit release, then record separately confirmed publication intent with an annotated version tag and monitor npm/GitHub parity."
3
+ description: "Prepare, integrate and publish a verified agent-workflow-kit release: one confirmed Semver authorizes the annotated version tag, then monitor npm/GitHub parity to released."
4
4
  ---
5
5
 
6
6
  # Kit Release
7
7
 
8
8
  Prepare a release deterministically. This skill owns the shipped-delta decision,
9
- metadata preparation, verification, and the separate post-merge publication
10
- gate. It delegates commit, branch push, PR, merge, and cleanup to wrapup. It
11
- never publishes to a registry or creates a GitHub release directly.
9
+ metadata preparation, verification, and the post-merge publication intent. It
10
+ delegates commit, branch push, PR, merge, and cleanup to wrapup. It never
11
+ publishes to a registry or creates a GitHub release by hand — it records intent
12
+ with the annotated tag and lets the trusted workflow publish.
13
+
14
+ The release has **one** human gate: the confirmed Semver in step 2. Everything
15
+ after it — merge, tag, publish, parity check — is the agent's to carry out.
12
16
 
13
17
  ## Workflow
14
18
 
@@ -33,8 +37,8 @@ never publishes to a registry or creates a GitHub release directly.
33
37
  Do not turn a narrower build-only or single-action request into this
34
38
  authority.
35
39
 
36
- Both routes authorize one prepared target only. Neither authorizes
37
- publication.
40
+ Either route authorizes exactly one target and that authorization carries
41
+ through to its tag and publish. This is the release's single human gate.
38
42
 
39
43
  3. Prepare that authorized exact version:
40
44
 
@@ -52,21 +56,25 @@ never publishes to a registry or creates a GitHub release directly.
52
56
  `scripts/wrapup-land.py` exclusively own commit, push, PR creation, merge,
53
57
  and cleanup. Do not reproduce those operations here.
54
58
 
55
- 5. After merge, report the exact integrated version and commit as
56
- `awaiting-tag`. Merging integrates the prepared release; it cannot start
57
- publication. Creating and pushing the annotated `v<version>` tag requires a
58
- **separate explicit confirmation** to publish that exact version. The
59
- earlier Semver confirmation or AFK preparation mandate authorized metadata
60
- preparation, not publication.
61
-
62
- 6. After that confirmation, verify that the package version on current
63
- `origin/main` is exactly `<version>`. Create a matching annotated
64
- `v<version>` tag on that commit and push only that tag. A lightweight tag,
65
- mismatching version, or commit outside canonical `main` is invalid release
66
- intent. Never infer a tag target, move an existing tag, or tag an unmerged
67
- commit.
68
-
69
- 7. Monitor the tag-triggered `release.yml` workflow and inspect its externally
59
+ 5. Publish. Merging integrates the prepared release; only the annotated tag
60
+ starts publication. Verify that the package version on current `origin/main`
61
+ is exactly `<version>`, then create and push the matching annotated
62
+ `v<version>` tag **the confirmed Semver authorizes the whole release,
63
+ through tag and publish, so do this without asking again**. The target was
64
+ chosen once, at step 2; nothing between there and here produces information
65
+ a second gate could act on. Report the integrated commit as you tag it, not
66
+ as a question.
67
+
68
+ Publication is **irreversible** npm versions cannot be reused, and the
69
+ unpublish window is narrow and breaks consumers. The safety lives in gates
70
+ that already ran, not in a prompt: `release:guard`, `kit:staleness`, the full
71
+ suite and `npm pack --dry-run` before merge, then the workflow's own tag
72
+ identity, package version, main ancestry and artifact checks after it. A
73
+ lightweight tag, a mismatching version, or a commit outside canonical `main`
74
+ is invalid release intent. Never infer a tag target, move an existing tag, or
75
+ tag an unmerged commit.
76
+
77
+ 6. Monitor the tag-triggered `release.yml` workflow and inspect its externally
70
78
  reconstructable state:
71
79
 
72
80
  ```sh
package/README.md CHANGED
@@ -387,6 +387,11 @@ the old way. Decision record:
387
387
 
388
388
  ## Release notes
389
389
 
390
+ ### 0.34.6
391
+
392
+ - changed: `.agents/skills/kit-release/SKILL.md`
393
+ - changed: `.claude/skills/kit-release/SKILL.md`
394
+
390
395
  ### 0.34.5
391
396
 
392
397
  - changed: `.agents/skills/kit-update/SKILL.md`
@@ -1,5 +1,5 @@
1
1
  {
2
- "kitVersion": "0.34.5",
2
+ "kitVersion": "0.34.6",
3
3
  "files": [
4
4
  {
5
5
  "path": ".agents/skills/ask-matt/SKILL.md",
@@ -367,7 +367,7 @@
367
367
  "ownerSkill": "kit-release",
368
368
  "surface": "codex",
369
369
  "installRole": "maintainer",
370
- "sha256": "f584caa1753ed34de584418a4176015cc3e2382db06efae488bb6d785eab71b7",
370
+ "sha256": "38a3df1f9d4b5573180dc67daba85eb3fd143ae3b60ca6dbfed3297d6a0855cd",
371
371
  "mode": 420,
372
372
  "origin": "kit"
373
373
  },
@@ -1679,7 +1679,7 @@
1679
1679
  "ownerSkill": "kit-release",
1680
1680
  "surface": "claude",
1681
1681
  "installRole": "maintainer",
1682
- "sha256": "f584caa1753ed34de584418a4176015cc3e2382db06efae488bb6d785eab71b7",
1682
+ "sha256": "38a3df1f9d4b5573180dc67daba85eb3fd143ae3b60ca6dbfed3297d6a0855cd",
1683
1683
  "mode": 420,
1684
1684
  "origin": "kit"
1685
1685
  },
@@ -6,6 +6,17 @@ Clarified 2026-07-25 by issue #239: an explicit AFK end-to-end mandate may
6
6
  authorize deterministic reversible release preparation, but never the
7
7
  publication tag itself.
8
8
 
9
+ Amended 2026-07-25 by issue #257: the confirmed Semver authorizes the whole
10
+ release, through tag and publish. The separation of integration and publication
11
+ below is unchanged — merging still cannot publish, and only an annotated tag
12
+ records release intent — but that intent no longer waits for a second human
13
+ confirmation. The maintainer chooses the version once; the agent then merges,
14
+ tags, and monitors to `released`. The second gate had proven worse than no gate:
15
+ it left prepared versions sitting in `awaiting-tag` until someone returned,
16
+ which is how 0.34.2 was skipped and buried under 0.34.3 (#243). Safety stays in
17
+ the gates that run regardless of who is watching — guard, staleness, suite,
18
+ pack, and the workflow's own tag/version/ancestry validation.
19
+
9
20
  The release workflow currently publishes whenever a merge to `main` changes
10
21
  `package.json`. That keeps the canonical branch and npm close together, but it
11
22
  also makes an ordinary merge an irreversible public action whose consequence is
@@ -39,11 +50,13 @@ We decided that integration and publication are separate transitions:
39
50
 
40
51
  ## Consequences
41
52
 
42
- - A prepared version may temporarily exist on `main` in an `awaiting-tag` state.
43
- - An explicit AFK Wave/Program mandate may cover the deterministic reversible
44
- metadata preparation and landing that it names. It never by itself authorizes
45
- creating or pushing the publication tag; that irreversible action requires a
46
- separate explicit confirmation.
53
+ - A prepared version exists on `main` in an `awaiting-tag` state only for as
54
+ long as the agent needs to tag it not until a human returns (amended by
55
+ #257).
56
+ - The authorizing act is the confirmed Semver. An explicit AFK Wave/Program
57
+ mandate that names release preparation carries the same weight, and either
58
+ route reaches through tag and publish for that one target. A narrower
59
+ build-only or single-action request never becomes this authority.
47
60
  - A single-Wave mandate does not authorize the next Program Wave. A later
48
61
  explicit whole-Program mandate does authorize all planned Waves and remains in
49
62
  force across their boundaries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikon85/agent-workflow-kit",
3
- "version": "0.34.5",
3
+ "version": "0.34.6",
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": {
@@ -184,15 +184,21 @@ test('both release skill surfaces name only the owned scoped npm package', async
184
184
  }
185
185
  });
186
186
 
187
- test('an explicit AFK scope can authorize reversible preparation but never publication', async () => {
187
+ // Amended by #257: one gate, at the Semver. The previous contract required a
188
+ // second confirmation before the tag; that gate left prepared versions stranded
189
+ // in `awaiting-tag` and is gone. What must survive is the narrowing rule — a
190
+ // build-only request never becomes release authority.
191
+ test('one confirmed Semver authorizes the release through tag and publish', async () => {
188
192
  const claude = await readFile(join(REPO, '.claude/skills/kit-release/SKILL.md'), 'utf8');
189
193
  const codex = await readFile(join(REPO, '.agents/skills/kit-release/SKILL.md'), 'utf8');
190
- assert.equal(codex, claude);
194
+ assert.equal(codex.split('\n---\n')[1], claude.split('\n---\n')[1]);
191
195
  for (const body of [claude, codex]) {
192
196
  assert.match(body, /explicit AFK end-to-end mandate/i);
193
197
  assert.match(body, /deterministic recommendation/i);
194
- assert.match(body, /reversible metadata preparation/i);
195
- assert.match(body, /annotated `v<version>` tag[\s\S]*separate explicit confirmation/i);
198
+ assert.match(body, /annotated\s+`v<version>` tag/i);
199
+ assert.match(body, /confirmed Semver authorizes[\s\S]*without asking again/i);
200
+ assert.match(body, /narrower build-only or single-action request/i);
201
+ assert.doesNotMatch(body, /separate explicit confirmation/i);
196
202
  }
197
203
  });
198
204
 
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env python3
2
+ """Release-authorization contract (#257).
3
+
4
+ The confirmed Semver authorizes the whole release, through tag and publish.
5
+ One human gate at version choice, not two — the second gate stalled every
6
+ release at `awaiting-tag` until someone returned, which is how 0.34.2 was
7
+ skipped and buried under 0.34.3 (#243).
8
+
9
+ What this pins:
10
+
11
+ - Both `kit-release` surfaces carry the carried-through authorization, and
12
+ neither demands a separate confirmation before tagging.
13
+ - The safety framing survives the change: irreversibility and the pre-tag
14
+ gates stay named, so autonomy never reads as "tag whatever".
15
+ - `CLAUDE.md`, `AGENTS.md` and ADR-0004 agree with the skill.
16
+
17
+ Run: python3 scripts/test_release_authorization_contract.py
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import unittest
22
+ from pathlib import Path
23
+
24
+ ROOT = Path(__file__).resolve().parents[1]
25
+ SURFACES = (".claude/skills/kit-release/SKILL.md", ".agents/skills/kit-release/SKILL.md")
26
+ ADR = "docs/adr/0004-release-intent-is-a-version-tag.md"
27
+ DOCTRINE_FILES = ("CLAUDE.md", "AGENTS.md")
28
+ # Wording that would reinstate the second gate anywhere in the release surface.
29
+ SECOND_GATE = (
30
+ "separate explicit confirmation",
31
+ "separately confirmed publication intent",
32
+ "obtain a separate",
33
+ "After that confirmation",
34
+ )
35
+
36
+
37
+ def read(relative: str) -> str:
38
+ return (ROOT / relative).read_text(encoding="utf-8")
39
+
40
+
41
+ def normalized(relative: str) -> str:
42
+ return " ".join(read(relative).split())
43
+
44
+
45
+ class SkillSurfaceContract(unittest.TestCase):
46
+ def test_both_surfaces_carry_the_authorization_through_to_the_tag(self):
47
+ for surface in SURFACES:
48
+ with self.subTest(surface=surface):
49
+ prose = normalized(surface)
50
+ self.assertIn("confirmed Semver authorizes", prose)
51
+ self.assertIn("tag and publish", prose)
52
+ self.assertIn("without asking again", prose)
53
+
54
+ def test_no_surface_reinstates_a_second_confirmation_gate(self):
55
+ for surface in SURFACES:
56
+ for phrase in SECOND_GATE:
57
+ with self.subTest(surface=surface, phrase=phrase):
58
+ self.assertNotIn(phrase, normalized(surface))
59
+
60
+ def test_autonomy_never_drops_the_safety_framing(self):
61
+ """Tagging stays irreversible and gated — the gates just move earlier."""
62
+ for surface in SURFACES:
63
+ with self.subTest(surface=surface):
64
+ prose = normalized(surface)
65
+ self.assertIn("irreversible", prose)
66
+ self.assertIn("cannot be reused", prose)
67
+ for gate in ("release:guard", "kit:staleness", "npm pack"):
68
+ self.assertIn(gate, prose)
69
+
70
+ def test_the_tag_remains_the_sole_publication_intent(self):
71
+ for surface in SURFACES:
72
+ with self.subTest(surface=surface):
73
+ prose = normalized(surface)
74
+ self.assertIn("Merging integrates", prose)
75
+ self.assertIn("annotated", prose)
76
+
77
+ def test_both_surfaces_stay_mirrored_below_the_frontmatter(self):
78
+ bodies = [read(surface).split("\n---\n", 1)[1] for surface in SURFACES]
79
+ self.assertEqual(bodies[0], bodies[1])
80
+
81
+
82
+ class ProjectDoctrineContract(unittest.TestCase):
83
+ def test_root_convention_files_agree_with_the_skill(self):
84
+ for name in DOCTRINE_FILES:
85
+ with self.subTest(document=name):
86
+ prose = normalized(name)
87
+ self.assertIn("confirmed Semver authorizes", prose)
88
+ for phrase in SECOND_GATE:
89
+ self.assertNotIn(phrase, prose)
90
+
91
+ def test_the_adr_records_an_amendment_instead_of_a_silent_rewrite(self):
92
+ prose = normalized(ADR)
93
+ self.assertIn("Amended", prose)
94
+ self.assertIn("2026-07-25", prose)
95
+ self.assertIn("confirmed Semver authorizes", prose)
96
+ # The original decision must remain readable, not be overwritten.
97
+ self.assertIn("version tag", prose)
98
+
99
+
100
+ if __name__ == "__main__":
101
+ unittest.main()