@ikon85/agent-workflow-kit 0.26.2 → 0.27.1
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/ask-matt/SKILL.md +1 -2
- package/.agents/skills/board-to-waves/SKILL.md +2 -2
- package/.agents/skills/improve-codebase-architecture/SKILL.md +0 -2
- package/.agents/skills/setup-workflow/board-sync.md +11 -0
- package/.claude/skills/ask-matt/SKILL.md +1 -2
- package/.claude/skills/board-to-waves/SKILL.md +2 -2
- package/.claude/skills/improve-codebase-architecture/SKILL.md +0 -2
- package/.claude/skills/setup-pre-commit/SKILL.md +3 -0
- package/.claude/skills/setup-pre-commit/scripts/pre-commit.template.sh +6 -0
- package/.claude/skills/setup-workflow/board-sync.md +11 -0
- package/.claude/skills/skill-manifest.json +0 -9
- package/PROVENANCE.md +5 -4
- package/README.md +39 -17
- package/agent-workflow-kit.package.json +14 -54
- package/docs/agents/board-sync.md +3 -0
- package/docs/workflow.html +259 -0
- package/docs/workflow.png +0 -0
- package/package.json +1 -1
- package/scripts/board-sync.py +18 -13
- package/scripts/board_config.py +7 -0
- package/scripts/release-parity.mjs +34 -0
- package/scripts/release-parity.test.mjs +37 -0
- package/scripts/test_board_sync_wave_title.py +108 -0
- package/scripts/test_skill_precommit_template.py +30 -0
- package/src/cli.mjs +5 -2
- package/src/commands/update.mjs +2 -2
- package/.agents/skills/zoom-out/SKILL.md +0 -7
- package/.agents/skills/zoom-out/THIRD-PARTY-NOTICES.md +0 -29
- package/.claude/skills/zoom-out/SKILL.md +0 -7
- package/.claude/skills/zoom-out/THIRD-PARTY-NOTICES.md +0 -29
|
@@ -90,8 +90,7 @@ An independent second model catches what one model rationalises. Read-only, boun
|
|
|
90
90
|
|
|
91
91
|
Not feature work — upkeep.
|
|
92
92
|
|
|
93
|
-
- **`/improve-codebase-architecture`** — run in spare moments to keep the codebase good for agents. Surfaces **deepening opportunities**; picking one _generates an idea_ for the main flow at `/grill-with-docs`.
|
|
94
|
-
- **`/zoom-out`** — step back from the diff to the structure when a change is fighting the codebase; recon that becomes a planned slice or guides a refactor in place.
|
|
93
|
+
- **`/improve-codebase-architecture`** — run in spare moments to keep the codebase good for agents, or step back from the diff to the structure when a change is fighting the codebase. Surfaces **deepening opportunities**; picking one _generates an idea_ for the main flow at `/grill-with-docs`.
|
|
95
94
|
- **`/security-audit`** — a whole-app, application-layer security audit run as an independent two-model pass (two models audit the same code separately, then the remediation plan is hardened before any fix). Run before a release or after the attack surface changes (new endpoint, new input source, auth change, dependency bump). Infra hardening (ports/TLS/SSH/backups) is audited separately.
|
|
96
95
|
|
|
97
96
|
## Vocabulary underneath
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: board-to-waves
|
|
3
3
|
disable-model-invocation: false
|
|
4
|
-
"description": "Use when sweeping/grooming the GitHub backlog board to cluster open issues into thematic waves (Wellen) — \"lass uns das Board durchgehen\", \"was ist offen und passt zusammen\", \"clustern wir den Backlog\", \"welche Wellen stecken da drin\" — or to spot candidate waves before planning. Reads all open issues, groups them by the Gate+Booster+Splitter heuristic, estimates size/risk + grill-needed per candidate, and after the user confirms creates cluster/Wave-less candidate STUB issues with a To-Do checklist. STOPS at stubs: no PRD, no slicing, no sub-issue links, no promotion (downstream: to-prd matures the stub, to-issues slices + promotes). NOT for maturing/slicing ONE already-chosen candidate (to-prd/to-issues), NOT for per-issue triage labelling (triage), NOT for code comprehension
|
|
4
|
+
"description": "Use when sweeping/grooming the GitHub backlog board to cluster open issues into thematic waves (Wellen) — \"lass uns das Board durchgehen\", \"was ist offen und passt zusammen\", \"clustern wir den Backlog\", \"welche Wellen stecken da drin\" — or to spot candidate waves before planning. Reads all open issues, groups them by the Gate+Booster+Splitter heuristic, estimates size/risk + grill-needed per candidate, and after the user confirms creates cluster/Wave-less candidate STUB issues with a To-Do checklist. STOPS at stubs: no PRD, no slicing, no sub-issue links, no promotion (downstream: to-prd matures the stub, to-issues slices + promotes). NOT for maturing/slicing ONE already-chosen candidate (to-prd/to-issues), NOT for per-issue triage labelling (triage), NOT for code comprehension — this is board-WIDE thematic affinity grouping, not per-issue and not code-reading."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# board-to-waves
|
|
@@ -130,6 +130,6 @@ Next step (<maintainer>'s call, separate): grill → to-prd (matures the stub)
|
|
|
130
130
|
|
|
131
131
|
## Notes
|
|
132
132
|
- **Stops at stubs.** Never write the PRD, slice, link, promote, or call `to-prd`/`to-issues` yourself.
|
|
133
|
-
- Boundary: `triage` = per-issue state machine; `
|
|
133
|
+
- Boundary: `triage` = per-issue state machine; `improve-codebase-architecture` = code structure; `board-to-waves` = board-wide thematic affinity. Different altitudes.
|
|
134
134
|
- A leftover bucket is OK and intentional — not every issue belongs in a wave. Force-clustering dilutes the gate.
|
|
135
135
|
- Size/risk are a rough estimate, not a commitment. <maintainer> can override the stub's "when to grill" recommendation at any time.
|
|
@@ -8,8 +8,6 @@ description: "Find deepening opportunities in a codebase, informed by the domain
|
|
|
8
8
|
|
|
9
9
|
Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability.
|
|
10
10
|
|
|
11
|
-
For a quick one-off map of an unfamiliar area without the report/grilling loop below, use `zoom-out` instead.
|
|
12
|
-
|
|
13
11
|
## Glossary
|
|
14
12
|
|
|
15
13
|
Use these terms exactly in every suggestion. Consistent language is the point — don't drift into "component," "service," "API," or "boundary." Full definitions in [LANGUAGE.md](LANGUAGE.md).
|
|
@@ -71,6 +71,9 @@ The optional `wrapup` block is a wrapup-only switch, not a board field: `wrapup.
|
|
|
71
71
|
"headings": {
|
|
72
72
|
"vorBau": "Clarify Before Build"
|
|
73
73
|
},
|
|
74
|
+
"titles": {
|
|
75
|
+
"wavePrefix": "Wave"
|
|
76
|
+
},
|
|
74
77
|
"wrapup": {
|
|
75
78
|
"remoteBranchSweep": false
|
|
76
79
|
}
|
|
@@ -93,6 +96,14 @@ follows; renaming an option later is one edit here. A role you don't have
|
|
|
93
96
|
with a visible hint, and `--status-role` commands fail with the exact snippet
|
|
94
97
|
to add.
|
|
95
98
|
|
|
99
|
+
### Wave titles (`titles.wavePrefix`)
|
|
100
|
+
|
|
101
|
+
The word that opens a wave anchor's title: `<prefix> <N> — <topic>` (e.g.
|
|
102
|
+
`Wave 7 — Auth hardening`). `board-sync.py promote` writes it and strips an
|
|
103
|
+
existing one idempotently on re-promote. A profile **without** the key keeps
|
|
104
|
+
the historical default `"Welle"`, so boards created before this key keep
|
|
105
|
+
their titles unchanged; set it once to match your board's language.
|
|
106
|
+
|
|
96
107
|
## If the IDs are not yet filled (stub)
|
|
97
108
|
|
|
98
109
|
1. Create a GitHub-Projects (v2) board for this owner and add the fields above (at minimum a `Status` single-select with your stage options — the recommended stage names are `Idea, Triaged, Spec, In Progress, Review, Done`, matching the seeded `roles` defaults).
|
|
@@ -90,8 +90,7 @@ An independent second model catches what one model rationalises. Read-only, boun
|
|
|
90
90
|
|
|
91
91
|
Not feature work — upkeep.
|
|
92
92
|
|
|
93
|
-
- **`/improve-codebase-architecture`** — run in spare moments to keep the codebase good for agents. Surfaces **deepening opportunities**; picking one _generates an idea_ for the main flow at `/grill-with-docs`.
|
|
94
|
-
- **`/zoom-out`** — step back from the diff to the structure when a change is fighting the codebase; recon that becomes a planned slice or guides a refactor in place.
|
|
93
|
+
- **`/improve-codebase-architecture`** — run in spare moments to keep the codebase good for agents, or step back from the diff to the structure when a change is fighting the codebase. Surfaces **deepening opportunities**; picking one _generates an idea_ for the main flow at `/grill-with-docs`.
|
|
95
94
|
- **`/security-audit`** — a whole-app, application-layer security audit run as an independent two-model pass (two models audit the same code separately, then the remediation plan is hardened before any fix). Run before a release or after the attack surface changes (new endpoint, new input source, auth change, dependency bump). Infra hardening (ports/TLS/SSH/backups) is audited separately.
|
|
96
95
|
|
|
97
96
|
## Vocabulary underneath
|
|
@@ -12,7 +12,7 @@ description: >-
|
|
|
12
12
|
stubs: no PRD, no slicing, no sub-issue links, no promotion (downstream:
|
|
13
13
|
to-prd matures the stub, to-issues slices + promotes). NOT for
|
|
14
14
|
maturing/slicing ONE already-chosen candidate (to-prd/to-issues), NOT for
|
|
15
|
-
per-issue triage labelling (triage), NOT for code comprehension
|
|
15
|
+
per-issue triage labelling (triage), NOT for code comprehension —
|
|
16
16
|
this is board-WIDE thematic affinity grouping, not per-issue and not
|
|
17
17
|
code-reading.
|
|
18
18
|
---
|
|
@@ -143,6 +143,6 @@ Next step (<maintainer>'s call, separate): grill → to-prd (matures the stub)
|
|
|
143
143
|
|
|
144
144
|
## Notes
|
|
145
145
|
- **Stops at stubs.** Never write the PRD, slice, link, promote, or call `to-prd`/`to-issues` yourself.
|
|
146
|
-
- Boundary: `triage` = per-issue state machine; `
|
|
146
|
+
- Boundary: `triage` = per-issue state machine; `improve-codebase-architecture` = code structure; `board-to-waves` = board-wide thematic affinity. Different altitudes.
|
|
147
147
|
- A leftover bucket is OK and intentional — not every issue belongs in a wave. Force-clustering dilutes the gate.
|
|
148
148
|
- Size/risk are a rough estimate, not a commitment. <maintainer> can override the stub's "when to grill" recommendation at any time.
|
|
@@ -8,8 +8,6 @@ description: Find deepening opportunities in a codebase, informed by the domain
|
|
|
8
8
|
|
|
9
9
|
Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability.
|
|
10
10
|
|
|
11
|
-
For a quick one-off map of an unfamiliar area without the report/grilling loop below, use `zoom-out` instead.
|
|
12
|
-
|
|
13
11
|
## Glossary
|
|
14
12
|
|
|
15
13
|
Use these terms exactly in every suggestion. Consistent language is the point — don't drift into "component," "service," "API," or "boundary." Full definitions in [LANGUAGE.md](LANGUAGE.md).
|
|
@@ -102,3 +102,6 @@ both: pick one hooks mechanism per repo.
|
|
|
102
102
|
- Hooks are just scripts — `echo`-debug them freely; nothing is hidden behind a
|
|
103
103
|
tool.
|
|
104
104
|
- Exit non-zero = block the commit. Exit 0 = allow.
|
|
105
|
+
- Keep the template's `unset GIT_DIR …` line: git exports these to hooks, and a
|
|
106
|
+
gate that runs tests which call git in their own temp repos would otherwise
|
|
107
|
+
operate on the host repo's index instead.
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
|
|
12
12
|
set -euo pipefail
|
|
13
13
|
|
|
14
|
+
# --- Env sanitize (keep this) ----------------------------------------------
|
|
15
|
+
# Git exports GIT_DIR & co. to hooks. If your gate runs a test suite whose
|
|
16
|
+
# child tests call git in their own temp repos, these inherited vars redirect
|
|
17
|
+
# every such git call onto THIS repo's index (mass-staged deletions).
|
|
18
|
+
unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_PREFIX
|
|
19
|
+
|
|
14
20
|
# --- Optional preflight ----------------------------------------------------
|
|
15
21
|
# Bail early with a clear message if the toolchain isn't installed, so the
|
|
16
22
|
# real checks don't fail with cryptic errors. Adapt or delete for your stack.
|
|
@@ -71,6 +71,9 @@ The optional `wrapup` block is a wrapup-only switch, not a board field: `wrapup.
|
|
|
71
71
|
"headings": {
|
|
72
72
|
"vorBau": "Clarify Before Build"
|
|
73
73
|
},
|
|
74
|
+
"titles": {
|
|
75
|
+
"wavePrefix": "Wave"
|
|
76
|
+
},
|
|
74
77
|
"wrapup": {
|
|
75
78
|
"remoteBranchSweep": false
|
|
76
79
|
}
|
|
@@ -93,6 +96,14 @@ follows; renaming an option later is one edit here. A role you don't have
|
|
|
93
96
|
with a visible hint, and `--status-role` commands fail with the exact snippet
|
|
94
97
|
to add.
|
|
95
98
|
|
|
99
|
+
### Wave titles (`titles.wavePrefix`)
|
|
100
|
+
|
|
101
|
+
The word that opens a wave anchor's title: `<prefix> <N> — <topic>` (e.g.
|
|
102
|
+
`Wave 7 — Auth hardening`). `board-sync.py promote` writes it and strips an
|
|
103
|
+
existing one idempotently on re-promote. A profile **without** the key keeps
|
|
104
|
+
the historical default `"Welle"`, so boards created before this key keep
|
|
105
|
+
their titles unchanged; set it once to match your board's language.
|
|
106
|
+
|
|
96
107
|
## If the IDs are not yet filled (stub)
|
|
97
108
|
|
|
98
109
|
1. Create a GitHub-Projects (v2) board for this owner and add the fields above (at minimum a `Status` single-select with your stage options — the recommended stage names are `Idea, Triaged, Spec, In Progress, Review, Done`, matching the seeded `roles` defaults).
|
|
@@ -167,15 +167,6 @@
|
|
|
167
167
|
],
|
|
168
168
|
"provenance": "matt-pocock"
|
|
169
169
|
},
|
|
170
|
-
"zoom-out": {
|
|
171
|
-
"class": "vendored",
|
|
172
|
-
"publish": true,
|
|
173
|
-
"surfaces": [
|
|
174
|
-
"claude",
|
|
175
|
-
"codex"
|
|
176
|
-
],
|
|
177
|
-
"provenance": "matt-pocock"
|
|
178
|
-
},
|
|
179
170
|
"improve-codebase-architecture": {
|
|
180
171
|
"class": "vendored",
|
|
181
172
|
"publish": true,
|
package/PROVENANCE.md
CHANGED
|
@@ -6,7 +6,7 @@ not byte-identity.
|
|
|
6
6
|
|
|
7
7
|
## Matt Pocock (MIT) — https://github.com/mattpocock/skills @ d574778
|
|
8
8
|
|
|
9
|
-
to-prd, to-issues, grill-with-docs, grill-me, tdd, diagnose,
|
|
9
|
+
to-prd, to-issues, grill-with-docs, grill-me, tdd, diagnose,
|
|
10
10
|
improve-codebase-architecture, prototype, triage, write-a-skill,
|
|
11
11
|
codebase-design, domain-modeling, implement, resolving-merge-conflicts, ask-matt,
|
|
12
12
|
wayfinder, research, git-guardrails-claude-code, setup-workflow.
|
|
@@ -15,9 +15,10 @@ Folder↔upstream-name divergence (upstream renamed; local folder kept for
|
|
|
15
15
|
invocation stability): `diagnose` = upstream `diagnosing-bugs`,
|
|
16
16
|
`write-a-skill` = upstream `writing-great-skills`, `to-prd` = upstream
|
|
17
17
|
`to-spec`, `to-issues` = upstream `to-tickets` (upstream merged to-issues +
|
|
18
|
-
the short-lived to-plan into to-tickets @ v1.1.0). `zoom-out`
|
|
19
|
-
upstream
|
|
20
|
-
as
|
|
18
|
+
the short-lived to-plan into to-tickets @ v1.1.0). `zoom-out` (last-seen
|
|
19
|
+
upstream SHA 2bf7005) was removed upstream and, after a period as a local
|
|
20
|
+
fork, removed from this kit as well — `improve-codebase-architecture` covers
|
|
21
|
+
the step-back-to-the-structure door.
|
|
21
22
|
|
|
22
23
|
Each carries a `THIRD-PARTY-NOTICES.md` with its upstream path.
|
|
23
24
|
|
package/README.md
CHANGED
|
@@ -58,22 +58,20 @@ The skills aren't a grab-bag — they're four phases of one loop, entered throug
|
|
|
58
58
|
single funnel no matter where your work starts. Each phase below names the failure
|
|
59
59
|
mode it removes and the skills that remove it.
|
|
60
60
|
|
|
61
|
-

