@ikon85/agent-workflow-kit 0.37.0 → 0.38.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/orchestrate-wave/SKILL.md +5 -5
- package/.agents/skills/setup-workflow/SKILL.md +8 -1
- package/.agents/skills/setup-workflow/worktree-lifecycle.md +18 -1
- package/.agents/skills/wrapup/SKILL.md +22 -0
- package/.claude/skills/orchestrate-wave/SKILL.md +5 -5
- package/.claude/skills/setup-workflow/SKILL.md +8 -1
- package/.claude/skills/setup-workflow/worktree-lifecycle.md +18 -1
- package/.claude/skills/wrapup/SKILL.md +22 -0
- package/README.md +36 -0
- package/agent-workflow-kit.package.json +24 -16
- package/docs/adr/0007-session-teardown-requires-provenance-bound-ownership.md +88 -0
- package/docs/agents/workflow-capabilities.json +11 -1
- package/package.json +1 -1
- package/scripts/test_orchestrate_wave_contract.py +9 -0
- package/scripts/test_worktree_wrapup_contract.py +1004 -3
- package/scripts/worktree-lifecycle/README.md +108 -0
- package/scripts/worktree-lifecycle/capabilities.json +9 -1
- package/scripts/worktree-lifecycle/cleanup.py +22 -51
- package/scripts/worktree-lifecycle/core.py +1054 -4
- package/scripts/worktree-lifecycle/profile.py +38 -3
- package/scripts/worktree-lifecycle/session.py +1857 -0
- package/scripts/worktree-lifecycle/setup.py +15 -0
- package/scripts/wrapup-land.py +314 -12
- package/src/lib/bundle.mjs +1 -0
|
@@ -141,7 +141,7 @@ replace the ~30-second heartbeat; otherwise the standing heartbeat remains requi
|
|
|
141
141
|
LOCAL annotated tag, so two sessions racing one wave cannot both win. Either
|
|
142
142
|
`acquired: false` or a work signal you did not create means another session
|
|
143
143
|
owns the wave — **STOP**, report the returned `claim.owner` plus the exact
|
|
144
|
-
branch/worktree, touch nothing.
|
|
144
|
+
branch/worktree, touch nothing. After acquisition, begin the claim-bound teardown receipt with `python3 scripts/worktree-lifecycle/session.py begin --anchor <anchor> --owner <claim-owner> --base <wave-HEAD>`; claim and receipt stay local — never push them.
|
|
145
145
|
4. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
|
|
146
146
|
points there). Bring its branch to current `main`:
|
|
147
147
|
`git -C <wave> merge --ff-only origin/main` (if your repo guards destructive
|
|
@@ -195,8 +195,8 @@ disjoint wave, conflict hub first. Dispatch only `FREI` slices: re-read
|
|
|
195
195
|
`frontier <anchor#>` before each wave and clear changed edges only via `dep-remove`.
|
|
196
196
|
Before each slice, bind **(a) inline vs delegate** and **(b) tier + effort** under
|
|
197
197
|
Standing rules. Tiny mechanical work may stay inline.
|
|
198
|
-
For Path A/B, create
|
|
199
|
-
`git worktree add
|
|
198
|
+
For Path A/B, create each new worktree through the active receipt: `python3 scripts/worktree-lifecycle/session.py create --anchor <anchor> --owner <claim-owner> --base <wave-HEAD> --profile <profile> <slice-issue> <slug> <type>`.
|
|
199
|
+
It refuses reused/pre-existing targets; never replace this ownership proof with raw `git worktree add`.
|
|
200
200
|
- **Claim each slice issue at builder launch — the wave claim is not a slice
|
|
201
201
|
claim.** It guards the anchor on this machine only; the slice issue is the
|
|
202
202
|
grabbable unit a second machine or cloud agent sees. Before dispatch, skip and
|
|
@@ -358,8 +358,8 @@ written · merge order documented.
|
|
|
358
358
|
- A skill edited during the wave → sync its dual-surface mirror in the SAME PR
|
|
359
359
|
using the tool named by `§Landing` when present; mirror parity remains a pre-PR
|
|
360
360
|
gate.
|
|
361
|
-
-
|
|
362
|
-
|
|
361
|
+
- After reading every `ANNAHMEN.md`, seal the receipt, inspect it against fetched canonical `main`, then run its `teardown`; only ancestry/one-to-one patch-equivalent exact owned OIDs are compare-deleted, while foreign targets, unique/ambiguous content, changed OIDs, dirty/protected worktrees, and open/unknown PR evidence stop.
|
|
362
|
+
- Keep the completed receipt as recovery-OID evidence; only then release this run's wave claim.
|
|
363
363
|
|
|
364
364
|
**Done when:** no orphan process · this run's wave claim removed · this run's
|
|
365
365
|
unlanded slice claims released · ANNAHMEN propagated ·
|
|
@@ -204,11 +204,15 @@ Worktree Lifecycle for this repository?"* Offer exactly **Yes**, **Later**, and
|
|
|
204
204
|
- **Yes** — create or deepen only the `worktreeLifecycle` section in
|
|
205
205
|
`docs/agents/workflow-capabilities.json`, preserve every other section and
|
|
206
206
|
unknown key, reconcile an explicit consumer-derived `scratchPatterns` array,
|
|
207
|
+
explicitly derive and review the consumer's
|
|
208
|
+
`wrapup.landingGeneratedArtifactPatterns` array from real landing outputs,
|
|
207
209
|
and reconcile only the exact kit-owned hook commands listed in the seed.
|
|
208
210
|
- **Later / No** — record the choice in the tracked profile without installing
|
|
209
211
|
hook wiring. Ordinary reruns do not ask again.
|
|
210
212
|
- **Existing** — adopt the current section and wiring without normalizing
|
|
211
|
-
consumer-owned values.
|
|
213
|
+
consumer-owned values. Preserve an existing landing-artifact policy
|
|
214
|
+
byte-for-byte; if it is missing, surface the explicit derivation decision and
|
|
215
|
+
do not write a default.
|
|
212
216
|
- **Disable** — remove only the exact kit-owned hook commands first, then set
|
|
213
217
|
`enabled: false`; retain the profile, setup policy, and unknown keys.
|
|
214
218
|
|
|
@@ -520,6 +524,9 @@ unknown consumer keys share this profile. Apply the transition and hook
|
|
|
520
524
|
ownership rules from [worktree-lifecycle.md](./worktree-lifecycle.md),
|
|
521
525
|
[workflow-advisories.md](./workflow-advisories.md), and
|
|
522
526
|
[safety-guardrails.md](./safety-guardrails.md) transactionally.
|
|
527
|
+
The landing-artifact policy is deletion authority: it is always an explicit
|
|
528
|
+
consumer-reviewed setup value, never an update-time default or an inference
|
|
529
|
+
from ignored paths.
|
|
523
530
|
|
|
524
531
|
For Memory Lifecycle, use only the deterministic setup helper from Section A5.
|
|
525
532
|
Do not copy templates with shell commands or edit the capability profile by
|
|
@@ -29,6 +29,7 @@ advisory, and safe cleanup policy as one unit.
|
|
|
29
29
|
"operations": [
|
|
30
30
|
"record-choice",
|
|
31
31
|
"reconcile-profile-enabled",
|
|
32
|
+
"reconcile-landing-artifact-policy",
|
|
32
33
|
"reconcile-hook-wiring"
|
|
33
34
|
]
|
|
34
35
|
},
|
|
@@ -50,7 +51,8 @@ advisory, and safe cleanup policy as one unit.
|
|
|
50
51
|
"state": "existing",
|
|
51
52
|
"choice": "yes",
|
|
52
53
|
"operations": [
|
|
53
|
-
"adopt-existing"
|
|
54
|
+
"adopt-existing",
|
|
55
|
+
"reconcile-landing-artifact-policy"
|
|
54
56
|
]
|
|
55
57
|
},
|
|
56
58
|
{
|
|
@@ -87,6 +89,21 @@ Derive its glob values from the consumer's ignored planning artefacts; an empty
|
|
|
87
89
|
array is valid. Existing values are consumer-owned and remain byte-identical on
|
|
88
90
|
adoption or rerun. Core never supplies filename defaults.
|
|
89
91
|
|
|
92
|
+
Also reconcile an explicit
|
|
93
|
+
`wrapup.landingGeneratedArtifactPatterns` array. Derive candidates from the
|
|
94
|
+
consumer's real landing commands and ignored outputs, show the exact list for
|
|
95
|
+
review, and write it only as part of that explicit setup decision. Never copy
|
|
96
|
+
another repository's values or infer deletion authority from `.gitignore`
|
|
97
|
+
alone. An empty array is valid. Existing configured values remain byte-identical.
|
|
98
|
+
If an existing enabled profile lacks the key, report one actionable setup
|
|
99
|
+
decision and leave the project layer unchanged until the consumer confirms the
|
|
100
|
+
derived list.
|
|
101
|
+
|
|
102
|
+
Patterns use repository-relative POSIX semantics: `*` stays within one segment,
|
|
103
|
+
while `**` crosses `/`; a leading `**/` also matches the repository root.
|
|
104
|
+
Thus `**/__pycache__/**` covers root and nested caches, while `dist-kit/*` does
|
|
105
|
+
not cover `dist-kit/a/b`.
|
|
106
|
+
|
|
90
107
|
The shipped read-only inventory is
|
|
91
108
|
`python3 scripts/worktree-lifecycle/cleanup.py sweep`. The same profile powers
|
|
92
109
|
its branch issue extraction and scratch-only cleanup verdicts.
|
|
@@ -105,6 +105,28 @@ One call covers: push → PR create/reuse (+ drift markers merged into the body)
|
|
|
105
105
|
|
|
106
106
|
STOP → diagnose in the main conversation, fix, re-run `land` (an already-merged PR resumes at teardown).
|
|
107
107
|
|
|
108
|
+
Before merge, the committed worktree policy only nominates exact landing
|
|
109
|
+
evidence. After merge, cleanup reloads `docs/agents/workflow-capabilities.json`
|
|
110
|
+
from canonical `origin/main`; only the identical merged, attempt-bound scratch
|
|
111
|
+
and generator policy authorizes each evidence path and deletion. A mismatch is
|
|
112
|
+
a hard STOP that preserves every file—never bypass it with the unmerged branch
|
|
113
|
+
profile.
|
|
114
|
+
|
|
115
|
+
Landing provenance has one explicit relinquish route. If the STOP names an
|
|
116
|
+
unfinished or drifted landing attempt and the ambiguous files cannot be restored
|
|
117
|
+
to their frozen identities, run:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
python3 scripts/wrapup-land.py land --branch "<branch>" --abandon-unfinished-attempt
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
This archives the started or frozen attempt receipt only. It deletes and claims
|
|
124
|
+
no files, works even when the older creation baseline is missing, and returns
|
|
125
|
+
before push, PR, or merge. The next `land` conservatively protects every current
|
|
126
|
+
matching path; classify or move those blockers first. Do not use relinquish for
|
|
127
|
+
an exact unchanged frozen attempt: a normal retry validates that evidence and
|
|
128
|
+
resumes deterministically.
|
|
129
|
+
|
|
108
130
|
### 6 · Post-merge (agent)
|
|
109
131
|
- **Sibling propagation:** for each `drift_markers` entry in the land report, append the note to the target issue's `vor_bau` section + re-stamp its `plan_revision`. Log-based markers → **write directly, then show what was written where** (mandatory report — visibility moved from a pre-gate into the report, decision 2026-07-06); fallback candidates the user hasn't confirmed yet → confirm first. Program context widens the target set to unbuilt wave-stubs/leaves and the Program-PRD itself — same append-only mechanism. **Exception:** appends to the Program-PRD or unbuilt wave-stubs do **not** re-stamp `plan_revision` — that stays reserved for structural wave-plan edits via the `to-waves` escalation path; a mere drift note must not stale-block published stubs.
|
|
110
132
|
- **Anchor close:** report says `anchor_complete: true` → `gh issue close <anchor> -c "Wave complete — all slices merged via PR #<pr>."` and verify board status Done. The guard keeps anchors away from every auto-close — this verified close is the only close path; without it the anchor stays silently open after the last slice. **Then re-run the upward propagation**: the land-time `program-sync` ran BEFORE this close, so on a wave-completing slice the Wellenplan still shows 🔄 and the Phasen-Gate stays unchecked — after the board shows Done, run `python3 scripts/board-sync.py program-sync <program-prd#>` once more (the report's `program_sync.program` names it; skip when the report says the parent is not a program). Board auto-rules can lag the close (Close→Done race) — verify Done first, that's what the token reads.
|
|
@@ -141,7 +141,7 @@ replace the ~30-second heartbeat; otherwise the standing heartbeat remains requi
|
|
|
141
141
|
LOCAL annotated tag, so two sessions racing one wave cannot both win. Either
|
|
142
142
|
`acquired: false` or a work signal you did not create means another session
|
|
143
143
|
owns the wave — **STOP**, report the returned `claim.owner` plus the exact
|
|
144
|
-
branch/worktree, touch nothing.
|
|
144
|
+
branch/worktree, touch nothing. After acquisition, begin the claim-bound teardown receipt with `python3 scripts/worktree-lifecycle/session.py begin --anchor <anchor> --owner <claim-owner> --base <wave-HEAD>`; claim and receipt stay local — never push them.
|
|
145
145
|
4. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
|
|
146
146
|
points there). Bring its branch to current `main`:
|
|
147
147
|
`git -C <wave> merge --ff-only origin/main` (if your repo guards destructive
|
|
@@ -195,8 +195,8 @@ disjoint wave, conflict hub first. Dispatch only `FREI` slices: re-read
|
|
|
195
195
|
`frontier <anchor#>` before each wave and clear changed edges only via `dep-remove`.
|
|
196
196
|
Before each slice, bind **(a) inline vs delegate** and **(b) tier + effort** under
|
|
197
197
|
Standing rules. Tiny mechanical work may stay inline.
|
|
198
|
-
For Path A/B, create
|
|
199
|
-
`git worktree add
|
|
198
|
+
For Path A/B, create each new worktree through the active receipt: `python3 scripts/worktree-lifecycle/session.py create --anchor <anchor> --owner <claim-owner> --base <wave-HEAD> --profile <profile> <slice-issue> <slug> <type>`.
|
|
199
|
+
It refuses reused/pre-existing targets; never replace this ownership proof with raw `git worktree add`.
|
|
200
200
|
- **Claim each slice issue at builder launch — the wave claim is not a slice
|
|
201
201
|
claim.** It guards the anchor on this machine only; the slice issue is the
|
|
202
202
|
grabbable unit a second machine or cloud agent sees. Before dispatch, skip and
|
|
@@ -358,8 +358,8 @@ written · merge order documented.
|
|
|
358
358
|
- A skill edited during the wave → sync its dual-surface mirror in the SAME PR
|
|
359
359
|
using the tool named by `§Landing` when present; mirror parity remains a pre-PR
|
|
360
360
|
gate.
|
|
361
|
-
-
|
|
362
|
-
|
|
361
|
+
- After reading every `ANNAHMEN.md`, seal the receipt, inspect it against fetched canonical `main`, then run its `teardown`; only ancestry/one-to-one patch-equivalent exact owned OIDs are compare-deleted, while foreign targets, unique/ambiguous content, changed OIDs, dirty/protected worktrees, and open/unknown PR evidence stop.
|
|
362
|
+
- Keep the completed receipt as recovery-OID evidence; only then release this run's wave claim.
|
|
363
363
|
|
|
364
364
|
**Done when:** no orphan process · this run's wave claim removed · this run's
|
|
365
365
|
unlanded slice claims released · ANNAHMEN propagated ·
|
|
@@ -204,11 +204,15 @@ Worktree Lifecycle for this repository?"* Offer exactly **Yes**, **Later**, and
|
|
|
204
204
|
- **Yes** — create or deepen only the `worktreeLifecycle` section in
|
|
205
205
|
`docs/agents/workflow-capabilities.json`, preserve every other section and
|
|
206
206
|
unknown key, reconcile an explicit consumer-derived `scratchPatterns` array,
|
|
207
|
+
explicitly derive and review the consumer's
|
|
208
|
+
`wrapup.landingGeneratedArtifactPatterns` array from real landing outputs,
|
|
207
209
|
and reconcile only the exact kit-owned hook commands listed in the seed.
|
|
208
210
|
- **Later / No** — record the choice in the tracked profile without installing
|
|
209
211
|
hook wiring. Ordinary reruns do not ask again.
|
|
210
212
|
- **Existing** — adopt the current section and wiring without normalizing
|
|
211
|
-
consumer-owned values.
|
|
213
|
+
consumer-owned values. Preserve an existing landing-artifact policy
|
|
214
|
+
byte-for-byte; if it is missing, surface the explicit derivation decision and
|
|
215
|
+
do not write a default.
|
|
212
216
|
- **Disable** — remove only the exact kit-owned hook commands first, then set
|
|
213
217
|
`enabled: false`; retain the profile, setup policy, and unknown keys.
|
|
214
218
|
|
|
@@ -520,6 +524,9 @@ unknown consumer keys share this profile. Apply the transition and hook
|
|
|
520
524
|
ownership rules from [worktree-lifecycle.md](./worktree-lifecycle.md),
|
|
521
525
|
[workflow-advisories.md](./workflow-advisories.md), and
|
|
522
526
|
[safety-guardrails.md](./safety-guardrails.md) transactionally.
|
|
527
|
+
The landing-artifact policy is deletion authority: it is always an explicit
|
|
528
|
+
consumer-reviewed setup value, never an update-time default or an inference
|
|
529
|
+
from ignored paths.
|
|
523
530
|
|
|
524
531
|
For Memory Lifecycle, use only the deterministic setup helper from Section A5.
|
|
525
532
|
Do not copy templates with shell commands or edit the capability profile by
|
|
@@ -29,6 +29,7 @@ advisory, and safe cleanup policy as one unit.
|
|
|
29
29
|
"operations": [
|
|
30
30
|
"record-choice",
|
|
31
31
|
"reconcile-profile-enabled",
|
|
32
|
+
"reconcile-landing-artifact-policy",
|
|
32
33
|
"reconcile-hook-wiring"
|
|
33
34
|
]
|
|
34
35
|
},
|
|
@@ -50,7 +51,8 @@ advisory, and safe cleanup policy as one unit.
|
|
|
50
51
|
"state": "existing",
|
|
51
52
|
"choice": "yes",
|
|
52
53
|
"operations": [
|
|
53
|
-
"adopt-existing"
|
|
54
|
+
"adopt-existing",
|
|
55
|
+
"reconcile-landing-artifact-policy"
|
|
54
56
|
]
|
|
55
57
|
},
|
|
56
58
|
{
|
|
@@ -87,6 +89,21 @@ Derive its glob values from the consumer's ignored planning artefacts; an empty
|
|
|
87
89
|
array is valid. Existing values are consumer-owned and remain byte-identical on
|
|
88
90
|
adoption or rerun. Core never supplies filename defaults.
|
|
89
91
|
|
|
92
|
+
Also reconcile an explicit
|
|
93
|
+
`wrapup.landingGeneratedArtifactPatterns` array. Derive candidates from the
|
|
94
|
+
consumer's real landing commands and ignored outputs, show the exact list for
|
|
95
|
+
review, and write it only as part of that explicit setup decision. Never copy
|
|
96
|
+
another repository's values or infer deletion authority from `.gitignore`
|
|
97
|
+
alone. An empty array is valid. Existing configured values remain byte-identical.
|
|
98
|
+
If an existing enabled profile lacks the key, report one actionable setup
|
|
99
|
+
decision and leave the project layer unchanged until the consumer confirms the
|
|
100
|
+
derived list.
|
|
101
|
+
|
|
102
|
+
Patterns use repository-relative POSIX semantics: `*` stays within one segment,
|
|
103
|
+
while `**` crosses `/`; a leading `**/` also matches the repository root.
|
|
104
|
+
Thus `**/__pycache__/**` covers root and nested caches, while `dist-kit/*` does
|
|
105
|
+
not cover `dist-kit/a/b`.
|
|
106
|
+
|
|
90
107
|
The shipped read-only inventory is
|
|
91
108
|
`python3 scripts/worktree-lifecycle/cleanup.py sweep`. The same profile powers
|
|
92
109
|
its branch issue extraction and scratch-only cleanup verdicts.
|
|
@@ -105,6 +105,28 @@ One call covers: push → PR create/reuse (+ drift markers merged into the body)
|
|
|
105
105
|
|
|
106
106
|
STOP → diagnose in the main conversation, fix, re-run `land` (an already-merged PR resumes at teardown).
|
|
107
107
|
|
|
108
|
+
Before merge, the committed worktree policy only nominates exact landing
|
|
109
|
+
evidence. After merge, cleanup reloads `docs/agents/workflow-capabilities.json`
|
|
110
|
+
from canonical `origin/main`; only the identical merged, attempt-bound scratch
|
|
111
|
+
and generator policy authorizes each evidence path and deletion. A mismatch is
|
|
112
|
+
a hard STOP that preserves every file—never bypass it with the unmerged branch
|
|
113
|
+
profile.
|
|
114
|
+
|
|
115
|
+
Landing provenance has one explicit relinquish route. If the STOP names an
|
|
116
|
+
unfinished or drifted landing attempt and the ambiguous files cannot be restored
|
|
117
|
+
to their frozen identities, run:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
python3 scripts/wrapup-land.py land --branch "<branch>" --abandon-unfinished-attempt
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
This archives the started or frozen attempt receipt only. It deletes and claims
|
|
124
|
+
no files, works even when the older creation baseline is missing, and returns
|
|
125
|
+
before push, PR, or merge. The next `land` conservatively protects every current
|
|
126
|
+
matching path; classify or move those blockers first. Do not use relinquish for
|
|
127
|
+
an exact unchanged frozen attempt: a normal retry validates that evidence and
|
|
128
|
+
resumes deterministically.
|
|
129
|
+
|
|
108
130
|
### 6 · Post-merge (agent)
|
|
109
131
|
- **Sibling propagation:** for each `drift_markers` entry in the land report, append the note to the target issue's `vor_bau` section + re-stamp its `plan_revision`. Log-based markers → **write directly, then show what was written where** (mandatory report — visibility moved from a pre-gate into the report, decision 2026-07-06); fallback candidates the user hasn't confirmed yet → confirm first. Program context widens the target set to unbuilt wave-stubs/leaves and the Program-PRD itself — same append-only mechanism. **Exception:** appends to the Program-PRD or unbuilt wave-stubs do **not** re-stamp `plan_revision` — that stays reserved for structural wave-plan edits via the `to-waves` escalation path; a mere drift note must not stale-block published stubs.
|
|
110
132
|
- **Anchor close:** report says `anchor_complete: true` → `gh issue close <anchor> -c "Wave complete — all slices merged via PR #<pr>."` and verify board status Done. The guard keeps anchors away from every auto-close — this verified close is the only close path; without it the anchor stays silently open after the last slice. **Then re-run the upward propagation**: the land-time `program-sync` ran BEFORE this close, so on a wave-completing slice the Wellenplan still shows 🔄 and the Phasen-Gate stays unchecked — after the board shows Done, run `python3 scripts/board-sync.py program-sync <program-prd#>` once more (the report's `program_sync.program` names it; skip when the report says the parent is not a program). Board auto-rules can lag the close (Close→Done race) — verify Done first, that's what the token reads.
|
package/README.md
CHANGED
|
@@ -425,6 +425,15 @@ Explicit fork with its own identity and update line instead.
|
|
|
425
425
|
|
|
426
426
|
## Upgrade notes
|
|
427
427
|
|
|
428
|
+
### 0.38.0 — explicit landing-artifact policy
|
|
429
|
+
|
|
430
|
+
Existing consumers must run `setup-workflow` once after `kit-update`, review
|
|
431
|
+
the generated `wrapup.landingGeneratedArtifactPatterns` decision in
|
|
432
|
+
`docs/agents/workflow-capabilities.json`, and commit that profile change.
|
|
433
|
+
Until the explicit policy is committed, `wrapup-land` fails closed before
|
|
434
|
+
landing instead of assuming that no generated artifact is eligible for
|
|
435
|
+
session-owned cleanup.
|
|
436
|
+
|
|
428
437
|
### 0.33.0 — capability-gated orchestration
|
|
429
438
|
|
|
430
439
|
`kit-update` reconciles this release for you. These notes matter only if you
|
|
@@ -454,6 +463,33 @@ the old way. Decision record:
|
|
|
454
463
|
|
|
455
464
|
## Release notes
|
|
456
465
|
|
|
466
|
+
### 0.38.0
|
|
467
|
+
|
|
468
|
+
- added: `docs/adr/0007-session-teardown-requires-provenance-bound-ownership.md`
|
|
469
|
+
- added: `scripts/worktree-lifecycle/session.py`
|
|
470
|
+
- changed: `.agents/skills/orchestrate-wave/SKILL.md`
|
|
471
|
+
- changed: `.agents/skills/setup-workflow/SKILL.md`
|
|
472
|
+
- changed: `.agents/skills/setup-workflow/worktree-lifecycle.md`
|
|
473
|
+
- changed: `.agents/skills/wrapup/SKILL.md`
|
|
474
|
+
- changed: `.claude/skills/orchestrate-wave/SKILL.md`
|
|
475
|
+
- changed: `.claude/skills/setup-workflow/SKILL.md`
|
|
476
|
+
- changed: `.claude/skills/setup-workflow/worktree-lifecycle.md`
|
|
477
|
+
- changed: `.claude/skills/wrapup/SKILL.md`
|
|
478
|
+
- changed: `README.md`
|
|
479
|
+
- changed: `agent-workflow-kit.package.json`
|
|
480
|
+
- changed: `docs/agents/workflow-capabilities.json`
|
|
481
|
+
- changed: `package.json`
|
|
482
|
+
- changed: `scripts/test_orchestrate_wave_contract.py`
|
|
483
|
+
- changed: `scripts/test_worktree_wrapup_contract.py`
|
|
484
|
+
- changed: `scripts/worktree-lifecycle/README.md`
|
|
485
|
+
- changed: `scripts/worktree-lifecycle/capabilities.json`
|
|
486
|
+
- changed: `scripts/worktree-lifecycle/cleanup.py`
|
|
487
|
+
- changed: `scripts/worktree-lifecycle/core.py`
|
|
488
|
+
- changed: `scripts/worktree-lifecycle/profile.py`
|
|
489
|
+
- changed: `scripts/worktree-lifecycle/setup.py`
|
|
490
|
+
- changed: `scripts/wrapup-land.py`
|
|
491
|
+
- changed: `src/lib/bundle.mjs`
|
|
492
|
+
|
|
457
493
|
### 0.37.0
|
|
458
494
|
|
|
459
495
|
- added: `scripts/test_anchor_table.py`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"kitVersion": "0.
|
|
2
|
+
"kitVersion": "0.38.0",
|
|
3
3
|
"files": [
|
|
4
4
|
{
|
|
5
5
|
"path": ".agents/skills/ask-matt/SKILL.md",
|
|
@@ -447,7 +447,7 @@
|
|
|
447
447
|
"ownerSkill": "orchestrate-wave",
|
|
448
448
|
"surface": "codex",
|
|
449
449
|
"installRole": "consumer",
|
|
450
|
-
"sha256": "
|
|
450
|
+
"sha256": "02862cd5e7e07a5f06dad89792fcebd0a6c17cf2216a27c7e0f724026fdda53a",
|
|
451
451
|
"mode": 420,
|
|
452
452
|
"origin": "kit"
|
|
453
453
|
},
|
|
@@ -687,7 +687,7 @@
|
|
|
687
687
|
"ownerSkill": "setup-workflow",
|
|
688
688
|
"surface": "codex",
|
|
689
689
|
"installRole": "consumer",
|
|
690
|
-
"sha256": "
|
|
690
|
+
"sha256": "a5733b71f9257f0999c866bfdea551aedf4b9066572bd484fc263440cb292ca6",
|
|
691
691
|
"mode": 420,
|
|
692
692
|
"origin": "kit"
|
|
693
693
|
},
|
|
@@ -757,7 +757,7 @@
|
|
|
757
757
|
"ownerSkill": "setup-workflow",
|
|
758
758
|
"surface": "codex",
|
|
759
759
|
"installRole": "consumer",
|
|
760
|
-
"sha256": "
|
|
760
|
+
"sha256": "e53e6b37bdfdfb0014e2e7ad8fe84cfc2af302eb1a9c6e9e682b1eec05036f1e",
|
|
761
761
|
"mode": 420,
|
|
762
762
|
"origin": "kit"
|
|
763
763
|
},
|
|
@@ -997,7 +997,7 @@
|
|
|
997
997
|
"ownerSkill": "wrapup",
|
|
998
998
|
"surface": "codex",
|
|
999
999
|
"installRole": "consumer",
|
|
1000
|
-
"sha256": "
|
|
1000
|
+
"sha256": "2f84b787b81b6f63ebda996a648a6a32c0c79c5894d6471f84250c0f2a24a2c3",
|
|
1001
1001
|
"mode": 420,
|
|
1002
1002
|
"origin": "kit"
|
|
1003
1003
|
},
|
|
@@ -1769,7 +1769,7 @@
|
|
|
1769
1769
|
"ownerSkill": "orchestrate-wave",
|
|
1770
1770
|
"surface": "claude",
|
|
1771
1771
|
"installRole": "consumer",
|
|
1772
|
-
"sha256": "
|
|
1772
|
+
"sha256": "02862cd5e7e07a5f06dad89792fcebd0a6c17cf2216a27c7e0f724026fdda53a",
|
|
1773
1773
|
"mode": 420,
|
|
1774
1774
|
"origin": "kit"
|
|
1775
1775
|
},
|
|
@@ -2029,7 +2029,7 @@
|
|
|
2029
2029
|
"ownerSkill": "setup-workflow",
|
|
2030
2030
|
"surface": "claude",
|
|
2031
2031
|
"installRole": "consumer",
|
|
2032
|
-
"sha256": "
|
|
2032
|
+
"sha256": "a5733b71f9257f0999c866bfdea551aedf4b9066572bd484fc263440cb292ca6",
|
|
2033
2033
|
"mode": 420,
|
|
2034
2034
|
"origin": "kit"
|
|
2035
2035
|
},
|
|
@@ -2099,7 +2099,7 @@
|
|
|
2099
2099
|
"ownerSkill": "setup-workflow",
|
|
2100
2100
|
"surface": "claude",
|
|
2101
2101
|
"installRole": "consumer",
|
|
2102
|
-
"sha256": "
|
|
2102
|
+
"sha256": "e53e6b37bdfdfb0014e2e7ad8fe84cfc2af302eb1a9c6e9e682b1eec05036f1e",
|
|
2103
2103
|
"mode": 420,
|
|
2104
2104
|
"origin": "kit"
|
|
2105
2105
|
},
|
|
@@ -2347,7 +2347,7 @@
|
|
|
2347
2347
|
"ownerSkill": "wrapup",
|
|
2348
2348
|
"surface": "claude",
|
|
2349
2349
|
"installRole": "consumer",
|
|
2350
|
-
"sha256": "
|
|
2350
|
+
"sha256": "2f84b787b81b6f63ebda996a648a6a32c0c79c5894d6471f84250c0f2a24a2c3",
|
|
2351
2351
|
"mode": 420,
|
|
2352
2352
|
"origin": "kit"
|
|
2353
2353
|
},
|
|
@@ -2779,7 +2779,7 @@
|
|
|
2779
2779
|
"path": "scripts/worktree-lifecycle/capabilities.json",
|
|
2780
2780
|
"kind": "doc",
|
|
2781
2781
|
"installRole": "consumer",
|
|
2782
|
-
"sha256": "
|
|
2782
|
+
"sha256": "689910f11b51a5f2938989a82378332375e614f2684fe4cc48db7a4ce5c12f4b",
|
|
2783
2783
|
"mode": 420,
|
|
2784
2784
|
"origin": "kit"
|
|
2785
2785
|
},
|
|
@@ -2787,7 +2787,7 @@
|
|
|
2787
2787
|
"path": "scripts/worktree-lifecycle/cleanup.py",
|
|
2788
2788
|
"kind": "script",
|
|
2789
2789
|
"installRole": "consumer",
|
|
2790
|
-
"sha256": "
|
|
2790
|
+
"sha256": "4671aa6d40590abe103509916abda34e1717b43f7f0f521fc7fe90e1e29be50d",
|
|
2791
2791
|
"mode": 493,
|
|
2792
2792
|
"origin": "kit"
|
|
2793
2793
|
},
|
|
@@ -2795,7 +2795,7 @@
|
|
|
2795
2795
|
"path": "scripts/worktree-lifecycle/core.py",
|
|
2796
2796
|
"kind": "script",
|
|
2797
2797
|
"installRole": "consumer",
|
|
2798
|
-
"sha256": "
|
|
2798
|
+
"sha256": "a869ecc4646fc3493b883521594c3976e53b9b896d1361c87e1085adea10052c",
|
|
2799
2799
|
"mode": 420,
|
|
2800
2800
|
"origin": "kit"
|
|
2801
2801
|
},
|
|
@@ -2803,7 +2803,7 @@
|
|
|
2803
2803
|
"path": "scripts/worktree-lifecycle/profile.py",
|
|
2804
2804
|
"kind": "script",
|
|
2805
2805
|
"installRole": "consumer",
|
|
2806
|
-
"sha256": "
|
|
2806
|
+
"sha256": "4a76462e4a9f7c4c3fd1b199217f8c68b9946c49bc934eef7bc888244bdbd16f",
|
|
2807
2807
|
"mode": 420,
|
|
2808
2808
|
"origin": "kit"
|
|
2809
2809
|
},
|
|
@@ -2811,15 +2811,23 @@
|
|
|
2811
2811
|
"path": "scripts/worktree-lifecycle/README.md",
|
|
2812
2812
|
"kind": "doc",
|
|
2813
2813
|
"installRole": "consumer",
|
|
2814
|
-
"sha256": "
|
|
2814
|
+
"sha256": "55c62d00f84e5a1e008d059dc1aad2e026f35dab25437e5cb3c53b717d621a06",
|
|
2815
2815
|
"mode": 420,
|
|
2816
2816
|
"origin": "kit"
|
|
2817
2817
|
},
|
|
2818
|
+
{
|
|
2819
|
+
"path": "scripts/worktree-lifecycle/session.py",
|
|
2820
|
+
"kind": "script",
|
|
2821
|
+
"installRole": "consumer",
|
|
2822
|
+
"sha256": "18c2794aaf9fef96a15000c515b600345d3bf1715e23b07d0646156e601ea35a",
|
|
2823
|
+
"mode": 493,
|
|
2824
|
+
"origin": "kit"
|
|
2825
|
+
},
|
|
2818
2826
|
{
|
|
2819
2827
|
"path": "scripts/worktree-lifecycle/setup.py",
|
|
2820
2828
|
"kind": "script",
|
|
2821
2829
|
"installRole": "consumer",
|
|
2822
|
-
"sha256": "
|
|
2830
|
+
"sha256": "fa84d0056b24263389e0d17746abc8dc0afbd0152c323a62a6d7590ca9c62cac",
|
|
2823
2831
|
"mode": 493,
|
|
2824
2832
|
"origin": "kit"
|
|
2825
2833
|
},
|
|
@@ -2827,7 +2835,7 @@
|
|
|
2827
2835
|
"path": "scripts/wrapup-land.py",
|
|
2828
2836
|
"kind": "script",
|
|
2829
2837
|
"installRole": "consumer",
|
|
2830
|
-
"sha256": "
|
|
2838
|
+
"sha256": "f92779efab05fb17447abf47b8aec3fab6a501eff8e11735c245e5f615f9e460",
|
|
2831
2839
|
"mode": 493,
|
|
2832
2840
|
"origin": "kit"
|
|
2833
2841
|
},
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Session teardown requires provenance-bound ownership
|
|
2
|
+
|
|
3
|
+
Status: accepted (2026-07-26, Wave #271)
|
|
4
|
+
|
|
5
|
+
Long agent sessions create branches, linked worktrees, setup outputs, and
|
|
6
|
+
landing-time build artifacts. The desired end state is that every
|
|
7
|
+
provenance-captured target created by that session can be removed, including
|
|
8
|
+
branches whose changes reached
|
|
9
|
+
canonical `main` through patch-equivalent commits rather than ancestry.
|
|
10
|
+
|
|
11
|
+
Repository state alone cannot identify that ownership safely. A foreign branch
|
|
12
|
+
can have the same name or patch, a user file can match a generated-artifact
|
|
13
|
+
pattern, and a path can be replaced between assessment and deletion. Retrying
|
|
14
|
+
after a crash adds a time dimension: a fresh snapshot cannot distinguish an
|
|
15
|
+
earlier generator output from a file created by the user between attempts.
|
|
16
|
+
|
|
17
|
+
We decided that teardown authority must come from **Teardown provenance**, not
|
|
18
|
+
from present-day similarity:
|
|
19
|
+
|
|
20
|
+
1. A session records intent before creation, but receives cleanup authority only
|
|
21
|
+
through an atomic **Ownership proof**. Branch and proof ref are acquired in
|
|
22
|
+
one Git transaction bound to the active wave claim.
|
|
23
|
+
2. Setup, session work, and landing are separate provenance boundaries. Setup
|
|
24
|
+
and session cleanup use the worktree-creation baseline; landing cleanup uses
|
|
25
|
+
a persisted landing-attempt boundary and freezes the exact outputs of its
|
|
26
|
+
generator-capable step.
|
|
27
|
+
3. Paths and patterns select candidates but never prove identity. Cleanup binds
|
|
28
|
+
regular files and worktree roots to no-follow object evidence and revalidates
|
|
29
|
+
that evidence immediately before mutation.
|
|
30
|
+
4. The **Lifecycle receipt** is a durably replaced state-transition journal.
|
|
31
|
+
Prepared Git ref transactions close the worktree-removal race, and committed
|
|
32
|
+
intermediate states make known outcomes resumable. An external SIGKILL may
|
|
33
|
+
still leave Git's own lock files requiring operator recovery.
|
|
34
|
+
5. Lost evidence is not reconstructed from coincidence. An interrupted landing
|
|
35
|
+
attempt without frozen outputs can be archived without claiming or deleting
|
|
36
|
+
its files, after which the ambiguous files must be classified before a new
|
|
37
|
+
attempt proceeds.
|
|
38
|
+
|
|
39
|
+
## Considered options
|
|
40
|
+
|
|
41
|
+
- **Delete branches merged by ancestry:** rejected because squash,
|
|
42
|
+
cherry-pick, and patch-equivalent integration leave session-owned branch refs
|
|
43
|
+
outside ancestry.
|
|
44
|
+
- **Treat a receipt row as ownership:** rejected because another process can
|
|
45
|
+
create the named branch or worktree after the absence check but before the
|
|
46
|
+
attempted creation.
|
|
47
|
+
- **Authorize files by ignored path or generator pattern:** rejected because a
|
|
48
|
+
consumer file can occupy the same path before landing or replace an assessed
|
|
49
|
+
output afterward.
|
|
50
|
+
- **Take a fresh landing snapshot on every retry:** rejected because it protects
|
|
51
|
+
prior generator outputs as if they predated landing, while a persistent start
|
|
52
|
+
snapshot alone incorrectly claims every later matching user file.
|
|
53
|
+
- **Force-remove apparently clean targets:** rejected because force bypasses the
|
|
54
|
+
repository and filesystem evidence that distinguishes owned work from foreign
|
|
55
|
+
work.
|
|
56
|
+
- **Guess ownership after an unjournaled crash window:** rejected because safe
|
|
57
|
+
cleanup and guaranteed automatic liveness cannot both be recovered after the
|
|
58
|
+
distinguishing evidence is lost.
|
|
59
|
+
|
|
60
|
+
## Consequences
|
|
61
|
+
|
|
62
|
+
- A completed session can remove its exact worktrees, branches, proof refs, and
|
|
63
|
+
provenance-captured generated artifacts without hiding history or sweeping
|
|
64
|
+
unrelated repository state.
|
|
65
|
+
- Foreign branches, worktrees, replacement symlinks, replacements, late writes,
|
|
66
|
+
and pre-landing consumer files are hard stops or remain outside cleanup
|
|
67
|
+
authority. Setup recovery may remove only a symlink whose exact no-follow
|
|
68
|
+
identity it captured as setup-created.
|
|
69
|
+
- Exact unchanged frozen evidence is deterministically resumable. Started or
|
|
70
|
+
drifted frozen attempts can be explicitly relinquished by archiving only the
|
|
71
|
+
receipt; every current file then remains protected and must be classified
|
|
72
|
+
before another attempt.
|
|
73
|
+
- Provenance-less legacy worktrees receive only a conservative baseline after
|
|
74
|
+
exact registration, no-follow root, attached branch, and clean tracked/index
|
|
75
|
+
checks. Setup reuse defers backfill while tracked work or current
|
|
76
|
+
landing-generated blockers remain. Landing classifies those blockers before
|
|
77
|
+
writing evidence; after they are moved, all remaining current ignored and
|
|
78
|
+
untracked files become protected. Corrupt evidence and active attempts are
|
|
79
|
+
never backfilled.
|
|
80
|
+
- Before merge, a committed worktree policy may nominate only exact,
|
|
81
|
+
identity-bound cleanup candidates; it authorizes no deletion. After merge,
|
|
82
|
+
the profile is reloaded directly from canonical `origin/main` and must match
|
|
83
|
+
both the candidate and attempt-bound policy digest before any mutation.
|
|
84
|
+
Generator evidence is also reauthorized path-by-path against that canonical
|
|
85
|
+
policy. Missing policy, an unmerged widening, or branch/canonical drift
|
|
86
|
+
preserves every file.
|
|
87
|
+
- The lifecycle implementation is necessarily a small transaction protocol,
|
|
88
|
+
with more states and race tests than a path-based cleanup script.
|
|
@@ -7,12 +7,22 @@
|
|
|
7
7
|
"branchRegex": "^(?:feat|fix|chore|docs)/(?P<issue>\\d+)-",
|
|
8
8
|
"mainBranches": ["main"],
|
|
9
9
|
"protectedBranches": ["main"],
|
|
10
|
-
"scratchPatterns": [
|
|
10
|
+
"scratchPatterns": [
|
|
11
|
+
"PLAN.md",
|
|
12
|
+
"PLAN-REVIEW-LOG.md",
|
|
13
|
+
".claude/logs/**"
|
|
14
|
+
],
|
|
11
15
|
"setupEntry": "python3 scripts/worktree-lifecycle/setup.py",
|
|
12
16
|
"setupSteps": [],
|
|
13
17
|
"riskyCommandPatterns": [
|
|
14
18
|
"\\b(?:npm|pnpm|yarn)\\s+(?:run\\s+)?(?:test|typecheck|build)\\b",
|
|
15
19
|
"\\bgit\\s+(?:commit|push)\\b"
|
|
16
20
|
]
|
|
21
|
+
},
|
|
22
|
+
"wrapup": {
|
|
23
|
+
"landingGeneratedArtifactPatterns": [
|
|
24
|
+
"dist-kit/**",
|
|
25
|
+
"**/__pycache__/**"
|
|
26
|
+
]
|
|
17
27
|
}
|
|
18
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikon85/agent-workflow-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.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": {
|
|
@@ -95,6 +95,15 @@ BEHAVIORAL_PARITY = {
|
|
|
95
95
|
"Program-PRD",
|
|
96
96
|
"program sync",
|
|
97
97
|
),
|
|
98
|
+
"session-owned teardown": (
|
|
99
|
+
"session.py begin",
|
|
100
|
+
"session.py create",
|
|
101
|
+
"refuses reused/pre-existing targets",
|
|
102
|
+
"seal the receipt",
|
|
103
|
+
"compare-deleted",
|
|
104
|
+
"foreign targets",
|
|
105
|
+
"recovery-OID evidence",
|
|
106
|
+
),
|
|
98
107
|
"program authorization continuity": (
|
|
99
108
|
"explicit whole-Program mandate",
|
|
100
109
|
"all planned Waves",
|