@ikon85/agent-workflow-kit 0.38.0 → 0.40.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/grill-me/SKILL.md +1 -1
- package/.agents/skills/grill-with-docs/SKILL.md +1 -1
- package/.agents/skills/kit-update/SKILL.md +33 -1
- package/.agents/skills/orchestrate-wave/SKILL.md +4 -4
- package/.agents/skills/setup-workflow/SKILL.md +84 -3
- package/.agents/skills/setup-workflow/board-sync.md +6 -2
- package/.agents/skills/setup-workflow/workflow-advisories.md +34 -0
- package/.agents/skills/setup-workflow/worktree-lifecycle.md +54 -3
- package/.agents/skills/wrapup/SKILL.md +24 -0
- package/.claude/hooks/drift-guard.py +212 -21
- package/.claude/skills/grill-me/SKILL.md +1 -1
- package/.claude/skills/grill-with-docs/SKILL.md +1 -1
- package/.claude/skills/kit-update/SKILL.md +33 -1
- package/.claude/skills/orchestrate-wave/SKILL.md +4 -4
- package/.claude/skills/setup-workflow/SKILL.md +84 -3
- package/.claude/skills/setup-workflow/board-sync.md +6 -2
- package/.claude/skills/setup-workflow/workflow-advisories.md +34 -0
- package/.claude/skills/setup-workflow/worktree-lifecycle.md +54 -3
- package/.claude/skills/wrapup/SKILL.md +24 -0
- package/README.md +62 -0
- package/agent-workflow-kit.package.json +57 -25
- package/docs/adr/0008-planning-ignore-rules-are-offered-never-installed.md +84 -0
- package/package.json +1 -1
- package/scripts/board_bootstrap.py +367 -0
- package/scripts/kit-update-pr.mjs +20 -7
- package/scripts/kit-update-pr.test.mjs +29 -0
- package/scripts/profile_globs.py +347 -0
- package/scripts/test_board_bootstrap.py +348 -0
- package/scripts/test_drift_guard_diagnostics.py +295 -0
- package/scripts/test_profile_globs.py +280 -0
- package/scripts/test_skill_setup_workflow_seeds.py +87 -0
- package/scripts/test_worktree_ignore_seed.py +320 -0
- package/scripts/test_worktree_wrapup_contract.py +588 -0
- package/scripts/workflow-advisories/core.py +29 -4
- package/scripts/worktree-lifecycle/README.md +53 -4
- package/scripts/worktree-lifecycle/core.py +211 -60
- package/scripts/worktree-lifecycle/ignore_seed.py +226 -0
- package/scripts/worktree-lifecycle/plan-artifacts.json +37 -0
- package/scripts/wrapup-land.py +179 -34
- package/src/cli.mjs +32 -1
- package/src/commands/update.mjs +30 -21
- package/src/consumer-migrations.json +19 -0
- package/src/lib/bundle.mjs +16 -0
- package/src/lib/consumerMigrations.mjs +161 -0
|
@@ -52,7 +52,7 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
|
|
|
52
52
|
|
|
53
53
|
## Plan-lock — writing PLAN.md
|
|
54
54
|
|
|
55
|
-
Once all decisions are made (plan locked, before sign-off/handoff) and the session runs in a **worktree** → write the locked plan as `PLAN.md` to the worktree root
|
|
55
|
+
Once all decisions are made (plan locked, before sign-off/handoff) and the session runs in a **worktree** → write the locked plan as `PLAN.md` to the worktree root. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule (consistent with CLAUDE.md "plan inside the worktree"). This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work **without** a worktree stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
|
|
56
56
|
|
|
57
57
|
## Re-grill reconcile — execute-ready (Wave 26)
|
|
58
58
|
|
|
@@ -40,7 +40,7 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
|
|
|
40
40
|
|
|
41
41
|
## Plan-lock — writing PLAN.md
|
|
42
42
|
|
|
43
|
-
Once all decisions are made (plan locked, before sign-off/handoff) and the session runs in a **worktree** → write the locked plan as `PLAN.md` to the worktree root
|
|
43
|
+
Once all decisions are made (plan locked, before sign-off/handoff) and the session runs in a **worktree** → write the locked plan as `PLAN.md` to the worktree root. `PLAN.md` is **expected** to be ignored by git so it never travels over git — the kit never edits your `.gitignore` by itself, but `/setup-workflow` offers to add that rule (consistent with CLAUDE.md "plan inside the worktree"). This way the locked plan survives a session cut and `to-prd` finds its default source. Continuing same-session work **without** a worktree stays allowed (conversation = source); but for a deliberate **session cut** before `to-prd`, `PLAN.md` is mandatory. (The `-codex` variant already writes `PLAN.md` anyway.)
|
|
44
44
|
|
|
45
45
|
</plan-lock>
|
|
46
46
|
|
|
@@ -105,6 +105,19 @@ release contain the same artifact.
|
|
|
105
105
|
and safe routes—never file content. Automated update pull
|
|
106
106
|
requests carry the same availability summary and remain manual-merge only.
|
|
107
107
|
|
|
108
|
+
Read the required consumer migrations alongside the file delta. A release
|
|
109
|
+
that forces the Consumer to commit a decision registers it as declarative,
|
|
110
|
+
versioned data in the Kit's migration registry — never as release-note prose.
|
|
111
|
+
Preview and the terminal report expose the same structured record, so an
|
|
112
|
+
interactive run, a `--yes` run, `update --json`, and the automated update
|
|
113
|
+
pull request all name the same outstanding actions. Each action names the
|
|
114
|
+
workflow that resolves it, the Consumer file that carries the decision, and
|
|
115
|
+
the exact missing decision. `kit-update` only detects and reports it: it
|
|
116
|
+
never writes the decision, never infers a value, and never invents or
|
|
117
|
+
auto-accepts a pattern that would grant deletion authority. An empty but
|
|
118
|
+
explicit decision is a committed decision and clears the action; a missing
|
|
119
|
+
one keeps it pending on every rerun.
|
|
120
|
+
|
|
108
121
|
For each conflicted kit-shipped file, always ask the user whether the local
|
|
109
122
|
edit is a generic improvement or project-specific; never decide or act
|
|
110
123
|
automatically. For a generic improvement retained as a bridge, run
|
|
@@ -131,7 +144,26 @@ release contain the same artifact.
|
|
|
131
144
|
resume the transaction through the update API's `resumeFrom` option. Do not
|
|
132
145
|
copy staged files into the consumer by hand.
|
|
133
146
|
|
|
134
|
-
5.
|
|
147
|
+
5. Review the consumer profile's glob dialect after the update:
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Every consumer-profile glob — Worktree Lifecycle `scratchPatterns` and
|
|
154
|
+
`wrapup.landingGeneratedArtifactPatterns`, Workflow Advisories
|
|
155
|
+
`baseline.sourceGlobs` and the `preRefactor`/`stopChecks` surface globs — is
|
|
156
|
+
matched by one shared repository-relative dialect. A pattern written for an
|
|
157
|
+
older matcher can narrow or widen. The check names each such pattern with
|
|
158
|
+
the witness path that proves the difference and marks the keys that carry
|
|
159
|
+
deletion authority; exit code 1 means at least one needs review. Report the
|
|
160
|
+
named patterns and let the user rewrite them. The updater never rewrites a
|
|
161
|
+
consumer pattern, and a widened deletion-authority pattern is never accepted
|
|
162
|
+
silently — an update must not expand what cleanup may remove. A missing or
|
|
163
|
+
disabled profile leaves nothing to review and does not invalidate the
|
|
164
|
+
update.
|
|
165
|
+
|
|
166
|
+
6. Check the optional project census after the update:
|
|
135
167
|
|
|
136
168
|
```sh
|
|
137
169
|
python3 .claude/hooks/drift-guard.py --census-status
|
|
@@ -146,8 +146,8 @@ replace the ~30-second heartbeat; otherwise the standing heartbeat remains requi
|
|
|
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
|
|
148
148
|
git, ff-merge is the safe path — not `reset --hard`). Install dependencies with
|
|
149
|
-
your package manager after (the lockfile may have moved). A
|
|
150
|
-
survives the merge.
|
|
149
|
+
your package manager after (the lockfile may have moved). A plan doc the repository
|
|
150
|
+
ignores survives the merge; a tracked one may not (`/setup-workflow` offers those rules).
|
|
151
151
|
5. **Run project setup steps (`§Setup`)** the later verify needs — e.g. a DB
|
|
152
152
|
tunnel or service the live-verify depends on. Absent layer → start whatever your
|
|
153
153
|
live-verify environment requires before Phase 4.
|
|
@@ -332,8 +332,8 @@ written · merge order documented.
|
|
|
332
332
|
- **Release this run's slice claims.** A landed slice's PR supersedes its claim;
|
|
333
333
|
for a pulled or abandoned slice remove the claim this run planted (unassign +
|
|
334
334
|
`claim released` comment) so it stays grabbable. Foreign ones stay untouched.
|
|
335
|
-
- **Before removing any slice worktree, read its `ANNAHMEN.md`** (an assumptions
|
|
336
|
-
|
|
335
|
+
- **Before removing any slice worktree, read its `ANNAHMEN.md`** (an assumptions log at
|
|
336
|
+
the worktree root, **expected** to be ignored by git — `/setup-workflow` offers that rule) and propagate each build-time assumption marker
|
|
337
337
|
to the sibling issue it carries. A hand-driven multi-PR / migration landing does
|
|
338
338
|
NOT run `wrapup`'s assumption-propagation step — this is the only place it
|
|
339
339
|
happens; `worktree remove` deletes the log.
|
|
@@ -37,6 +37,7 @@ This is a prompt-driven skill, not a deterministic script. Explore, present what
|
|
|
37
37
|
| `docs/agents/workflow-capabilities.json` + capability assets | consumer-owned Worktree Lifecycle, Memory Lifecycle, Workflow Advisories, and Safety Guardrails choices (Sections A4–A7) |
|
|
38
38
|
| `.claude/settings.json` | additive activation of the advisory kit-origin Edit/Write hint (Section A8) |
|
|
39
39
|
| user-local routing profile | familiar agent surfaces + switching autonomy (Section A9; never package- or repository-owned) |
|
|
40
|
+
| `.gitignore` | **offered only** — one previewed, append-only marker block with the ignore rules for the planning artifacts the skills write (Section A11) |
|
|
40
41
|
|
|
41
42
|
## Idempotency contract — read before writing anything
|
|
42
43
|
|
|
@@ -216,6 +217,15 @@ Worktree Lifecycle for this repository?"* Offer exactly **Yes**, **Later**, and
|
|
|
216
217
|
- **Disable** — remove only the exact kit-owned hook commands first, then set
|
|
217
218
|
`enabled: false`; retain the profile, setup policy, and unknown keys.
|
|
218
219
|
|
|
220
|
+
Whenever a profile already carries patterns — on **Yes** over an existing
|
|
221
|
+
section and on **Existing** — run
|
|
222
|
+
`python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json` and
|
|
223
|
+
report every pattern it names. Patterns whose match set narrows or widens under
|
|
224
|
+
the shared dialect are a consumer decision: name them with their witness path,
|
|
225
|
+
mark the deletion-authority keys, and let the consumer rewrite them. Never
|
|
226
|
+
rewrite a pattern for them, and never accept a widened deletion-authority
|
|
227
|
+
pattern silently.
|
|
228
|
+
|
|
219
229
|
The default setup entry is
|
|
220
230
|
`python3 scripts/worktree-lifecycle/setup.py`; a proven consumer-native helper
|
|
221
231
|
may remain the configured `setupEntry` for parity. The handoff advisory always
|
|
@@ -273,6 +283,12 @@ repository?"* Offer exactly **Yes**, **Later**, and **No**.
|
|
|
273
283
|
- **Disable** — remove exact kit-owned commands first, then set `enabled:
|
|
274
284
|
false`; preserve every profile value and unknown key.
|
|
275
285
|
|
|
286
|
+
`baseline.sourceGlobs` and the `preRefactor`/`stopChecks` surface globs use the
|
|
287
|
+
same shared dialect as the Worktree Lifecycle patterns above. An adopted
|
|
288
|
+
profile written for the older whole-string matcher can change meaning, so run
|
|
289
|
+
`python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json` and
|
|
290
|
+
report every pattern it names before treating the section as reconciled.
|
|
291
|
+
|
|
276
292
|
### 2f. Section A7 — Optional Safety Guardrails
|
|
277
293
|
|
|
278
294
|
> Safety Guardrails is a counted group of seven independently selectable
|
|
@@ -390,6 +406,55 @@ machine, checkout path, repository name, credentials, or current GitHub login.
|
|
|
390
406
|
Even a valid capability authorizes local preparation only; a pull request,
|
|
391
407
|
push, publish, or merge remains a separate explicit approval.
|
|
392
408
|
|
|
409
|
+
### 2j. Section A11 — Planning-artifact ignore rules (offered)
|
|
410
|
+
|
|
411
|
+
> The planning skills write `PLAN.md`, `PLAN-REVIEW-LOG.md`, and `ANNAHMEN.md`
|
|
412
|
+
> into a session worktree. `.gitignore` is the consumer's file: the kit does not
|
|
413
|
+
> own it and never touches it during `init` or `update`, so those artifacts are
|
|
414
|
+
> ignored only if this repository already says so. Without the rules every
|
|
415
|
+
> planning worktree reports a permanently dirty tree, the Worktree Lifecycle
|
|
416
|
+
> cleanup refuses to remove it, and a plan doc can be committed by accident.
|
|
417
|
+
|
|
418
|
+
Read the current state first. The preview is read-only and writes nothing:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
python3 scripts/worktree-lifecycle/ignore_seed.py preview
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
- `nothing-to-do` — this repository already ignores every declared artifact.
|
|
425
|
+
Report it and ask nothing.
|
|
426
|
+
- `blocked` — the marker block exists but no longer covers everything. That
|
|
427
|
+
block is consumer-owned: name the uncovered artifacts, let the user edit
|
|
428
|
+
`.gitignore` themselves, and never repair or rewrite it.
|
|
429
|
+
- `append` — show the exact lines the preview printed, the whole marker block
|
|
430
|
+
verbatim and nothing summarized, then ask: *"Should setup add these ignore
|
|
431
|
+
rules to `.gitignore`?"*
|
|
432
|
+
|
|
433
|
+
Offer exactly two choices:
|
|
434
|
+
|
|
435
|
+
- **Add the rules** — run the seeder once. It appends that one marker block and
|
|
436
|
+
touches nothing else:
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
python3 scripts/worktree-lifecycle/ignore_seed.py apply
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
- **Not now** — write nothing. Explain that the planning skills still work, that
|
|
443
|
+
the artifacts will keep showing up as untracked changes, and that re-running
|
|
444
|
+
`/setup-workflow` offers this again.
|
|
445
|
+
|
|
446
|
+
The write is append-only inside one idempotent marker block: it never rewrites,
|
|
447
|
+
reorders, or removes an existing line; a re-run after an approval is a
|
|
448
|
+
byte-identical no-op; and a decline leaves the file exactly as it was. An
|
|
449
|
+
artifact already committed to history is reported separately — an ignore rule
|
|
450
|
+
cannot untrack it, and setup never runs `git rm`. Only this explicit, approved
|
|
451
|
+
step may write `.gitignore`; `init` and `update` reconciliation never reach the
|
|
452
|
+
seeder.
|
|
453
|
+
|
|
454
|
+
Report `appended · nothing to do (already ignored) · declined · blocked
|
|
455
|
+
(consumer-edited block)`. After an approval — and only then — the Section A4
|
|
456
|
+
`scratchPatterns` derivation has real ignored planning artefacts to read.
|
|
457
|
+
|
|
393
458
|
### 3. Section B — Triage labels
|
|
394
459
|
|
|
395
460
|
> When `triage` processes an incoming issue it applies labels (or your tracker's equivalent). It needs strings you've actually configured, or it creates duplicates.
|
|
@@ -411,13 +476,29 @@ Seed `docs/agents/domain.md` from [domain.md](./domain.md).
|
|
|
411
476
|
|
|
412
477
|
**Skip entirely if Section A is not GitHub** → write `board-sync.md` with `state=not-applicable`, `mode=none`, a one-line "this project does not use a GitHub-Projects board" note. Terminal; never re-prompts.
|
|
413
478
|
|
|
414
|
-
**Preflight:** `gh auth status
|
|
479
|
+
**Preflight:** `gh auth status` (or `python3 scripts/board_bootstrap.py preflight --json` for the machine-readable answer). If `project`/`read:project` scope is missing, surface the exact remedy: `gh auth refresh -s project,read:project`, then fall through to the stub path below — without the write scope, never attempt creation.
|
|
415
480
|
|
|
416
|
-
**Discover (the
|
|
481
|
+
**Discover (the existing-board path):** `gh project list --owner <remote-owner> --format json`. If **exactly one** project clearly belongs to this repo's owner, read its fields: `gh project field-list <number> --owner <owner> --format json`. Record each field's `id`, `name`, `dataType` (single-select / number / text), and for single-selects the option `id`s. Write `board-sync.md` with `state=filled`, `mode=github-projects-v2`, the project node id + repo + the discovered field/option IDs, seeded from [board-sync.md](./board-sync.md). Fill the `<!-- board-sync:profile -->` **JSON block** (the machine SSOT `scripts/board_config.py` parses) — replace each `<…>` placeholder under `repo`/`project`/`fields` with the discovered value; leave the convention values (`labels`/`branchPrefixes`/`prMarkers`/`headings`) at their seeded defaults unless this project's conventions differ.
|
|
417
482
|
|
|
418
483
|
**Map the status roles (`fields.status.roles`):** the seeded map carries the recommended English stage names (`Idea/Triaged/Spec/In Progress/Review/Done`). Reconcile it against the **discovered** Status option names: an exact (case-sensitive) match keeps its seeded entry; for every role whose seeded name is NOT among the discovered options, ask the user which of their actual option names plays that role (a stage they don't have may be omitted from the map — say so). Never guess a mapping from similarity. Finish with a validation pass: every role value in the map MUST appear in `fields.status.options`, else fix before writing `state=filled`.
|
|
419
484
|
|
|
420
|
-
**
|
|
485
|
+
**Offer creation (no board found, scope present):** a fresh repo can reach a working board in this run — `gh project create` provisions the shell and `gh project field-create --single-select-options` provisions the Status single-select together with its options. Minting a GitHub Project is an outward, user-visible action, so **ask first and never create a board without an explicit yes**. Name the stage options the board will get (the seed's `fields.status.roles` values) in the question, and edit those role values in the seed *before* creating if the user wants a different stage vocabulary — they become the board's Status options verbatim. Present exactly two choices:
|
|
486
|
+
|
|
487
|
+
- **Create it now** — run the one creation path (never hand-assemble the `gh` sequence):
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
python3 scripts/board_bootstrap.py create --owner <owner> --repo <owner>/<repo> \
|
|
491
|
+
--title "<repo> Workflow" --seed <path of this skill folder>/board-sync.md \
|
|
492
|
+
--out docs/agents/board-sync.md
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
It re-checks the destination and the scope before it writes anything, creates the project, the Status single-select (option names read from the seed profile's `fields.status.roles` — the board's own stage vocabulary, never a literal), and the Wave / Cluster / Spec-Path / Plan-Path fields, then discovers the real field/option IDs via `gh project field-list` and writes `docs/agents/board-sync.md` at `state=filled`, `mode=github-projects-v2` **from that readback**. Show the user `--dry-run` output first if they want to see the exact sequence. Report the created project's number and URL, and that its Status roles now resolve.
|
|
496
|
+
|
|
497
|
+
- **Not now** — create nothing and take the stub path below unchanged.
|
|
498
|
+
|
|
499
|
+
**A non-zero exit is a stub, never a partial claim.** The helper writes no profile when the destination is consumer-owned, the scope is missing (exit 3), or creation/readback/validation fails — so a half-created board can never produce a profile claiming fields that do not exist. On any non-zero exit, relay its message (it names the project it created, if any, so the user can finish or delete it), then take the stub path; never hand-write a `state=filled` profile and never retry creation without asking again.
|
|
500
|
+
|
|
501
|
+
**Fallback (the single catch-all — declined / no board / >1 / ambiguous / scope error / read failure / creation failure):** write `board-sync.md` with `state=stub`, `mode=github-projects-v2`, and inline **instructions**: which fields the workflow profile needs (a Status single-select with your stage options; optionally a Wave number, a Cluster text, a Spec-Path / Plan-Path text), how to create the board in the GitHub UI / `gh`, and "then run `/setup-workflow` again — it will discover and fill the IDs." Retryable.
|
|
421
502
|
|
|
422
503
|
**Optional — Phase field + saved Views (Program route only):** never
|
|
423
504
|
auto-discovered or auto-created, unlike the fields above — a Phase field's
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
How the board-managed workflow skills (`to-prd`, `to-issues`, `board-to-waves`, …) address this project's GitHub-Projects board. A board stores its fields under opaque GraphQL IDs that differ per board, so they are recorded here rather than hardcoded in any skill.
|
|
4
4
|
|
|
5
5
|
`/setup-workflow` writes this file in one of three states (see the sentinel on the first line):
|
|
6
|
-
- **`state=filled`** — the IDs below were discovered from your board.
|
|
7
|
-
- **`state=stub`** — no single board was
|
|
6
|
+
- **`state=filled`** — the IDs below were discovered from your board (an existing one, or the one `/setup-workflow` offered to create for you).
|
|
7
|
+
- **`state=stub`** — no single board was filled: you declined the creation offer, `gh` lacked the `project` scope, several boards were ambiguous, or creation failed. Create the board (below) and re-run `/setup-workflow`.
|
|
8
8
|
- **`state=not-applicable`** (`mode=none`) — this project does not use a GitHub-Projects board.
|
|
9
9
|
|
|
10
10
|
## Board profile — fields the workflow skills use
|
|
@@ -106,6 +106,10 @@ their titles unchanged; set it once to match your board's language.
|
|
|
106
106
|
|
|
107
107
|
## If the IDs are not yet filled (stub)
|
|
108
108
|
|
|
109
|
+
**Let setup create the board.** Ensure `gh` has the scopes (`gh auth refresh -s project,read:project`) and re-run `/setup-workflow`: with no board and the scope present it *offers* to create one. On your yes it runs `scripts/board_bootstrap.py`, which creates the project plus the Status single-select (its options named after the `roles` map below) and the Wave / Cluster / Spec-Path / Plan-Path fields, reads the real IDs back, and rewrites this file at `state=filled`. Nothing is created without that explicit yes, and a failed run leaves this stub in place rather than a half-true profile.
|
|
110
|
+
|
|
111
|
+
**Or build it by hand:**
|
|
112
|
+
|
|
109
113
|
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).
|
|
110
114
|
2. Ensure `gh` has the scopes: `gh auth refresh -s project,read:project`.
|
|
111
115
|
3. Re-run `/setup-workflow` — it discovers the board (`gh project field-list`) and fills the IDs here automatically.
|
|
@@ -74,6 +74,40 @@ key. Consumer values are never normalized on adoption.
|
|
|
74
74
|
Empty command surfaces are honest inactive defaults. Setup recommends concrete
|
|
75
75
|
project commands from the tools already present, then asks before activating.
|
|
76
76
|
|
|
77
|
+
## Profile glob dialect
|
|
78
|
+
|
|
79
|
+
`baseline.sourceGlobs`, `preRefactor.surfaces[].globs`, and
|
|
80
|
+
`stopChecks.surfaces[].globs` are matched by the one shared dialect in
|
|
81
|
+
`scripts/profile_globs.py` — the same matcher Worktree Lifecycle uses for its
|
|
82
|
+
scratch and landing-artifact policies. There is no second matcher and no
|
|
83
|
+
per-capability variant:
|
|
84
|
+
|
|
85
|
+
- `*` matches any run of characters inside one path segment, never `/`.
|
|
86
|
+
- `?` matches exactly one character inside one path segment.
|
|
87
|
+
- `[seq]` and `[!seq]` are per-segment character classes; `/` is always a
|
|
88
|
+
separator and never a class member.
|
|
89
|
+
- `**` as a complete segment matches zero or more segments, so a leading `**/`
|
|
90
|
+
also matches the repository root and `dir/**` also matches `dir` itself.
|
|
91
|
+
- Matching is always case-sensitive, on every host filesystem.
|
|
92
|
+
- A pattern must match the whole repository-relative path.
|
|
93
|
+
|
|
94
|
+
Thus `src/**` covers `src/a/b.ts`, `**/*.ts` covers both `index.ts` and
|
|
95
|
+
`src/index.ts`, and `*.ts` covers only a root-level file.
|
|
96
|
+
|
|
97
|
+
A profile written for the older whole-string matcher can therefore change
|
|
98
|
+
meaning. When adopting an existing profile, or after any kit update, review it:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The check names every pattern whose match set narrows or widens, prints the
|
|
105
|
+
concrete witness path that proves the difference, and separately flags patterns
|
|
106
|
+
that only matched case-insensitively on the previous matcher. Exit code 1 means
|
|
107
|
+
at least one pattern needs review. Report the named patterns and let the
|
|
108
|
+
consumer rewrite them; never migrate a pattern automatically. The check reads
|
|
109
|
+
the profile and never edits it.
|
|
110
|
+
|
|
77
111
|
## Hook ownership
|
|
78
112
|
|
|
79
113
|
- PreToolUse on Read:
|
|
@@ -82,12 +82,34 @@ The exact kit-owned commands are:
|
|
|
82
82
|
Preserve unrelated settings, hook groups, profile sections, and unknown keys.
|
|
83
83
|
Repeated reconciliation with the same choice is byte-identical.
|
|
84
84
|
|
|
85
|
+
## Planning-artifact ignore rules (offered, never installed)
|
|
86
|
+
|
|
87
|
+
The planning artefacts the shipped skills write live in the worktree, but
|
|
88
|
+
`.gitignore` is a consumer file the kit does not own: `init` and `update` never
|
|
89
|
+
touch it. Setup may therefore only **offer** the rules, from Section A11, using
|
|
90
|
+
`python3 scripts/worktree-lifecycle/ignore_seed.py`. The kit-owned declaration
|
|
91
|
+
of which artefacts those are is `scripts/worktree-lifecycle/plan-artifacts.json`.
|
|
92
|
+
|
|
93
|
+
| State | Setup action |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `append` | Show the exact marker block, then ask. |
|
|
96
|
+
| approve | Run `ignore_seed.py apply` once: it appends that one block, append-only. |
|
|
97
|
+
| decline | Write nothing; a later rerun offers it again. |
|
|
98
|
+
| already ignored | Report `nothing to do`; ask nothing and write nothing. |
|
|
99
|
+
| re-run after approval | Byte-identical no-op; never a second block. |
|
|
100
|
+
| consumer-edited block | `blocked` — report the uncovered artefacts and leave the file untouched. |
|
|
101
|
+
|
|
102
|
+
The seeder never rewrites, reorders, or removes an existing line, and a tracked
|
|
103
|
+
artefact is reported rather than untracked for the consumer. Only this explicit,
|
|
104
|
+
approved step may write `.gitignore`.
|
|
105
|
+
|
|
85
106
|
## Scratch classification and sweep
|
|
86
107
|
|
|
87
108
|
Reconcile an explicit `scratchPatterns` array when enabling a new profile.
|
|
88
109
|
Derive its glob values from the consumer's ignored planning artefacts; an empty
|
|
89
110
|
array is valid. Existing values are consumer-owned and remain byte-identical on
|
|
90
|
-
adoption or rerun. Core never supplies filename defaults
|
|
111
|
+
adoption or rerun. Core never supplies filename defaults — the offered ignore
|
|
112
|
+
rules above are what give that derivation something real to read.
|
|
91
113
|
|
|
92
114
|
Also reconcile an explicit
|
|
93
115
|
`wrapup.landingGeneratedArtifactPatterns` array. Derive candidates from the
|
|
@@ -99,11 +121,40 @@ If an existing enabled profile lacks the key, report one actionable setup
|
|
|
99
121
|
decision and leave the project layer unchanged until the consumer confirms the
|
|
100
122
|
derived list.
|
|
101
123
|
|
|
102
|
-
|
|
103
|
-
|
|
124
|
+
## Profile glob dialect
|
|
125
|
+
|
|
126
|
+
Every consumer-profile glob in this kit — Worktree Lifecycle and Workflow
|
|
127
|
+
Advisories alike — is matched by the one shared dialect in
|
|
128
|
+
`scripts/profile_globs.py`. There is no second matcher and no per-capability
|
|
129
|
+
variant:
|
|
130
|
+
|
|
131
|
+
- `*` matches any run of characters inside one path segment, never `/`.
|
|
132
|
+
- `?` matches exactly one character inside one path segment.
|
|
133
|
+
- `[seq]` and `[!seq]` are per-segment character classes; `/` is always a
|
|
134
|
+
separator and never a class member.
|
|
135
|
+
- `**` as a complete segment matches zero or more segments, so a leading `**/`
|
|
136
|
+
also matches the repository root and `dir/**` also matches `dir` itself.
|
|
137
|
+
- Matching is always case-sensitive, on every host filesystem.
|
|
138
|
+
- A pattern must match the whole repository-relative path.
|
|
139
|
+
|
|
104
140
|
Thus `**/__pycache__/**` covers root and nested caches, while `dist-kit/*` does
|
|
105
141
|
not cover `dist-kit/a/b`.
|
|
106
142
|
|
|
143
|
+
When adopting an existing profile, or after any kit update, review it before
|
|
144
|
+
trusting its patterns:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
python3 scripts/profile_globs.py docs/agents/workflow-capabilities.json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The check names every pattern whose match set narrows or widens against that
|
|
151
|
+
key's legacy matcher, prints the concrete witness path that proves the
|
|
152
|
+
difference, and marks the keys that carry deletion authority. Exit code 1 means
|
|
153
|
+
at least one pattern needs review. Report the named patterns and let the
|
|
154
|
+
consumer rewrite them; never migrate a pattern automatically and never treat a
|
|
155
|
+
widened deletion-authority pattern as an accepted default. The check reads the
|
|
156
|
+
profile and never edits it.
|
|
157
|
+
|
|
107
158
|
The shipped read-only inventory is
|
|
108
159
|
`python3 scripts/worktree-lifecycle/cleanup.py sweep`. The same profile powers
|
|
109
160
|
its branch issue extraction and scratch-only cleanup verdicts.
|
|
@@ -127,6 +127,30 @@ matching path; classify or move those blockers first. Do not use relinquish for
|
|
|
127
127
|
an exact unchanged frozen attempt: a normal retry validates that evidence and
|
|
128
128
|
resumes deterministically.
|
|
129
129
|
|
|
130
|
+
An attempt journaled under the superseded v1 contract is **legacy, not
|
|
131
|
+
corruption**. The STOP says so explicitly and names the same
|
|
132
|
+
`--abandon-unfinished-attempt` archive route; archival stays valid for a v1 and
|
|
133
|
+
a v2 receipt even without a creation baseline or a local main profile, and no
|
|
134
|
+
generated or consumer file is deleted or claimed on that route.
|
|
135
|
+
|
|
136
|
+
If canonical `origin/main` changed its scratch or generator policy *after* the
|
|
137
|
+
attempt started, the PR can merge and cleanup then STOPs with `worktree cleanup
|
|
138
|
+
policy differs from merged canonical origin/main`. That STOP stays fail-closed
|
|
139
|
+
and names its one supported route out:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
python3 scripts/wrapup-land.py land --branch "<branch>" --recover-canonical-cleanup
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
This resumes the teardown of an **already-merged** worktree only. It never reads
|
|
146
|
+
the stale worktree candidate policy: it re-reads the merged canonical policy,
|
|
147
|
+
requires the branch to already be an ancestor of canonical `origin/main`, and
|
|
148
|
+
revalidates each frozen landing identity against that canonical policy before
|
|
149
|
+
the ordinary shared assessment and removal run. Evidence the canonical policy no
|
|
150
|
+
longer names, a changed identity, and any pre-existing or foreign file are hard
|
|
151
|
+
STOPs that delete nothing. Re-running after a successful teardown is a no-op.
|
|
152
|
+
The flag is mutually exclusive with `--abandon-unfinished-attempt`.
|
|
153
|
+
|
|
130
154
|
### 6 · Post-merge (agent)
|
|
131
155
|
- **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.
|
|
132
156
|
- **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.
|