|
|
62
62
|
|
|
63
63
|
<!--
|
|
64
|
-
The image above is a pre-rendered PNG, not
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-i tools/agent-workflow-kit/assets/workflow.mmd \
|
|
72
|
-
-o tools/agent-workflow-kit/assets/workflow.png \
|
|
73
|
-
-t dark -b '#0d1117' -s 3
|
|
74
|
-
build-kit.mjs copies assets/workflow.png -> dist-kit/docs/workflow.png.
|
|
64
|
+
The image above is a pre-rendered PNG, not live HTML, on purpose: GitHub
|
|
65
|
+
READMEs can't embed HTML pages, and a PNG renders identically everywhere.
|
|
66
|
+
Source of truth: docs/workflow.html (same design language as
|
|
67
|
+
docs/methodology.html). Regenerate after editing the source:
|
|
68
|
+
serve docs/ locally, open workflow.html?theme=dark in a 1160px-wide
|
|
69
|
+
viewport, take a full-page screenshot -> docs/workflow.png
|
|
70
|
+
The interactive version is linked below and published via GitHub Pages.
|
|
75
71
|
-->
|
|
76
72
|
|
|
73
|
+
**[view the workflow map →](https://ikon85.github.io/agent-workflow-kit/workflow.html)**
|
|
74
|
+
|
|
77
75
|
|
|
78
76
|
### 1. Plan — turn a vague idea into shaped, tracked work
|
|
79
77
|
|
|
@@ -155,7 +153,7 @@ enter outside the plan funnel and feed straight into Execute:
|
|
|
155
153
|
- **`diagnose`** — a disciplined root-cause hunt for bugs (reproduce → isolate →
|
|
156
154
|
fix → prove), not a guess-and-patch. Entered from a bug or anomaly, never the PRD
|
|
157
155
|
funnel; the fix it lands flows on into Execute.
|
|
158
|
-
- **`
|
|
156
|
+
- **`improve-codebase-architecture`** — step back from the diff to
|
|
159
157
|
the structure when a change is fighting the codebase. A recon stream that either
|
|
160
158
|
becomes a planned slice (back through `to-issues`) or guides a refactor in place.
|
|
161
159
|
|
|
@@ -332,6 +330,29 @@ still reference. Flags: `--force` (overwrite pre-existing files on `init`),
|
|
|
332
330
|
|
|
333
331
|
## Release notes
|
|
334
332
|
|
|
333
|
+
### 0.27.1
|
|
334
|
+
|
|
335
|
+
- changed: `scripts/release-parity.mjs`
|
|
336
|
+
|
|
337
|
+
### 0.27.0
|
|
338
|
+
|
|
339
|
+
- removed: `.agents/skills/zoom-out/SKILL.md`
|
|
340
|
+
- removed: `.agents/skills/zoom-out/THIRD-PARTY-NOTICES.md`
|
|
341
|
+
- removed: `.claude/skills/zoom-out/SKILL.md`
|
|
342
|
+
- removed: `.claude/skills/zoom-out/THIRD-PARTY-NOTICES.md`
|
|
343
|
+
- changed: `.agents/skills/ask-matt/SKILL.md`
|
|
344
|
+
- changed: `.agents/skills/board-to-waves/SKILL.md`
|
|
345
|
+
- changed: `.agents/skills/improve-codebase-architecture/SKILL.md`
|
|
346
|
+
- changed: `.agents/skills/setup-workflow/board-sync.md`
|
|
347
|
+
- changed: `.claude/skills/ask-matt/SKILL.md`
|
|
348
|
+
- changed: `.claude/skills/board-to-waves/SKILL.md`
|
|
349
|
+
- changed: `.claude/skills/improve-codebase-architecture/SKILL.md`
|
|
350
|
+
- changed: `.claude/skills/setup-pre-commit/SKILL.md`
|
|
351
|
+
- changed: `.claude/skills/setup-pre-commit/scripts/pre-commit.template.sh`
|
|
352
|
+
- changed: `.claude/skills/setup-workflow/board-sync.md`
|
|
353
|
+
- changed: `scripts/board-sync.py`
|
|
354
|
+
- changed: `scripts/board_config.py`
|
|
355
|
+
|
|
335
356
|
### 0.26.2
|
|
336
357
|
|
|
337
358
|
- Metadata-only release.
|
|
@@ -743,14 +764,15 @@ still reference. Flags: `--force` (overwrite pre-existing files on `init`),
|
|
|
743
764
|
|
|
744
765
|
## What's in the box
|
|
745
766
|
|
|
746
|
-
**
|
|
767
|
+
**43 skills** (Router: ask-matt — "which skill/flow fits?" · Plan: grill-me,
|
|
747
768
|
grill-with-docs, to-prd, to-issues, board-to-waves, triage, spec-self-critique,
|
|
748
769
|
verify-spike, decision-gate, scale-check, to-waves, wayfinder, research · Execute: tdd, prototype, implement, orchestrate-wave ·
|
|
749
|
-
Design/diagnose/refactor streams: diagnose,
|
|
770
|
+
Design/diagnose/refactor streams: diagnose,
|
|
750
771
|
improve-codebase-architecture, codebase-design, domain-modeling, security-audit · Land: wrapup,
|
|
751
772
|
resolving-merge-conflicts, code-review, local-ci, git-worktree-recover, kit-release,
|
|
752
|
-
project-release · Learn: retro, audit-skills, write-a-skill
|
|
753
|
-
|
|
773
|
+
project-release, kit-update · Learn: retro, audit-skills, write-a-skill,
|
|
774
|
+
memory-lifecycle · Setup:
|
|
775
|
+
setup-workflow, git-guardrails, setup-pre-commit, census-update · Codex cross-model: grill-me-codex,
|
|
754
776
|
grill-with-docs-codex, codex-review, codex-build),
|
|
755
777
|
installed for both surfaces — `.claude/skills`
|
|
756
778
|
(Claude Code) and `.agents/skills` (Codex) — plus `codex-adapter-sync`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"kitVersion": "0.
|
|
2
|
+
"kitVersion": "0.27.1",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"path": ".agents/skills/ask-matt/SKILL.md",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"ownerSkill": "ask-matt",
|
|
8
8
|
"surface": "codex",
|
|
9
9
|
"installRole": "consumer",
|
|
10
|
-
"sha256": "
|
|
10
|
+
"sha256": "23997067d90e7a14c49b0bf2000a1f042cca0db8f45197dac7a8e3a8316bfed9",
|
|
11
11
|
"mode": 420,
|
|
12
12
|
"origin": "kit"
|
|
13
13
|
},
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"ownerSkill": "board-to-waves",
|
|
38
38
|
"surface": "codex",
|
|
39
39
|
"installRole": "consumer",
|
|
40
|
-
"sha256": "
|
|
40
|
+
"sha256": "1e145fd3da4426aa210169d9a47c5558588ee7317cbeb4ae8d0852c2cd672943",
|
|
41
41
|
"mode": 420,
|
|
42
42
|
"origin": "kit"
|
|
43
43
|
},
|
|
@@ -347,7 +347,7 @@
|
|
|
347
347
|
"ownerSkill": "improve-codebase-architecture",
|
|
348
348
|
"surface": "codex",
|
|
349
349
|
"installRole": "consumer",
|
|
350
|
-
"sha256": "
|
|
350
|
+
"sha256": "594ef87762120abab778e454c27d240bf5b2c3411f7fe6c5f6ff028a6cdfeb4b",
|
|
351
351
|
"mode": 420,
|
|
352
352
|
"origin": "kit"
|
|
353
353
|
},
|
|
@@ -557,7 +557,7 @@
|
|
|
557
557
|
"ownerSkill": "setup-workflow",
|
|
558
558
|
"surface": "codex",
|
|
559
559
|
"installRole": "consumer",
|
|
560
|
-
"sha256": "
|
|
560
|
+
"sha256": "032c9654baf6f5e60007e7d0767a96ab823a442ed86cb52e801836130c9b5ba2",
|
|
561
561
|
"mode": 420,
|
|
562
562
|
"origin": "kit"
|
|
563
563
|
},
|
|
@@ -971,26 +971,6 @@
|
|
|
971
971
|
"mode": 420,
|
|
972
972
|
"origin": "kit"
|
|
973
973
|
},
|
|
974
|
-
{
|
|
975
|
-
"path": ".agents/skills/zoom-out/SKILL.md",
|
|
976
|
-
"kind": "skill",
|
|
977
|
-
"ownerSkill": "zoom-out",
|
|
978
|
-
"surface": "codex",
|
|
979
|
-
"installRole": "consumer",
|
|
980
|
-
"sha256": "cc448ec9d88e3c9d06fd1d6083a3c15a342b8399bc46829169b8c30d5e657a27",
|
|
981
|
-
"mode": 420,
|
|
982
|
-
"origin": "kit"
|
|
983
|
-
},
|
|
984
|
-
{
|
|
985
|
-
"path": ".agents/skills/zoom-out/THIRD-PARTY-NOTICES.md",
|
|
986
|
-
"kind": "skill",
|
|
987
|
-
"ownerSkill": "zoom-out",
|
|
988
|
-
"surface": "codex",
|
|
989
|
-
"installRole": "consumer",
|
|
990
|
-
"sha256": "87a6e3845e705204a009b26bab75f09e64d97f2d00e19ccd9ee1da39564dbc69",
|
|
991
|
-
"mode": 420,
|
|
992
|
-
"origin": "kit"
|
|
993
|
-
},
|
|
994
974
|
{
|
|
995
975
|
"path": ".claude/hooks/_hook_utils.py",
|
|
996
976
|
"kind": "hook",
|
|
@@ -1181,7 +1161,7 @@
|
|
|
1181
1161
|
"ownerSkill": "ask-matt",
|
|
1182
1162
|
"surface": "claude",
|
|
1183
1163
|
"installRole": "consumer",
|
|
1184
|
-
"sha256": "
|
|
1164
|
+
"sha256": "931ccbc6645adcb02f585061aaf32655ddc1ae547ebb131b6956e8fe227376aa",
|
|
1185
1165
|
"mode": 420,
|
|
1186
1166
|
"origin": "kit"
|
|
1187
1167
|
},
|
|
@@ -1211,7 +1191,7 @@
|
|
|
1211
1191
|
"ownerSkill": "board-to-waves",
|
|
1212
1192
|
"surface": "claude",
|
|
1213
1193
|
"installRole": "consumer",
|
|
1214
|
-
"sha256": "
|
|
1194
|
+
"sha256": "28c47d10f7508cadf5056c66a62d5891dfb61733a30ae517be24dd766c7996dd",
|
|
1215
1195
|
"mode": 420,
|
|
1216
1196
|
"origin": "kit"
|
|
1217
1197
|
},
|
|
@@ -1641,7 +1621,7 @@
|
|
|
1641
1621
|
"ownerSkill": "improve-codebase-architecture",
|
|
1642
1622
|
"surface": "claude",
|
|
1643
1623
|
"installRole": "consumer",
|
|
1644
|
-
"sha256": "
|
|
1624
|
+
"sha256": "bf96773f4ba75a53c8b916052e36a6c0f4bcae8b46b94bb72beb446048ca6d8a",
|
|
1645
1625
|
"mode": 420,
|
|
1646
1626
|
"origin": "kit"
|
|
1647
1627
|
},
|
|
@@ -1841,7 +1821,7 @@
|
|
|
1841
1821
|
"ownerSkill": "setup-pre-commit",
|
|
1842
1822
|
"surface": "claude",
|
|
1843
1823
|
"installRole": "consumer",
|
|
1844
|
-
"sha256": "
|
|
1824
|
+
"sha256": "32a6aba5f5a88079ea81ca31a04fcffd3973e7d52584dca570cd8777c0dd618d",
|
|
1845
1825
|
"mode": 420,
|
|
1846
1826
|
"origin": "kit"
|
|
1847
1827
|
},
|
|
@@ -1851,7 +1831,7 @@
|
|
|
1851
1831
|
"ownerSkill": "setup-pre-commit",
|
|
1852
1832
|
"surface": "claude",
|
|
1853
1833
|
"installRole": "consumer",
|
|
1854
|
-
"sha256": "
|
|
1834
|
+
"sha256": "61ab40452ed411170ef16fbe2d6e5df39a61457c343ecedd23dbf726c1d800b7",
|
|
1855
1835
|
"mode": 420,
|
|
1856
1836
|
"origin": "kit"
|
|
1857
1837
|
},
|
|
@@ -1871,7 +1851,7 @@
|
|
|
1871
1851
|
"ownerSkill": "setup-workflow",
|
|
1872
1852
|
"surface": "claude",
|
|
1873
1853
|
"installRole": "consumer",
|
|
1874
|
-
"sha256": "
|
|
1854
|
+
"sha256": "032c9654baf6f5e60007e7d0767a96ab823a442ed86cb52e801836130c9b5ba2",
|
|
1875
1855
|
"mode": 420,
|
|
1876
1856
|
"origin": "kit"
|
|
1877
1857
|
},
|
|
@@ -2315,26 +2295,6 @@
|
|
|
2315
2295
|
"mode": 420,
|
|
2316
2296
|
"origin": "kit"
|
|
2317
2297
|
},
|
|
2318
|
-
{
|
|
2319
|
-
"path": ".claude/skills/zoom-out/SKILL.md",
|
|
2320
|
-
"kind": "skill",
|
|
2321
|
-
"ownerSkill": "zoom-out",
|
|
2322
|
-
"surface": "claude",
|
|
2323
|
-
"installRole": "consumer",
|
|
2324
|
-
"sha256": "9e4fbb4e8c5d8cc847812b324db8e72aa716148bceb7d2d368e8bfda146fb84f",
|
|
2325
|
-
"mode": 420,
|
|
2326
|
-
"origin": "kit"
|
|
2327
|
-
},
|
|
2328
|
-
{
|
|
2329
|
-
"path": ".claude/skills/zoom-out/THIRD-PARTY-NOTICES.md",
|
|
2330
|
-
"kind": "skill",
|
|
2331
|
-
"ownerSkill": "zoom-out",
|
|
2332
|
-
"surface": "claude",
|
|
2333
|
-
"installRole": "consumer",
|
|
2334
|
-
"sha256": "87a6e3845e705204a009b26bab75f09e64d97f2d00e19ccd9ee1da39564dbc69",
|
|
2335
|
-
"mode": 420,
|
|
2336
|
-
"origin": "kit"
|
|
2337
|
-
},
|
|
2338
2298
|
{
|
|
2339
2299
|
"path": "assets/memory-templates/meta_decision_layer_choice.md",
|
|
2340
2300
|
"kind": "template",
|
|
@@ -2379,7 +2339,7 @@
|
|
|
2379
2339
|
"path": "scripts/board_config.py",
|
|
2380
2340
|
"kind": "script",
|
|
2381
2341
|
"installRole": "consumer",
|
|
2382
|
-
"sha256": "
|
|
2342
|
+
"sha256": "020b44d1df176d44d531e24bd7d01ead25182b287a0316239489475dfeb00aa3",
|
|
2383
2343
|
"mode": 420,
|
|
2384
2344
|
"origin": "kit"
|
|
2385
2345
|
},
|
|
@@ -2395,7 +2355,7 @@
|
|
|
2395
2355
|
"path": "scripts/board-sync.py",
|
|
2396
2356
|
"kind": "script",
|
|
2397
2357
|
"installRole": "consumer",
|
|
2398
|
-
"sha256": "
|
|
2358
|
+
"sha256": "4cf206abfec87578863c99f11e00c99a2048f4f8776cbcb38a23c69e73e37c16",
|
|
2399
2359
|
"mode": 493,
|
|
2400
2360
|
"origin": "kit"
|
|
2401
2361
|
},
|
|
@@ -2579,7 +2539,7 @@
|
|
|
2579
2539
|
"path": "scripts/release-parity.mjs",
|
|
2580
2540
|
"kind": "script",
|
|
2581
2541
|
"installRole": "consumer",
|
|
2582
|
-
"sha256": "
|
|
2542
|
+
"sha256": "32f61bf776974be63a017e90f428d4dab6098a9e2ba0c25c865d18ea3bd3e89e",
|
|
2583
2543
|
"mode": 420,
|
|
2584
2544
|
"origin": "kit"
|
|
2585
2545
|
},
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>agent-workflow-kit — Workflow</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--page-bg: #F5F1E8;
|
|
10
|
+
--surface: #FAFAF7;
|
|
11
|
+
--ink: #1F2532;
|
|
12
|
+
--muted: #5B6579;
|
|
13
|
+
--border: #E8E4D8;
|
|
14
|
+
--accent-deep: #5C5630;
|
|
15
|
+
|
|
16
|
+
--plan: #4A6280; --plan-bg: #DDE3EC; --plan-text: #2F4258;
|
|
17
|
+
--exec: #5C7A4A; --exec-bg: #E8EDE0; --exec-text: #3D5230;
|
|
18
|
+
--land: #C2902B; --land-bg: #F2E5C7; --land-text: #7A5B1D;
|
|
19
|
+
--learn: #8A95A6; --learn-bg: #E8EBF0; --learn-text: #5B6579;
|
|
20
|
+
--gate: #A8432D; --gate-bg: #F2DAD0; --gate-text: #6E2B1D;
|
|
21
|
+
--door: #5B6579; --door-bg: #EFEDE4; --door-text: #454E60;
|
|
22
|
+
}
|
|
23
|
+
@media (prefers-color-scheme: dark) {
|
|
24
|
+
:root {
|
|
25
|
+
--page-bg:#1F2532; --surface:#2E3548; --ink:#F5F1E8; --muted:#A6B0BF;
|
|
26
|
+
--border:rgba(255,255,255,0.14); --accent-deep:#B5A86B;
|
|
27
|
+
--plan:#7C9BB2; --plan-bg:#2E3850; --plan-text:#8FA9C4;
|
|
28
|
+
--exec:#82A36C; --exec-bg:#2A3A26; --exec-text:#94B57E;
|
|
29
|
+
--land:#DBAC4F; --land-bg:#3A3220; --land-text:#DBAC4F;
|
|
30
|
+
--learn:#8A95A6; --learn-bg:#2A3142; --learn-text:#9CA6B5;
|
|
31
|
+
--gate:#D9554F; --gate-bg:#3A2620; --gate-text:#EC8780;
|
|
32
|
+
--door:#8A95A6; --door-bg:#272E3E; --door-text:#A6B0BF;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
:root[data-theme="dark"] {
|
|
36
|
+
--page-bg:#1F2532; --surface:#2E3548; --ink:#F5F1E8; --muted:#A6B0BF;
|
|
37
|
+
--border:rgba(255,255,255,0.14); --accent-deep:#B5A86B;
|
|
38
|
+
--plan:#7C9BB2; --plan-bg:#2E3850; --plan-text:#8FA9C4;
|
|
39
|
+
--exec:#82A36C; --exec-bg:#2A3A26; --exec-text:#94B57E;
|
|
40
|
+
--land:#DBAC4F; --land-bg:#3A3220; --land-text:#DBAC4F;
|
|
41
|
+
--learn:#8A95A6; --learn-bg:#2A3142; --learn-text:#9CA6B5;
|
|
42
|
+
--gate:#D9554F; --gate-bg:#3A2620; --gate-text:#EC8780;
|
|
43
|
+
--door:#8A95A6; --door-bg:#272E3E; --door-text:#A6B0BF;
|
|
44
|
+
}
|
|
45
|
+
:root[data-theme="light"] {
|
|
46
|
+
--page-bg:#F5F1E8; --surface:#FAFAF7; --ink:#1F2532; --muted:#5B6579;
|
|
47
|
+
--border:#E8E4D8; --accent-deep:#5C5630;
|
|
48
|
+
--plan:#4A6280; --plan-bg:#DDE3EC; --plan-text:#2F4258;
|
|
49
|
+
--exec:#5C7A4A; --exec-bg:#E8EDE0; --exec-text:#3D5230;
|
|
50
|
+
--land:#C2902B; --land-bg:#F2E5C7; --land-text:#7A5B1D;
|
|
51
|
+
--learn:#8A95A6; --learn-bg:#E8EBF0; --learn-text:#5B6579;
|
|
52
|
+
--gate:#A8432D; --gate-bg:#F2DAD0; --gate-text:#6E2B1D;
|
|
53
|
+
--door:#5B6579; --door-bg:#EFEDE4; --door-text:#454E60;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
* { box-sizing: border-box; }
|
|
57
|
+
body {
|
|
58
|
+
margin: 0; background: var(--page-bg); color: var(--ink);
|
|
59
|
+
font-family: Charter, "Bitstream Charter", "Iowan Old Style", Georgia, serif;
|
|
60
|
+
font-size: 17px; line-height: 1.6; overflow-x: hidden;
|
|
61
|
+
}
|
|
62
|
+
.wrap { max-width: 1010px; margin: 0 auto; padding: 40px 24px 80px; }
|
|
63
|
+
h1,h3 { font-family: system-ui, "Segoe UI", -apple-system, sans-serif; }
|
|
64
|
+
h1 { font-size: 1.9rem; font-weight: 650; letter-spacing: -0.015em; margin: 0 0 8px; text-wrap: balance; }
|
|
65
|
+
p { margin: 0 0 1em; max-width: 72ch; }
|
|
66
|
+
a { color: var(--accent-deep); }
|
|
67
|
+
.eyebrow {
|
|
68
|
+
font-family: ui-monospace, Menlo, monospace; font-size: 0.72rem;
|
|
69
|
+
letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin-bottom: 12px;
|
|
70
|
+
}
|
|
71
|
+
.lede { color: var(--muted); font-size: 1.05rem; max-width: 66ch; }
|
|
72
|
+
|
|
73
|
+
.legend { display: flex; flex-wrap: wrap; gap: 8px 18px; margin: 18px 0 22px; }
|
|
74
|
+
.key { display: flex; align-items: center; gap: 7px; font-family: system-ui, sans-serif; font-size: 0.8rem; color: var(--muted); }
|
|
75
|
+
.dot { width: 11px; height: 11px; border-radius: 3px; background: var(--c); flex: none; }
|
|
76
|
+
|
|
77
|
+
.station {
|
|
78
|
+
font-family: ui-monospace, Menlo, monospace; font-size: 0.73rem;
|
|
79
|
+
background: var(--soft, var(--page-bg)); color: var(--sc, var(--ink));
|
|
80
|
+
border: 1px solid var(--border); border-radius: 5px; padding: 4px 8px; white-space: nowrap;
|
|
81
|
+
}
|
|
82
|
+
.station.plain { --soft: var(--page-bg); --sc: var(--muted); font-style: italic; }
|
|
83
|
+
.st-plan { --soft: var(--plan-bg); --sc: var(--plan-text); border-color: color-mix(in srgb, var(--plan) 40%, var(--border)); }
|
|
84
|
+
.st-exec { --soft: var(--exec-bg); --sc: var(--exec-text); border-color: color-mix(in srgb, var(--exec) 40%, var(--border)); }
|
|
85
|
+
.st-land { --soft: var(--land-bg); --sc: var(--land-text); border-color: color-mix(in srgb, var(--land) 40%, var(--border)); }
|
|
86
|
+
.st-learn { --soft: var(--learn-bg); --sc: var(--learn-text); border-color: color-mix(in srgb, var(--learn) 40%, var(--border)); }
|
|
87
|
+
.st-gate { --soft: var(--gate-bg); --sc: var(--gate-text); border-color: color-mix(in srgb, var(--gate) 50%, var(--border)); font-weight: 600; }
|
|
88
|
+
.st-door { --soft: var(--door-bg); --sc: var(--door-text); border-color: color-mix(in srgb, var(--door) 40%, var(--border)); }
|
|
89
|
+
.arrow { color: var(--muted); font-family: system-ui, sans-serif; font-size: 0.85rem; padding: 0 2px; user-select: none; }
|
|
90
|
+
.decision { font-size: 0.76rem; color: var(--muted); font-style: italic; padding: 0 4px; }
|
|
91
|
+
|
|
92
|
+
.subway { display: grid; grid-template-columns: 158px 1fr; border: 1px solid var(--border);
|
|
93
|
+
border-radius: 8px; background: var(--surface); overflow: hidden; }
|
|
94
|
+
.sw-row { display: contents; }
|
|
95
|
+
.sw-label { padding: 14px 14px; border-bottom: 1px solid var(--border); border-right: 1px solid var(--border);
|
|
96
|
+
font-family: system-ui, sans-serif; font-size: 0.8rem; font-weight: 650; color: var(--lc, var(--muted));
|
|
97
|
+
display: flex; flex-direction: column; gap: 2px; justify-content: center; }
|
|
98
|
+
.sw-label small { font-weight: 400; color: var(--muted); font-size: 0.72rem; }
|
|
99
|
+
.sw-track { padding: 13px 16px; border-bottom: 1px solid var(--border); display: flex; flex-wrap: wrap;
|
|
100
|
+
align-items: center; gap: 7px 4px; background: linear-gradient(to right, color-mix(in srgb, var(--lbg, transparent) 45%, transparent), transparent 55%); }
|
|
101
|
+
.sw-row:last-of-type .sw-label, .sw-row:last-of-type .sw-track { border-bottom: none; }
|
|
102
|
+
|
|
103
|
+
.inter { grid-column: 1 / -1; padding: 12px 16px 14px; border-top: 1px dashed var(--border); }
|
|
104
|
+
.inter .i-title { font-family: system-ui, sans-serif; font-weight: 650; font-size: 0.82rem; color: var(--muted); margin-bottom: 8px; }
|
|
105
|
+
.inter .i-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 4px; font-size: 0.85rem; color: var(--muted); margin-bottom: 7px; }
|
|
106
|
+
.inter .i-line:last-child { margin-bottom: 0; }
|
|
107
|
+
|
|
108
|
+
footer { margin-top: 28px; font-size: 0.85rem; color: var(--muted); font-family: system-ui, sans-serif; }
|
|
109
|
+
|
|
110
|
+
@media (max-width: 640px) {
|
|
111
|
+
.subway { grid-template-columns: 1fr; }
|
|
112
|
+
.sw-label { border-right: none; padding-bottom: 4px; }
|
|
113
|
+
.sw-track { border-bottom: 1px solid var(--border); }
|
|
114
|
+
}
|
|
115
|
+
</style>
|
|
116
|
+
</head>
|
|
117
|
+
<body>
|
|
118
|
+
<div class="wrap">
|
|
119
|
+
<div class="eyebrow">agent-workflow-kit · workflow</div>
|
|
120
|
+
<h1>One loop, many doors</h1>
|
|
121
|
+
<p class="lede">Every piece of work — idea, plan, backlog, bug — boards its own line, and every line converges on the same spine: <em>implement → wrapup → retro</em>. implement drives tdd internally — red → green → refactor at pre-agreed seams, code-review before landing.</p>
|
|
122
|
+
|
|
123
|
+
<div class="legend">
|
|
124
|
+
<span class="key"><span class="dot" style="--c: var(--door)"></span> Door / input</span>
|
|
125
|
+
<span class="key"><span class="dot" style="--c: var(--plan)"></span> Plan</span>
|
|
126
|
+
<span class="key"><span class="dot" style="--c: var(--exec)"></span> Execute</span>
|
|
127
|
+
<span class="key"><span class="dot" style="--c: var(--land)"></span> Land</span>
|
|
128
|
+
<span class="key"><span class="dot" style="--c: var(--learn)"></span> Learn</span>
|
|
129
|
+
<span class="key"><span class="dot" style="--c: var(--gate)"></span> Gate</span>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<div class="subway">
|
|
133
|
+
<div class="sw-row">
|
|
134
|
+
<div class="sw-label" style="--lc: var(--door-text); --lbg: var(--door-bg);">router<small>size unclear? start here</small></div>
|
|
135
|
+
<div class="sw-track" style="--lbg: var(--door-bg);">
|
|
136
|
+
<span class="station st-plan">scale-check</span>
|
|
137
|
+
<span class="decision">3–6 questions</span><span class="arrow">→</span>
|
|
138
|
+
<span class="station plain">Program → program line</span><span class="arrow">/</span>
|
|
139
|
+
<span class="station plain">Feature → main line</span><span class="arrow">/</span>
|
|
140
|
+
<span class="station plain">Direct-Slice → implement</span><span class="arrow">/</span>
|
|
141
|
+
<span class="station plain">Bug → repair line</span>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
<div class="sw-row">
|
|
145
|
+
<div class="sw-label" style="--lc: var(--plan-text); --lbg: var(--plan-bg);">main line<small>idea → shipped</small></div>
|
|
146
|
+
<div class="sw-track" style="--lbg: var(--plan-bg);">
|
|
147
|
+
<span class="station plain">idea / plan / issue</span><span class="arrow">→</span>
|
|
148
|
+
<span class="station st-gate">grill? — see grill line</span><span class="arrow">→</span>
|
|
149
|
+
<span class="station st-plan">to-prd</span><span class="arrow">→</span>
|
|
150
|
+
<span class="station st-plan">to-issues</span><span class="arrow">→</span>
|
|
151
|
+
<span class="station st-gate">gate</span><span class="arrow">→</span>
|
|
152
|
+
<span class="station st-exec">implement</span>
|
|
153
|
+
<span class="decision">drives tdd inside</span><span class="arrow">→</span>
|
|
154
|
+
<span class="station st-land">wrapup</span><span class="arrow">→</span>
|
|
155
|
+
<span class="station st-learn">retro</span>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
<div class="sw-row">
|
|
159
|
+
<div class="sw-label" style="--lc: var(--gate-text); --lbg: var(--gate-bg);">grill line<small>as deep as the stakes</small></div>
|
|
160
|
+
<div class="sw-track" style="--lbg: var(--gate-bg);">
|
|
161
|
+
<span class="station plain">mechanical change → none</span><span class="arrow">/</span>
|
|
162
|
+
<span class="station st-gate">grill-me</span>
|
|
163
|
+
<span class="decision">relentless interview, one question at a time</span><span class="arrow">/</span>
|
|
164
|
+
<span class="station st-gate">grill-with-docs</span>
|
|
165
|
+
<span class="decision">+ CONTEXT.md, ADRs updated inline</span><span class="arrow">/</span>
|
|
166
|
+
<span class="station st-gate">grill-me-codex · grill-with-docs-codex</span>
|
|
167
|
+
<span class="decision">+ Act 2: Codex reviews PLAN.md adversarially until APPROVED</span>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="sw-row">
|
|
171
|
+
<div class="sw-label" style="--lc: var(--gate-text); --lbg: var(--gate-bg);">codex line<small>second model, high stakes</small></div>
|
|
172
|
+
<div class="sw-track" style="--lbg: var(--gate-bg);">
|
|
173
|
+
<span class="station st-gate">codex-review</span>
|
|
174
|
+
<span class="decision">plan already exists — cross-model review only</span><span class="arrow">·</span>
|
|
175
|
+
<span class="station st-exec">codex-build</span>
|
|
176
|
+
<span class="decision">Act 3: Codex implements the frozen spec, Claude verifies diff + proof</span>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="sw-row">
|
|
180
|
+
<div class="sw-label" style="--lc: var(--plan-text); --lbg: var(--plan-bg);">program line<small>too big for one wave</small></div>
|
|
181
|
+
<div class="sw-track" style="--lbg: var(--plan-bg);">
|
|
182
|
+
<span class="station st-plan">scale-check</span><span class="arrow">→</span>
|
|
183
|
+
<span class="station st-gate">grill</span><span class="arrow">→</span>
|
|
184
|
+
<span class="station st-plan">to-waves</span>
|
|
185
|
+
<span class="decision">preview gate · zero board writes until yes</span><span class="arrow">→</span>
|
|
186
|
+
<span class="station st-exec">orchestrate-wave</span>
|
|
187
|
+
<span class="decision">per wave, often AFK</span><span class="arrow">→</span>
|
|
188
|
+
<span class="station st-land">wrapup</span><span class="arrow">→</span>
|
|
189
|
+
<span class="station st-learn">retro</span>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="sw-row">
|
|
193
|
+
<div class="sw-label" style="--lc: var(--plan-text); --lbg: var(--plan-bg);">board line<small>it grew bottom-up</small></div>
|
|
194
|
+
<div class="sw-track" style="--lbg: var(--plan-bg);">
|
|
195
|
+
<span class="station plain">loose backlog</span><span class="arrow">→</span>
|
|
196
|
+
<span class="station st-plan">board-to-waves</span>
|
|
197
|
+
<span class="decision">wave-stub candidates, no number yet</span><span class="arrow">→</span>
|
|
198
|
+
<span class="station st-plan">to-prd</span>
|
|
199
|
+
<span class="decision">matures the stub</span><span class="arrow">→</span>
|
|
200
|
+
<span class="station st-plan">to-issues</span>
|
|
201
|
+
<span class="decision">≥2 slices → promotes to a numbered wave anchor</span><span class="arrow">→</span>
|
|
202
|
+
<span class="station plain">joins the program line</span>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="sw-row">
|
|
206
|
+
<div class="sw-label" style="--lc: var(--gate-text); --lbg: var(--gate-bg);">repair line<small>something's broken</small></div>
|
|
207
|
+
<div class="sw-track" style="--lbg: var(--gate-bg);">
|
|
208
|
+
<span class="station plain">bug / anomaly</span><span class="arrow">→</span>
|
|
209
|
+
<span class="station st-door">diagnose</span>
|
|
210
|
+
<span class="decision">reproduce → isolate → fix → prove</span><span class="arrow">→</span>
|
|
211
|
+
<span class="station st-exec">implement</span><span class="arrow">→</span>
|
|
212
|
+
<span class="station st-land">wrapup</span>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
<div class="sw-row">
|
|
216
|
+
<div class="sw-label" style="--lc: var(--exec-text); --lbg: var(--exec-bg);">structure line<small>code fights back</small></div>
|
|
217
|
+
<div class="sw-track" style="--lbg: var(--exec-bg);">
|
|
218
|
+
<span class="station plain">change fighting the codebase</span><span class="arrow">→</span>
|
|
219
|
+
<span class="station st-door">improve-codebase-architecture</span><span class="arrow">→</span>
|
|
220
|
+
<span class="station st-plan">to-issues</span>
|
|
221
|
+
<span class="decision">plan a slice — or refactor in place</span>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
<div class="sw-row">
|
|
225
|
+
<div class="sw-label" style="--lc: var(--learn-text); --lbg: var(--learn-bg);">learn line<small>retro's real output</small></div>
|
|
226
|
+
<div class="sw-track" style="--lbg: var(--learn-bg);">
|
|
227
|
+
<span class="station st-learn">retro</span>
|
|
228
|
+
<span class="decision">user + agent friction, symmetric</span><span class="arrow">→</span>
|
|
229
|
+
<span class="station st-gate">CLAUDE.md rule</span><span class="arrow">/</span>
|
|
230
|
+
<span class="station st-land">spec-self-critique layer · ADR</span><span class="arrow">/</span>
|
|
231
|
+
<span class="station st-learn">memory</span><span class="arrow">/</span>
|
|
232
|
+
<span class="station st-plan">board issue</span>
|
|
233
|
+
<span class="decision">per-patch approval · Meta section in PR body</span>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<div class="inter">
|
|
238
|
+
<div class="i-title">Interchanges</div>
|
|
239
|
+
<div class="i-line">a slice hinging on an unknown inserts <span class="station st-gate">verify-spike / decision-gate</span> before its build</div>
|
|
240
|
+
<div class="i-line">unclear path inserts <span class="station st-exec">prototype</span> — throwaway that answers the design question first</div>
|
|
241
|
+
<div class="i-line">inside implement, <span class="station st-exec">tdd</span> runs red → green → refactor at pre-agreed seams</div>
|
|
242
|
+
<div class="i-line">before every PR, <span class="station st-land">local-ci</span> runs the full gate; the <span class="station st-gate">pre-commit / pre-push hooks</span> fire automatically once installed</div>
|
|
243
|
+
<div class="i-line">lost? <span class="station st-door">ask-matt</span> routes you to the right skill</div>
|
|
244
|
+
<div class="i-line">one-time setup, off-map: <span class="station st-door">setup-workflow</span> <span class="station st-door">git-guardrails</span> <span class="station st-door">setup-pre-commit</span></div>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
<footer>
|
|
249
|
+
How waves, programs, and slices relate — the altitude model — lives on the
|
|
250
|
+
<a href="methodology.html">methodology page</a>.
|
|
251
|
+
</footer>
|
|
252
|
+
</div>
|
|
253
|
+
<script>
|
|
254
|
+
// Capture helper: ?theme=dark|light pins the palette for PNG rendering.
|
|
255
|
+
var t = new URLSearchParams(location.search).get("theme");
|
|
256
|
+
if (t === "dark" || t === "light") document.documentElement.dataset.theme = t;
|
|
257
|
+
</script>
|
|
258
|
+
</body>
|
|
259
|
+
</html>
|
package/docs/workflow.png
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikon85/agent-workflow-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.1",
|
|
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": {
|
package/scripts/board-sync.py
CHANGED
|
@@ -35,7 +35,7 @@ from typing import Optional
|
|
|
35
35
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
36
36
|
from board_config import ( # noqa: E402
|
|
37
37
|
ConfigError, load_board_config, phase_field_id, program_type_label,
|
|
38
|
-
status_roles, STATUS_ROLE_KEYS,
|
|
38
|
+
status_roles, wave_title_prefix, STATUS_ROLE_KEYS,
|
|
39
39
|
)
|
|
40
40
|
# stamp-batch / field-value / promote-guards — pure logic, see module docstring.
|
|
41
41
|
from board_fields import ( # noqa: E402
|
|
@@ -414,9 +414,14 @@ def promote_label_args(issue: int, strip: Optional[list[str]] = None) -> list[st
|
|
|
414
414
|
return args
|
|
415
415
|
|
|
416
416
|
|
|
417
|
-
#
|
|
418
|
-
#
|
|
419
|
-
|
|
417
|
+
# The wave-anchor title prefix word comes from the profile (`titles.wavePrefix`,
|
|
418
|
+
# literal default "Welle" — see board_config.wave_title_prefix).
|
|
419
|
+
WAVE_TITLE_PREFIX = wave_title_prefix(_CFG)
|
|
420
|
+
# Existing `<prefix> <N> — ` prefix (any number, em-dash/en-dash/hyphen
|
|
421
|
+
# separator) — replaced on re-promote so the wave number never doubles up.
|
|
422
|
+
_WAVE_PREFIX_RE = re.compile(
|
|
423
|
+
rf"^\s*{re.escape(WAVE_TITLE_PREFIX)}\s+\d+\s*[—–-]\s*", re.IGNORECASE
|
|
424
|
+
)
|
|
420
425
|
# Leading conventional-commit token (`fix:`, `feat(ui):`, `chore!:`) — anchors
|
|
421
426
|
# don't carry these, so strip it when present. Matches only a lowercase token,
|
|
422
427
|
# so prose titles like "Supabase-Residuen entfernen: …" are left intact.
|
|
@@ -424,18 +429,18 @@ _CONVENTIONAL_PREFIX_RE = re.compile(r"^[a-z]+(\([^)]*\))?!?:\s*")
|
|
|
424
429
|
|
|
425
430
|
|
|
426
431
|
def wave_title(current: str, wave: int) -> str:
|
|
427
|
-
"""Title for a wave anchor:
|
|
432
|
+
"""Title for a wave anchor: `<prefix> <N> — <topic>`.
|
|
428
433
|
|
|
429
434
|
Strips a leading conventional-commit prefix FIRST, then any existing
|
|
430
|
-
|
|
431
|
-
with the given wave. Order matters: a title like
|
|
432
|
-
|
|
433
|
-
stripping Wave first leaves it intact and doubles up into
|
|
434
|
-
|
|
435
|
+
`<prefix> X — ` prefix underneath it (idempotent re-promote), then
|
|
436
|
+
re-prefixes with the given wave. Order matters: a title like
|
|
437
|
+
`fix: <prefix> 7 — X` only reveals its wave prefix once the conventional
|
|
438
|
+
prefix is gone — stripping Wave first leaves it intact and doubles up into
|
|
439
|
+
`<prefix> 29 — <prefix> 7 — X`.
|
|
435
440
|
"""
|
|
436
441
|
thema = _CONVENTIONAL_PREFIX_RE.sub("", current)
|
|
437
442
|
thema = _WAVE_PREFIX_RE.sub("", thema).strip()
|
|
438
|
-
return f"
|
|
443
|
+
return f"{WAVE_TITLE_PREFIX} {wave} — {thema}"
|
|
439
444
|
|
|
440
445
|
|
|
441
446
|
def title_edit_args(issue: int, title: str) -> list[str]:
|
|
@@ -770,7 +775,7 @@ def cmd_promote(args) -> int:
|
|
|
770
775
|
if args.dry_run:
|
|
771
776
|
_print_dry(promote_label_args(args.issue))
|
|
772
777
|
if rename:
|
|
773
|
-
print(f"[dry-run] gh issue edit {args.issue} --title '
|
|
778
|
+
print(f"[dry-run] gh issue edit {args.issue} --title '{WAVE_TITLE_PREFIX} {args.wave} — <topic>'")
|
|
774
779
|
_add_and_stamp(url, args.wave, args.status, None, None, None, dry_run=True)
|
|
775
780
|
return 0
|
|
776
781
|
labels = _issue_type_labels(args.issue)
|
|
@@ -1158,7 +1163,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1158
1163
|
help="explicit Wave (read `next-wave` first — no in-promote race)")
|
|
1159
1164
|
_add_status_flags(pr)
|
|
1160
1165
|
pr.add_argument("--no-rename", action="store_true",
|
|
1161
|
-
help="keep the title as-is (skip the
|
|
1166
|
+
help="keep the title as-is (skip the wave title prefix)")
|
|
1162
1167
|
pr.add_argument("--dry-run", action="store_true")
|
|
1163
1168
|
pr.set_defaults(func=cmd_promote)
|
|
1164
1169
|
|
package/scripts/board_config.py
CHANGED
|
@@ -126,6 +126,13 @@ def program_type_label(cfg: dict) -> str:
|
|
|
126
126
|
return cfg.get("labels", {}).get("programType", "type:program")
|
|
127
127
|
|
|
128
128
|
|
|
129
|
+
def wave_title_prefix(cfg: dict) -> str:
|
|
130
|
+
"""The `titles.wavePrefix` word that opens a wave anchor's title
|
|
131
|
+
(`<prefix> <N> — <topic>`), or the literal default `"Welle"` when the
|
|
132
|
+
profile hasn't set one — existing boards keep their titles unchanged."""
|
|
133
|
+
return cfg.get("titles", {}).get("wavePrefix", "Welle")
|
|
134
|
+
|
|
135
|
+
|
|
129
136
|
# The semantic role keys of the workflow — schema, not
|
|
130
137
|
# vocabulary; stable once shipped, extend additively, never rename. Single
|
|
131
138
|
# home so CLI `choices`, docs, and future consumers reference one list.
|
|
@@ -50,3 +50,37 @@ export function assertReleaseParity(identities) {
|
|
|
50
50
|
}
|
|
51
51
|
return identities.local;
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
// Consumer-side identity: an unpacked installation cannot be re-packed
|
|
55
|
+
// byte-identically (npm normalizes at publish/unpack), so the installed copy
|
|
56
|
+
// proves itself by content — never by a fresh tarball hash.
|
|
57
|
+
const INSTALLED_FIELDS = ['name', 'version', 'manifestSha256'];
|
|
58
|
+
|
|
59
|
+
export async function installedIdentityFromDir(kitRoot) {
|
|
60
|
+
const packageJson = JSON.parse(await readFile(`${kitRoot}/package.json`, 'utf8'));
|
|
61
|
+
const manifest = await readFile(`${kitRoot}/agent-workflow-kit.package.json`);
|
|
62
|
+
if (packageJson.version !== JSON.parse(manifest).kitVersion) {
|
|
63
|
+
throw new Error('installed package and manifest versions mismatch');
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
name: packageJson.name,
|
|
67
|
+
version: packageJson.version,
|
|
68
|
+
manifestSha256: digest('sha256', manifest),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function assertConsumerReleaseParity({ installed, npm, github }) {
|
|
73
|
+
validate('npm', npm);
|
|
74
|
+
validate('github', github);
|
|
75
|
+
for (const field of FIELDS) {
|
|
76
|
+
if (github[field] !== npm[field]) throw new Error(`github ${field} mismatch`);
|
|
77
|
+
}
|
|
78
|
+
if (!installed || typeof installed !== 'object') throw new Error('installed release identity missing');
|
|
79
|
+
for (const field of INSTALLED_FIELDS) {
|
|
80
|
+
if (typeof installed[field] !== 'string' || !installed[field]) {
|
|
81
|
+
throw new Error(`installed ${field} missing`);
|
|
82
|
+
}
|
|
83
|
+
if (installed[field] !== npm[field]) throw new Error(`installed ${field} mismatch`);
|
|
84
|
+
}
|
|
85
|
+
return npm;
|
|
86
|
+
}
|
|
@@ -51,3 +51,40 @@ test('a package tarball produces a deterministic content identity', async () =>
|
|
|
51
51
|
assert.deepEqual(first, second);
|
|
52
52
|
} finally { await rm(root, { recursive: true, force: true }); }
|
|
53
53
|
});
|
|
54
|
+
|
|
55
|
+
test('consumer parity proves npm↔github and matches the installed copy without re-packing', async () => {
|
|
56
|
+
const { assertConsumerReleaseParity } = await import('./release-parity.mjs');
|
|
57
|
+
const installed = { name: identity.name, version: identity.version, manifestSha256: identity.manifestSha256 };
|
|
58
|
+
assert.deepEqual(
|
|
59
|
+
assertConsumerReleaseParity({ installed, npm: { ...identity }, github: { ...identity } }),
|
|
60
|
+
identity,
|
|
61
|
+
);
|
|
62
|
+
assert.throws(() => assertConsumerReleaseParity({
|
|
63
|
+
installed, npm: { ...identity }, github: { ...identity, tarballIntegrity: 'different' },
|
|
64
|
+
}), /github tarballIntegrity mismatch/);
|
|
65
|
+
assert.throws(() => assertConsumerReleaseParity({
|
|
66
|
+
installed: { ...installed, manifestSha256: 'different' },
|
|
67
|
+
npm: { ...identity }, github: { ...identity },
|
|
68
|
+
}), /installed manifestSha256 mismatch/);
|
|
69
|
+
assert.throws(() => assertConsumerReleaseParity({
|
|
70
|
+
installed: { ...installed, version: '9.9.9' },
|
|
71
|
+
npm: { ...identity }, github: { ...identity },
|
|
72
|
+
}), /installed version mismatch/);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('an installed kit directory yields a content identity without npm pack', async () => {
|
|
76
|
+
const { installedIdentityFromDir } = await import('./release-parity.mjs');
|
|
77
|
+
const root = await mkdtemp(join(tmpdir(), 'release-parity-installed-'));
|
|
78
|
+
try {
|
|
79
|
+
const manifest = JSON.stringify({ kitVersion: '1.2.3', files: [] });
|
|
80
|
+
await writeFile(join(root, 'package.json'), JSON.stringify({ name: identity.name, version: '1.2.3' }));
|
|
81
|
+
await writeFile(join(root, 'agent-workflow-kit.package.json'), manifest);
|
|
82
|
+
const installed = await installedIdentityFromDir(root);
|
|
83
|
+
assert.equal(installed.name, identity.name);
|
|
84
|
+
assert.equal(installed.version, '1.2.3');
|
|
85
|
+
assert.equal(typeof installed.manifestSha256, 'string');
|
|
86
|
+
assert.equal('tarballIntegrity' in installed, false);
|
|
87
|
+
} finally {
|
|
88
|
+
await rm(root, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Wave anchor titles take their prefix from the board profile, not a hardcoded
|
|
3
|
+
German literal — an optional `titles.wavePrefix` key with the literal default
|
|
4
|
+
`"Welle"` so every existing profile keeps working unchanged."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import copy
|
|
9
|
+
import importlib.util
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import tempfile
|
|
13
|
+
import unittest
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
BASE_PROFILE = {
|
|
18
|
+
"repo": "example/kit",
|
|
19
|
+
"project": {"number": 1, "owner": "example", "nodeId": "PVT_test"},
|
|
20
|
+
"fields": {
|
|
21
|
+
"status": {"id": "STATUS", "options": {}},
|
|
22
|
+
"wave": "WAVE",
|
|
23
|
+
"cluster": "CLUSTER",
|
|
24
|
+
"specPath": "SPEC",
|
|
25
|
+
"planPath": "PLAN",
|
|
26
|
+
},
|
|
27
|
+
"labels": {
|
|
28
|
+
"readyForAgent": "ready-for-agent",
|
|
29
|
+
"typePrefix": "type:",
|
|
30
|
+
"clusterType": "type:cluster",
|
|
31
|
+
"waveStub": "wave-stub",
|
|
32
|
+
},
|
|
33
|
+
"branchPrefixes": ["feat", "fix"],
|
|
34
|
+
"prMarkers": {"partOf": "Part of", "retroMarker": "Retro", "retroValues": []},
|
|
35
|
+
"headings": {"vorBau": "Clarify Before Build"},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def load_board_sync(profile_dict: dict, module_name: str):
|
|
40
|
+
with tempfile.NamedTemporaryFile("w", suffix=".md", delete=False) as profile:
|
|
41
|
+
profile.write("<!-- board-sync:profile -->\n```json\n")
|
|
42
|
+
json.dump(profile_dict, profile)
|
|
43
|
+
profile.write("\n```\n")
|
|
44
|
+
profile_path = profile.name
|
|
45
|
+
os.environ["BOARD_SYNC_PROFILE"] = profile_path
|
|
46
|
+
spec = importlib.util.spec_from_file_location(
|
|
47
|
+
module_name, Path(__file__).with_name("board-sync.py")
|
|
48
|
+
)
|
|
49
|
+
module = importlib.util.module_from_spec(spec)
|
|
50
|
+
assert spec.loader is not None
|
|
51
|
+
spec.loader.exec_module(module)
|
|
52
|
+
Path(profile_path).unlink()
|
|
53
|
+
return module
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class WaveTitleDefaultPrefix(unittest.TestCase):
|
|
57
|
+
"""A profile without `titles.wavePrefix` keeps the historical `Welle` prefix."""
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def setUpClass(cls):
|
|
61
|
+
cls.bs = load_board_sync(copy.deepcopy(BASE_PROFILE), "board_sync_wave_default")
|
|
62
|
+
|
|
63
|
+
def test_default_prefix_is_welle(self):
|
|
64
|
+
self.assertEqual(self.bs.wave_title("Auth hardening", 7), "Welle 7 — Auth hardening")
|
|
65
|
+
|
|
66
|
+
def test_repromote_is_idempotent(self):
|
|
67
|
+
self.assertEqual(
|
|
68
|
+
self.bs.wave_title("Welle 7 — Auth hardening", 9),
|
|
69
|
+
"Welle 9 — Auth hardening",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def test_conventional_prefix_stripped_before_wave(self):
|
|
73
|
+
self.assertEqual(
|
|
74
|
+
self.bs.wave_title("fix: Welle 7 — Auth hardening", 29),
|
|
75
|
+
"Welle 29 — Auth hardening",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class WaveTitleProfilePrefix(unittest.TestCase):
|
|
80
|
+
"""A profile with `titles.wavePrefix` drives the anchor title language."""
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def setUpClass(cls):
|
|
84
|
+
profile = copy.deepcopy(BASE_PROFILE)
|
|
85
|
+
profile["titles"] = {"wavePrefix": "Wave"}
|
|
86
|
+
cls.bs = load_board_sync(profile, "board_sync_wave_custom")
|
|
87
|
+
|
|
88
|
+
def test_configured_prefix_is_used(self):
|
|
89
|
+
self.assertEqual(self.bs.wave_title("Auth hardening", 7), "Wave 7 — Auth hardening")
|
|
90
|
+
|
|
91
|
+
def test_repromote_is_idempotent_for_configured_prefix(self):
|
|
92
|
+
self.assertEqual(
|
|
93
|
+
self.bs.wave_title("Wave 7 — Auth hardening", 9),
|
|
94
|
+
"Wave 9 — Auth hardening",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def test_regex_metacharacters_in_prefix_are_literal(self):
|
|
98
|
+
profile = copy.deepcopy(BASE_PROFILE)
|
|
99
|
+
profile["titles"] = {"wavePrefix": "W+A"}
|
|
100
|
+
bs = load_board_sync(profile, "board_sync_wave_meta")
|
|
101
|
+
self.assertEqual(
|
|
102
|
+
bs.wave_title("W+A 3 — Auth hardening", 4),
|
|
103
|
+
"W+A 4 — Auth hardening",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
unittest.main()
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""The shipped pre-commit template must sanitize git's hook environment.
|
|
3
|
+
|
|
4
|
+
Git exports GIT_DIR/GIT_INDEX_FILE to hooks; a consumer gate that runs a test
|
|
5
|
+
suite whose child tests call git in their own temp repos would otherwise
|
|
6
|
+
redirect those calls onto the host repo's index (PR #121's incident)."""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import unittest
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
TEMPLATE = (
|
|
14
|
+
Path(__file__).resolve().parent.parent
|
|
15
|
+
/ ".claude/skills/setup-pre-commit/scripts/pre-commit.template.sh"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class PreCommitTemplateSanitizesGitEnv(unittest.TestCase):
|
|
20
|
+
def test_template_unsets_git_env_before_gate(self):
|
|
21
|
+
text = TEMPLATE.read_text(encoding="utf-8")
|
|
22
|
+
unset_pos = text.find("unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_PREFIX")
|
|
23
|
+
gate_pos = text.find(">>> your gate commands here <<<")
|
|
24
|
+
self.assertGreater(unset_pos, -1, "template must unset git's exported hook env")
|
|
25
|
+
self.assertGreater(gate_pos, -1, "template must keep the gate marker")
|
|
26
|
+
self.assertLess(unset_pos, gate_pos, "sanitize must happen before the gate runs")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
unittest.main()
|
package/src/cli.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { update } from './commands/update.mjs';
|
|
|
7
7
|
import { diff } from './commands/diff.mjs';
|
|
8
8
|
import { uninstall } from './commands/uninstall.mjs';
|
|
9
9
|
import { createCommandAdapter } from '../scripts/release-state.mjs';
|
|
10
|
+
import { installedIdentityFromDir } from '../scripts/release-parity.mjs';
|
|
10
11
|
|
|
11
12
|
const KIT_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
12
13
|
const consumerRoot = process.cwd();
|
|
@@ -87,8 +88,10 @@ async function readUpdateRelease() {
|
|
|
87
88
|
env: { ...process.env, GH_REPO: 'iKon85/agent-workflow-kit' },
|
|
88
89
|
});
|
|
89
90
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
// Re-packing an unpacked install is never byte-identical to the registry
|
|
92
|
+
// tarball — the installed copy proves itself by content identity instead.
|
|
93
|
+
const installed = await installedIdentityFromDir(KIT_ROOT);
|
|
94
|
+
return { installed, npm: await adapter.npm(installed), github: await adapter.github(installed) };
|
|
92
95
|
} finally {
|
|
93
96
|
await adapter.dispose();
|
|
94
97
|
}
|
package/src/commands/update.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, rm } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { assertConsumerReleaseParity } from '../../scripts/release-parity.mjs';
|
|
4
4
|
import { activateCandidate, stageConsumer, verifyCandidate } from '../lib/updateCandidate.mjs';
|
|
5
5
|
import { reconcile } from '../lib/updateReconcile.mjs';
|
|
6
6
|
import {
|
|
@@ -86,7 +86,7 @@ async function applyTransaction(context) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
function verifyRelease(identities, kitVersion) {
|
|
89
|
-
const release =
|
|
89
|
+
const release = assertConsumerReleaseParity(identities);
|
|
90
90
|
if (release.name !== RELEASE_NAME) throw new Error(`invalid release origin: ${release.name}`);
|
|
91
91
|
if (release.version !== kitVersion) {
|
|
92
92
|
throw new Error(`release version ${release.version} does not match kit ${kitVersion}`);
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: zoom-out
|
|
3
|
-
description: "Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture."
|
|
4
|
-
disable-model-invocation: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary vocabulary. (For a full refactor/deepening pass with an HTML report and grilling loop, use `improve-codebase-architecture` instead.)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Third-Party Notices
|
|
2
|
-
|
|
3
|
-
This skill is adapted from **Matt Pocock's skills**
|
|
4
|
-
(https://github.com/mattpocock/skills), `skills/engineering/zoom-out` @ 2bf7005, Copyright (c) 2026 Matt Pocock,
|
|
5
|
-
used under the MIT License. Locally adapted (fork-and-own); see PROVENANCE.md.
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
MIT License
|
|
9
|
-
|
|
10
|
-
Copyright (c) 2026 Matt Pocock
|
|
11
|
-
|
|
12
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
-
in the Software without restriction, including without limitation the rights
|
|
15
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
-
furnished to do so, subject to the following conditions:
|
|
18
|
-
|
|
19
|
-
The above copyright notice and this permission notice shall be included in all
|
|
20
|
-
copies or substantial portions of the Software.
|
|
21
|
-
|
|
22
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
-
SOFTWARE.
|
|
29
|
-
```
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: zoom-out
|
|
3
|
-
description: Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture.
|
|
4
|
-
disable-model-invocation: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary vocabulary. (For a full refactor/deepening pass with an HTML report and grilling loop, use `improve-codebase-architecture` instead.)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Third-Party Notices
|
|
2
|
-
|
|
3
|
-
This skill is adapted from **Matt Pocock's skills**
|
|
4
|
-
(https://github.com/mattpocock/skills), `skills/engineering/zoom-out` @ 2bf7005, Copyright (c) 2026 Matt Pocock,
|
|
5
|
-
used under the MIT License. Locally adapted (fork-and-own); see PROVENANCE.md.
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
MIT License
|
|
9
|
-
|
|
10
|
-
Copyright (c) 2026 Matt Pocock
|
|
11
|
-
|
|
12
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
-
in the Software without restriction, including without limitation the rights
|
|
15
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
-
furnished to do so, subject to the following conditions:
|
|
18
|
-
|
|
19
|
-
The above copyright notice and this permission notice shall be included in all
|
|
20
|
-
copies or substantial portions of the Software.
|
|
21
|
-
|
|
22
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
-
SOFTWARE.
|
|
29
|
-
```
|