@erclx/aitk 0.80.0 → 0.82.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.
Files changed (52) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/ci-workflow/REQUIREMENT.md +3 -1
  3. package/claude/skills/claude-address-review/SKILL.md +8 -3
  4. package/claude/skills/claude-address-review/references/rebase-conflicts.md +3 -1
  5. package/claude/skills/claude-autoship/SKILL.md +3 -1
  6. package/claude/skills/claude-diagram/SKILL.md +3 -1
  7. package/claude/skills/claude-docs/SKILL.md +17 -4
  8. package/claude/skills/claude-feature/SKILL.md +6 -2
  9. package/claude/skills/claude-intake/REQUIREMENT.md +3 -1
  10. package/claude/skills/claude-memory-review/SKILL.md +6 -2
  11. package/claude/skills/claude-memory-review/references/receipt-format.md +3 -1
  12. package/claude/skills/claude-orchestrate/REQUIREMENT.md +6 -2
  13. package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +3 -1
  14. package/claude/skills/claude-pr-review/SKILL.md +11 -3
  15. package/claude/skills/claude-seed-sync/SKILL.md +3 -1
  16. package/claude/skills/cli-script/REQUIREMENT.md +3 -1
  17. package/claude/skills/docs-sync/SKILL.md +3 -1
  18. package/claude/skills/git-followup/REQUIREMENT.md +3 -1
  19. package/claude/skills/git-followup/SKILL.md +10 -2
  20. package/claude/skills/git-pr/REQUIREMENT.md +8 -0
  21. package/claude/skills/git-pr/SKILL.md +20 -1
  22. package/claude/skills/git-pr/references/labels.md +59 -0
  23. package/claude/skills/git-ship/SKILL.md +3 -1
  24. package/claude/skills/migration-context/REQUIREMENT.md +3 -1
  25. package/claude/skills/project-commands/SKILL.md +3 -1
  26. package/claude/skills/session-resume/SKILL.md +3 -1
  27. package/claude/skills/setup-indexes/SKILL.md +3 -1
  28. package/claude/skills/setup-init/SKILL.md +3 -1
  29. package/claude/skills/toolkit-cli/SKILL.md +1 -1
  30. package/docs/agents/commands.md +2 -0
  31. package/docs/agents/comments.md +3 -1
  32. package/docs/agents/context-audit-checks.md +31 -7
  33. package/docs/agents/index.md +1 -1
  34. package/docs/agents/indexes.md +3 -1
  35. package/docs/agents/install-and-sync.md +12 -6
  36. package/docs/agents/markdown-audit.md +3 -1
  37. package/docs/agents/output-shape.md +3 -1
  38. package/docs/agents/records.md +45 -1
  39. package/docs/agents/sandbox.md +3 -1
  40. package/docs/ai-workflow.md +31 -8
  41. package/docs/operating-model.md +6 -3
  42. package/docs/target-projects.md +22 -6
  43. package/docs/visual-design-workflow.md +13 -3
  44. package/package.json +1 -1
  45. package/src/cli.ts +2 -1
  46. package/src/commands/records.ts +160 -2
  47. package/src/markdown/structure.ts +7 -1
  48. package/src/records/backup.ts +394 -0
  49. package/standards/prose.md +3 -1
  50. package/standards/rule.md +3 -1
  51. package/standards/tasks.md +11 -3
  52. package/standards/versioning.md +3 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "0.80.0",
4
+ "version": "0.82.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -11,7 +11,9 @@ Without this skill, a session writes a pipeline whose jobs run in sequence becau
11
11
 
12
12
  The same session splits a gate that finishes in a minute into three parallel jobs, which fails in the other direction. Each job repays checkout, dependency install, and toolchain setup before it reaches a stage, so the gate gets slower while reporting no earlier, and the roster reads as a design decision rather than as a cost nobody measured.
13
13
 
14
- The rest are reproducibility failures that surface as flakes. An action pinned to a moving ref changes under the project, so a run that passed yesterday fails today with no commit behind it and the diff explains nothing. A cache keyed on a static string serves a stale browser or toolchain after a version bump, and the failure reads as a broken test rather than a stale cache. Artifacts upload on every run and never expire, so storage grows with the commit count while the ones worth reading are the failures. And a workflow with no manual trigger can only be reproduced by pushing a commit, which is the wrong instrument for a run that failed for an environmental reason.
14
+ The rest are reproducibility failures that surface as flakes. An action pinned to a moving ref changes under the project, so a run that passed yesterday fails today with no commit behind it and the diff explains nothing.
15
+
16
+ A cache keyed on a static string serves a stale browser or toolchain after a version bump, and the failure reads as a broken test rather than a stale cache. Artifacts upload on every run and never expire, so storage grows with the commit count while the ones worth reading are the failures. And a workflow with no manual trigger can only be reproduced by pushing a commit, which is the wrong instrument for a run that failed for an environmental reason.
15
17
 
16
18
  ## Must
17
19
 
@@ -76,8 +76,9 @@ Push the fixes before posting the reply so the comment never runs ahead of the
76
76
  code it describes. Ship the fixes as a follow-up commit on the same branch with
77
77
  the `git-followup` skill, invoked with `reply-owned` so it stages, commits,
78
78
  pushes, and refreshes the open PR body without posting its own comment. This
79
- skill owns the reply. Do not reimplement that flow here. For in-place fixes to
80
- files the PR body already covers, `git-followup` leaves the body untouched and
79
+ skill owns the reply. Do not reimplement that flow here.
80
+
81
+ For in-place fixes to files the PR body already covers, `git-followup` leaves the body untouched and
81
82
  the reply comment carries the fix log. A rebase in step 5 rewrote the branch, so
82
83
  that push is a force-push and `git-followup` resolves it from the tracking
83
84
  branch. Worker branches are single-owner here, which is what makes overwriting
@@ -100,15 +101,19 @@ mapping each finding to what changed, or to a one-line reason when it is a
100
101
  conscious-accept rather than a defect. Key the filename on the PR number so two
101
102
  sessions addressing different pull requests never overwrite each other between
102
103
  the write and the post. Note any `.claude/` docs refreshed as a result of the
103
- fixes. The reply is a rendered-for-human GitHub surface, so follow
104
+ fixes.
105
+
106
+ The reply is a rendered-for-human GitHub surface, so follow
104
107
  `.claude/standards/prose.md` for voice, or `${CLAUDE_SKILL_DIR}/../../standards/prose.md`
105
108
  when the project does not have it, and keep each mapping to a line or two.
109
+
106
110
  Open the body with the `## Review response` heading so it anchors as a section
107
111
  distinct from human threads and stays subordinate to the `## Review` heading the
108
112
  review itself carries. Follow it with a one-line summary sentence, then one
109
113
  bullet per finding, each opening with the bolded finding identifier.
110
114
  Close the body with `🤖 Addressed by Claude Code` on its own line so the reply
111
115
  reads as an independent machine pass, not a human sign-off.
116
+
112
117
  When step 5 rebased the branch, say so in the summary sentence and name which
113
118
  files were resolved by hand and which the regen rebuilt. The next review is a
114
119
  full pass rather than a delta, and the reader is owed the reason.
@@ -28,7 +28,9 @@ These rules apply to a hunk from the rebase and a hunk from the stash pop alike:
28
28
  - Never take one side wholesale with `--ours` or `--theirs`. Both sides are valid content, so the drop is silent and passes every check.
29
29
  - Never resolve a generated file by hand. A file the project check rebuilds, such as an `index.md` carrying no `auto: false`, takes either side to clear the conflict and gets its real content from the regen below.
30
30
  - Where two branches wrote prose into one file, keep both sides and rewrite what the merge broke. A section that opens by counting what follows needs the count updated rather than the two versions concatenated.
31
- - When a hunk needs a decision the tree does not carry, stop rather than guessing, and name where the branch was left. The two sources recover differently. A hunk raised by the rebase takes `git rebase --abort`, which restores the old base: `❌ Conflict needs a decision at <file>. Branch left on its old base.` A hunk raised by the stash pop arrives after the rebase already landed, so no abort applies and the conflict stays in the tree: `❌ Conflict needs a decision at <file>. Branch rebased, fixes left conflicted in the tree.` A guess that compiles is the failure this stage would otherwise introduce, and either case reaches the operator as an ordinary finding on the next review pass.
31
+ - When a hunk needs a decision the tree does not carry, stop rather than guessing, and name where the branch was left. The two sources recover differently. A guess that compiles is the failure this stage would otherwise introduce, and either case reaches the operator as an ordinary finding on the next review pass.
32
+ - A hunk raised by the rebase takes `git rebase --abort`, which restores the old base: `❌ Conflict needs a decision at <file>. Branch left on its old base.`
33
+ - A hunk raised by the stash pop arrives after the rebase already landed, so no abort applies and the conflict stays in the tree: `❌ Conflict needs a decision at <file>. Branch rebased, fixes left conflicted in the tree.`
32
34
 
33
35
  Both sides of every hunk sit in the conflict and `git log origin/main` names what landed, so the tree carries the context. Do not wait on the orchestrator for it.
34
36
 
@@ -122,7 +122,9 @@ After the PR is created, mark it as draft:
122
122
  gh pr ready --undo
123
123
  ```
124
124
 
125
- After marking draft, watch CI. Poll `gh pr checks <number>` until no check is pending, then read the final status. On all-pass, continue. On any failure, stop and report the failing check with its URL. Do not auto-fix.
125
+ After marking draft, watch CI. Poll `gh pr checks <number>` until no check is pending, then read the final status.
126
+
127
+ On all-pass, continue. On any failure, stop and report the failing check with its URL. Do not auto-fix.
126
128
 
127
129
  8. `aitk:claude-memory-review`: if step 1's capture wrote or updated at least one memory file, propose fixes scoped to those entries, writing the decision-ready receipt while session context is fresh. Skip when capture wrote nothing to the folder, which is the ordinary outcome once routing has taken the domain facts.
128
130
 
@@ -28,7 +28,9 @@ Follow `.claude/standards/diagrams.md` for frontmatter, entry kinds, layout, bud
28
28
 
29
29
  ### Migrating a pre-split flat file
30
30
 
31
- When `.claude/diagrams/` holds no entry and `.claude/DIAGRAMS.md` exists, this pass converts it. An entry is any `*.md` in the folder other than `index.md`. The seed ships `index.md` alone, so a folder holding only the catalog is an empty set and still converts. Split each H2 section into the entry whose kind it matches, carry its mermaid body and explanation prose across unchanged, and add the frontmatter the standard requires. Leave `.claude/DIAGRAMS.md` on disk so the split can be compared against its source, and say in Step 7 that deleting it is the user's call.
31
+ When `.claude/diagrams/` holds no entry and `.claude/DIAGRAMS.md` exists, this pass converts it. An entry is any `*.md` in the folder other than `index.md`. The seed ships `index.md` alone, so a folder holding only the catalog is an empty set and still converts.
32
+
33
+ Split each H2 section into the entry whose kind it matches, carry its mermaid body and explanation prose across unchanged, and add the frontmatter the standard requires. Leave `.claude/DIAGRAMS.md` on disk so the split can be compared against its source, and say in Step 7 that deleting it is the user's call.
32
34
 
33
35
  Convert only. Do not redraw a diagram during a migration pass, since a rewrite and a move landing together leaves no way to tell which one broke a diagram.
34
36
 
@@ -64,7 +64,11 @@ Review the session for decisions that diverged from the original plan:
64
64
  - Design or UX decisions that differ from DESIGN.md or any `.claude/wireframes/<surface>.md`
65
65
  - Tasks blocked or newly identified
66
66
 
67
- Then resolve the diff baseline and match it against the board. From `.claude/tasks/index.md` at the main worktree root, pick the task files whose title or description relates to the changed paths and read the ones Step 1 skipped. Path matching only chooses which files to open. Behavior decides each outcome. For each unchecked outcome, decide whether the diff shipped the behavior that outcome names. Completion is the one judgment here that is a fact about the repository rather than a fact about the conversation, so the diff decides it and the session does not. Requirements, architecture, and design stay session-sourced.
67
+ Then resolve the diff baseline and match it against the board. From `.claude/tasks/index.md` at the main worktree root, pick the task files whose title or description relates to the changed paths and read the ones Step 1 skipped.
68
+
69
+ Path matching only chooses which files to open. Behavior decides each outcome. For each unchecked outcome, decide whether the diff shipped the behavior that outcome names.
70
+
71
+ Completion is the one judgment here that is a fact about the repository rather than a fact about the conversation, so the diff decides it and the session does not. Requirements, architecture, and design stay session-sourced.
68
72
 
69
73
  Keep the match conservative:
70
74
 
@@ -91,11 +95,13 @@ For each doc with relevant changes, apply updates following these rules. Read a
91
95
 
92
96
  **`.claude/tasks/`**
93
97
 
94
- - Mark completed outcomes `[x]` in the task's own file through `aitk tasks outcome <stem> --close <n> --json`, repeating `--close` for each. Positions count every outcome checkbox in file order from 1, which the read above already gives. The verb resolves the board at the main worktree root in-process, which is the route because this is an edit inside an existing file and the file-editing tools refuse that path from a linked worktree. Do not move or archive the file.
98
+ - Mark completed outcomes `[x]` in the task's own file through `aitk tasks outcome <stem> --close <n> --json`, repeating `--close` for each. Positions count every outcome checkbox in file order from 1, which the read above already gives. Do not move or archive the file.
95
99
  - Write a newly identified task as its own file, following `.claude/standards/tasks.md` for the filename and frontmatter.
96
100
  - Do not touch task files this session did not change.
97
101
  - Never hand-edit `.claude/tasks/index.md`. A hook regenerates it.
98
102
 
103
+ The verb resolves the board at the main worktree root in-process, which is the route because this is an edit inside an existing file and the file-editing tools refuse that path from a linked worktree.
104
+
99
105
  **REQUIREMENTS.md, ARCHITECTURE.md, DESIGN.md, `.claude/wireframes/<surface>.md`**
100
106
 
101
107
  - Update only the sections affected by session decisions.
@@ -164,6 +170,7 @@ Reuse the diff from the baseline above, names and content both. For each existin
164
170
 
165
171
  - Map the entry's section headings to the changed files. An entry is relevant when its prose references files, modules, or decisions touched by the diff.
166
172
  - For each relevant entry, rewrite only the sections affected by the diff. Same pattern as `docs-sync`. Do not touch unrelated sections.
173
+ - Write a reference to another entry as the path that entry sits at, rather than as its bare filename. `.claude/standards/context.md` states the form, and a bare name strands the reference once a domain splits into subfolders.
167
174
 
168
175
  Do not create new entries automatically. New entries are a deliberate decision: the user invokes `claude-docs --new-context <domain>` (future flag) or hand-creates the file following `.claude/standards/context.md`. Auto-creation risks padding `.claude/context/` with low-signal entries.
169
176
 
@@ -183,11 +190,17 @@ Sweep reviews this session consumed, and sweep plans across the whole board. Res
183
190
 
184
191
  Every move and delete below is a shell operation, so send each as a plain single `Bash` command rather than joining a `mkdir -p` to the `mv` with `&&`, which is refused as compound from a linked worktree. The one edit inside an existing file is the `Plan:` retarget, and no verb covers it: read the task file and write it back whole with a heredoc, which the file-editing tools refuse from a linked worktree and no shell stream editor may do.
185
192
 
186
- **Plans.** Scan every file in `.claude/tasks/`, not only the ones this session touched. For each task file whose outcomes are now all `[x]`, check for a `Plan:` line directly under the title and parse the target. The line carries a markdown link, so read the target out of the parentheses rather than taking the rest of the line. A task still carrying the older bare-path form parses the same way once the link is absent, so accept both. Resolve the target against `.claude/tasks/` before routing on it, which lands `../plans/x.md` and `.claude/plans/x.md` on the same file. The bullets below name resolved locations, so an unresolved target falls to the last one and no plan is ever archived. Never delete a plan. `.claude/standards/plan.md` owns the archive destination and why a shipped plan is moved rather than removed.
193
+ **Plans.** Scan every file in `.claude/tasks/`, not only the ones this session touched. For each task file whose outcomes are now all `[x]`, check for a `Plan:` line directly under the title and parse the target.
194
+
195
+ The line carries a markdown link, so read the target out of the parentheses rather than taking the rest of the line. A task still carrying the older bare-path form parses the same way once the link is absent, so accept both. Resolve the target against `.claude/tasks/` before routing on it, which lands `../plans/x.md` and `.claude/plans/x.md` on the same file.
196
+
197
+ The bullets below name resolved locations, so an unresolved target falls to the last one and no plan is ever archived. Never delete a plan. `.claude/standards/plan.md` owns the archive destination and why a shipped plan is moved rather than removed.
187
198
 
188
199
  Board-wide scope is the one place this sweep reaches past Step 3's rule against touching task files the session did not change. A board carrying a task that closed while an earlier run missed its archive is the defect this exists to clear, and skipping those tasks would preserve it. Reaching them is safe because the archive moves the plan and points the task at the new path, so a task from unrelated work ends up with a working pointer rather than a broken one.
189
200
 
190
- Before moving anything, count the other citations. Scan every `.claude/tasks/*.md` file except the one being processed for a `Plan:` line naming the same plan. Compare the resolved target from the parse above, never the raw target string and never the filename alone. A board carrying one task written `../plans/x.md` and another written `.claude/plans/x.md` cites one plan, and a raw string comparison reads two, counts zero, and archives the file out from under a live task. Comparing filenames swaps that for the opposite error, since a live plan and an archived one share a basename whenever a closed task still points into `.claude/plans-archive/`, and the count then reads a citation that does not exist and archives nothing.
201
+ Before moving anything, count the other citations. Scan every `.claude/tasks/*.md` file except the one being processed for a `Plan:` line naming the same plan. Compare the resolved target from the parse above, never the raw target string and never the filename alone.
202
+
203
+ A board carrying one task written `../plans/x.md` and another written `.claude/plans/x.md` cites one plan, and a raw string comparison reads two, counts zero, and archives the file out from under a live task. Comparing filenames swaps that for the opposite error, since a live plan and an archived one share a basename whenever a closed task still points into `.claude/plans-archive/`, and the count then reads a citation that does not exist and archives nothing.
191
204
 
192
205
  Exclude the closing task explicitly. It sits on the board and cites the plan itself, so a scan that counts it never reaches zero and no plan is ever archived.
193
206
 
@@ -23,7 +23,9 @@ Read these in parallel from the project root, skipping any that do not exist:
23
23
  Also read these when the feature touches code or UI. Skip them for prose, docs, catalog, or config-only changes:
24
24
 
25
25
  - `.claude/DESIGN.md`: tokens, typography, spacing, and component rules
26
- - `.claude/wireframes/index.md` + the surface files relevant to the feature: intended UI layout and behavior. Read `index.md` first, then load only the per-surface files (`.claude/wireframes/<surface>.md`) the feature actually touches. Do not read the whole folder speculatively. When the plan adds or revises a surface, the wireframe file follows `.claude/standards/wireframes.md`, or `${CLAUDE_SKILL_DIR}/../../standards/wireframes.md` when the project does not have it.
26
+ - `.claude/wireframes/index.md` + the surface files relevant to the feature: intended UI layout and behavior. Read `index.md` first, then load only the per-surface files (`.claude/wireframes/<surface>.md`) the feature actually touches. Do not read the whole folder speculatively.
27
+
28
+ When the plan adds or revises a surface, the wireframe file follows `.claude/standards/wireframes.md`, or `${CLAUDE_SKILL_DIR}/../../standards/wireframes.md` when the project does not have it.
27
29
 
28
30
  Coding standards live in `.claude/rules/`. Claude Code loads them automatically. Path-scoped rules apply to the files they match.
29
31
 
@@ -31,7 +33,9 @@ Coding standards live in `.claude/rules/`. Claude Code loads them automatically.
31
33
 
32
34
  Based on the feature description, identify and read source files that are directly relevant. Do not read entire directories speculatively.
33
35
 
34
- Measure against the tree rather than recall. Grep for each construct the plan will name and count the sites, so the plan carries the count the tree holds today. Confirm any work the plan sequences behind is still open, so it does not lead with an item that already shipped. Open each file before describing what is in it. A count or a claim carried from an earlier session, a summary, or another document is the most common way a plan ships the wrong scope.
36
+ Measure against the tree rather than recall. Grep for each construct the plan will name and count the sites, so the plan carries the count the tree holds today. Confirm any work the plan sequences behind is still open, so it does not lead with an item that already shipped.
37
+
38
+ Open each file before describing what is in it. A count or a claim carried from an earlier session, a summary, or another document is the most common way a plan ships the wrong scope.
35
39
 
36
40
  ## Step 3: build the plan
37
41
 
@@ -11,7 +11,9 @@ Without this skill, a brain dump reaches a session that has nowhere to put it. `
11
11
 
12
12
  Two failure modes cost more than the rest. An operator's silence on an item reads as consent when the folder borrows the plan file's blank-means-accept contract, which ships changes nobody approved across a folder read over weeks. And a report naming only a path cannot distinguish three new items from one reworded sentence in a file that holds a dozen items, so every reader diffs it against memory to find out what moved.
13
13
 
14
- Four more are cheaper to name than to rediscover. A question filed without a pick comes back unresolved, measured across one folder's 19 open items, where every one carrying a suggestion resolved on a bare `ok` and the five carrying none did not. A session with no numbering convention re-decides the folder shape per dump, so no two intakes are readable the same way and the second one has to be learned from scratch. A question answerable both in the index and on its item resolves to whichever a reader opens first, with no rule saying which wins. And a pass with no write scope starts fixing what it files, which turns a triage into a branch nobody asked for and nobody reviewed.
14
+ Four more are cheaper to name than to rediscover. A question filed without a pick comes back unresolved, measured across one folder's 19 open items, where every one carrying a suggestion resolved on a bare `ok` and the five carrying none did not.
15
+
16
+ A session with no numbering convention re-decides the folder shape per dump, so no two intakes are readable the same way and the second one has to be learned from scratch. A question answerable both in the index and on its item resolves to whichever a reader opens first, with no rule saying which wins. And a pass with no write scope starts fixing what it files, which turns a triage into a branch nobody asked for and nobody reviewed.
15
17
 
16
18
  ## Must
17
19
 
@@ -68,7 +68,9 @@ For each in-scope entry (see Scope), pick one action:
68
68
  - **Promote to a skill body**: the rule fires only when editing a specific path-scoped domain. Name the target skill.
69
69
  - **Promote to a standards file**: the rule is an authoring reference that belongs in `.claude/standards/<domain>.md`.
70
70
  - **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `.claude/context/index.md`. Append it to `.claude/.tmp/memory-routing/<slug>.md` in the format `claude-memory-capture` writes, and tell the user to run `/claude-docs` from a branch. Do not edit the context entry here.
71
- - **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning). Do not author the rule file inline. In the toolkit repo, point the user at `aitk-governance` and `.claude/standards/rule.md`, which own the source-of-truth rules under `governance/rules/`. In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`. Never edit the synced `.claude/rules/` copies of toolkit rules, because `aitk gov sync` overwrites them. Stop at handoff.
71
+ - **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning). Do not author the rule file inline. Never edit the synced `.claude/rules/` copies of toolkit rules, because `aitk gov sync` overwrites them. Stop at handoff.
72
+ - In the toolkit repo, point the user at `aitk-governance` and `.claude/standards/rule.md`, which own the source-of-truth rules under `governance/rules/`.
73
+ - In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`.
72
74
  - **Retire**: the rule is stale, already absorbed into a durable surface, too vague to phrase as a rule, or a one-time incident narrative. Apply moves the file to `.claude/.tmp/memory-archive/` rather than deleting it.
73
75
 
74
76
  Retire is an archive, not a deletion, which `.claude/standards/memory.md` states as the rule and this skill executes. The archive is worth less than a plan's, since a promoted entry survives in its destination and a stale one is discarded on purpose, which is why the move is cheap rather than free.
@@ -164,7 +166,9 @@ aitk indexes regen --no-stage --root <main-root> <main-root>/.claude/memory/inde
164
166
 
165
167
  The `PostToolUse` hook that keeps the index current matches `Write|Edit|MultiEdit`, and an archive move is a shell `mv`, so nothing fires on it. Without this call the index keeps a row per archived entry and drifts exactly the way the hand-appended one did. Run it once after the last move rather than per item.
166
168
 
167
- Apply promotion edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole promotion target. This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the guard instead.
169
+ Apply promotion edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole promotion target.
170
+
171
+ This governs the tracked surfaces a promote lands in, which sit at `pwd` and take `Edit` from anywhere. The receipt and the memory entries are main-root scratch and follow the guard instead.
168
172
 
169
173
  As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the review file. It stays as a receipt until Cleanup runs or the next Propose pass overwrites it.
170
174
 
@@ -9,7 +9,9 @@ The shape Step 4 of the Propose phase writes to `.claude/review/memory-review-<s
9
9
 
10
10
  ## Structure
11
11
 
12
- A summary block at the top, a legend, then one H2 per numbered item. Number items across all actions so the user can reference them by number. Fuse the status, action, and target into each H2. Put the memory filename on its own line, a one-line Why, the rewritten rule inline in a fenced `diff` block prefixed with `+` so reviewers see the additions in green, and a `Decision:` slot for the user. Do not include a `Take:` slot in the template. Discuss inserts one directly under `Decision:` only when responding to a question item. Status starts as 📝 pending for every item at proposal time.
12
+ A summary block at the top, a legend, then one H2 per numbered item. Number items across all actions so the user can reference them by number. Fuse the status, action, and target into each H2. Put the memory filename on its own line, a one-line Why, the rewritten rule inline in a fenced `diff` block prefixed with `+` so reviewers see the additions in green, and a `Decision:` slot for the user.
13
+
14
+ Do not include a `Take:` slot in the template. Discuss inserts one directly under `Decision:` only when responding to a question item. Status starts as 📝 pending for every item at proposal time.
13
15
 
14
16
  ````plaintext
15
17
  # Memory review: <slug>
@@ -21,13 +21,17 @@ Writing those plans against the tree alone is the second half, since several bra
21
21
 
22
22
  The session also writes surfaces it is told only how to read. Refilling the queue promotes and demotes rows in the priority file with no stated method, so a session invents one, and an inline rewrite exits clean when it matches nothing and leaves the board wrong with nothing reporting it. A row carrying prose where a plan pointer belongs costs a worker dispatch, because the ship chain refuses at its guard after the worktree is already open. A plan archived from a worker's own branch strands the pointer the board still carries, and the row reads as correct until someone follows it.
23
23
 
24
- The ban on writing at all fails on a different axis, which is that nothing enforces it and a session weighs proportionality against it. A one-line prose correction found while orchestrating satisfies the root instruction to handle a small edit immediately and violates this rule, and a session given no statement of which one wins takes the smaller apparent cost and authors the change. That removes the independent pass the repository built to catch what a self-review misses, and the vantage does not come back, since no later session can review the change without re-deriving the context that produced it. A correction no open task owns has nowhere to go either, so the route matters as much as the ban.
24
+ The ban on writing at all fails on a different axis, which is that nothing enforces it and a session weighs proportionality against it. A one-line prose correction found while orchestrating satisfies the root instruction to handle a small edit immediately and violates this rule, and a session given no statement of which one wins takes the smaller apparent cost and authors the change.
25
+
26
+ That removes the independent pass the repository built to catch what a self-review misses, and the vantage does not come back, since no later session can review the change without re-deriving the context that produced it. A correction no open task owns has nowhere to go either, so the route matters as much as the ban.
25
27
 
26
28
  Output drifts everywhere the contract stops. The specified shape covers invocation alone, so a sweep report, a board report, and an analysis each end in a decision the human owns and each buries it under the evidence they would have skipped. A compaction is the same failure one step earlier, since the file that survives it has a stated reader and no stated writer, and the session improvises what to save and loses the reasoning the board never held.
27
29
 
28
30
  Naming that reader without naming the way in fails on the next axis, and it fails circularly. The command that routes a resume request lives in this body, which is the surface a long session is likeliest to have dropped, and dropping it is the condition the handoff exists to survive, so the session holding a complete handoff cannot reach the runbook that reads it back. The review poll is lost in the same moment and recovered by neither, since it is session-scoped and the resume performs no restart, which leaves a reader who follows the whole handoff with a board and no trigger.
29
31
 
30
- The runbooks the session cannot run from memory fail on a third axis, which is where they are kept. A runbook reached by an installed path is a dependency on a channel this skill does not travel on, so a project holding the plugin and running no install follows the citation to nothing, and nothing reports the break because a missing file produces no error until someone opens the path. Every one of them therefore has to ship inside the skill, the four covering the moments the loop cannot detect and the fifth holding the review trigger. That last one fails on an axis of its own, since it names one client's command as the way to start the loop, so a session holding a different recurring-prompt scheduler reaches no path and a client without that command reaches none either, and the file ships to every target holding the plugin.
32
+ The runbooks the session cannot run from memory fail on a third axis, which is where they are kept. A runbook reached by an installed path is a dependency on a channel this skill does not travel on, so a project holding the plugin and running no install follows the citation to nothing, and nothing reports the break because a missing file produces no error until someone opens the path.
33
+
34
+ Every one of them therefore has to ship inside the skill, the four covering the moments the loop cannot detect and the fifth holding the review trigger. That last one fails on an axis of its own, since it names one client's command as the way to start the loop, so a session holding a different recurring-prompt scheduler reaches no path and a client without that command reaches none either, and the file ships to every target holding the plugin.
31
35
 
32
36
  The session also records nothing of what it learns. Both other callers of memory capture are ship-chain skills and this one never ships, so the session taking every operator correction is the session with no moment that writes one down. Hanging that moment on the merge sweep answers it and bills the operator a capture pass per batch of merges while nothing is being built, which is a cost paid on the days shipping is fastest.
33
37
 
@@ -19,7 +19,9 @@ Stale in the groundwork: <lean or number the shipped work overturned>
19
19
  Next: <the one or two tasks ready to hand a worker>
20
20
  ```
21
21
 
22
- Treat a groundwork folder as three kinds of content with different shelf lives. Trust the reasoning and the method, which stay correct. Re-measure every count, size, and cost, because they were true when written. Check every `Leaning:` against what has shipped, because work spawned by a track routinely overturns the lean that spawned it and nothing writes back. A plan a live task cites goes stale the same way, and `claude-orchestrate` states the check that catches it.
22
+ Treat a groundwork folder as three kinds of content with different shelf lives. Trust the reasoning and the method, which stay correct. Re-measure every count, size, and cost, because they were true when written. Check every `Leaning:` against what has shipped, because work spawned by a track routinely overturns the lean that spawned it and nothing writes back.
23
+
24
+ A plan a live task cites goes stale the same way, and `claude-orchestrate` states the check that catches it.
23
25
 
24
26
  After each merge, place every finding the work produced before starting anything else. A finding that changes a standard goes to the standard, one that changes another task goes to that task's Findings, and one that overturns a groundwork lean gets marked answered in that folder. Findings recorded in a pull request thread and nowhere else are lost at merge.
25
27
 
@@ -91,7 +91,9 @@ Use severity: `critical` (blocks merge), `should-fix` (fix before merge), `minor
91
91
 
92
92
  ## Step 4: post to the PR
93
93
 
94
- Write the comment to `.claude/.tmp/pr-review/body-<number>-<short-sha>.md`. The PR number stops two sessions reviewing different pull requests from overwriting each other between the write and the post. The head commit stops a second pass overwriting the first one's body, and leaves the folder a record of which commit each review covered. Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a name the folder already holds.
94
+ Write the comment to `.claude/.tmp/pr-review/body-<number>-<short-sha>.md`. The PR number stops two sessions reviewing different pull requests from overwriting each other between the write and the post. The head commit stops a second pass overwriting the first one's body, and leaves the folder a record of which commit each review covered.
95
+
96
+ Derive both segments from Step 1. Never pick a suffix by hand, and never reuse a name the folder already holds.
95
97
 
96
98
  The comment is a rendered-for-human GitHub surface, so follow `.claude/standards/prose.md` for voice, or `${CLAUDE_SKILL_DIR}/../../standards/prose.md` when the project does not have it: cut editorializing, and keep every sentence load-bearing. Match this shape on a first pass:
97
99
 
@@ -132,7 +134,11 @@ Read the state off the most recent review comment rather than off the presence o
132
134
 
133
135
  Both of this skill's headings anchor as a section distinct from human threads. Do not invent one beyond those two and the `## Review response` a sibling owns, and do not append the PR number, which GitHub already renders above the comment.
134
136
 
135
- Name the scope in every summary line after the first pass, since a reader cannot otherwise tell a narrow read from a full one. When the fallback in Step 2 fired, replace the commit count with `Re-reviewed the full change, the prior pass's commit is no longer on the branch`. Budget the body. State each finding as the failure and the fix in two or three sentences, not a paragraph of reasoning. Omit files with no findings. Do not lecture on process. The integration, contract, and consumer lenses stay, but as findings, not asides.
137
+ Name the scope in every summary line after the first pass, since a reader cannot otherwise tell a narrow read from a full one. When the fallback in Step 2 fired, replace the commit count with `Re-reviewed the full change, the prior pass's commit is no longer on the branch`.
138
+
139
+ Budget the body. State each finding as the failure and the fix in two or three sentences, not a paragraph of reasoning.
140
+
141
+ Omit files with no findings. Do not lecture on process. The integration, contract, and consumer lenses stay, but as findings, not asides.
136
142
 
137
143
  The `What is right` section is optional, capped at three bullets, and included only when it changes the merge decision. Drop it otherwise and let the summary line carry the approval.
138
144
 
@@ -144,7 +150,9 @@ Before posting, run the scan in `.claude/standards/publish.md` against the body,
144
150
  gh pr review <number> --comment --body-file .claude/.tmp/pr-review/body-<number>-<short-sha>.md
145
151
  ```
146
152
 
147
- A pass with no findings takes `## Review closed` and a short body, with the footer line included either way. On a first pass, post `✅ No blocking findings. Reviewed against project docs and roadmap.` On a later pass, post `✅ Prior findings addressed. Re-reviewed <short-sha>, N commits since the prior pass.` Post that one even when there is nothing to report. A review left with no closing comment reads as one nobody answered.
153
+ A pass with no findings takes `## Review closed` and a short body, with the footer line included either way. On a first pass, post `✅ No blocking findings. Reviewed against project docs and roadmap.` On a later pass, post `✅ Prior findings addressed. Re-reviewed <short-sha>, N commits since the prior pass.`
154
+
155
+ Post that one even when there is nothing to report. A review left with no closing comment reads as one nobody answered.
148
156
 
149
157
  ## Step 5: output
150
158
 
@@ -38,7 +38,9 @@ Fall back to the appearance heuristic in step 3 when the report cannot attribute
38
38
 
39
39
  ## Step 2: read installed copies
40
40
 
41
- For each entry in the merged list, read the file at its `target` path from the project root. Run reads in parallel. Mark missing files for **Add** treatment. Skip non-text seeds (`.json`) for section diffing. Record a one-line note in the scope table that the user can compare manually.
41
+ For each entry in the merged list, read the file at its `target` path from the project root. Run reads in parallel.
42
+
43
+ Mark missing files for **Add** treatment. Skip non-text seeds (`.json`) for section diffing. Record a one-line note in the scope table that the user can compare manually.
42
44
 
43
45
  When detecting target-only files for `local-only` flagging, skip files the toolkit's own walkers regenerate from sibling frontmatter (today: any `index.md` produced by `aitk indexes regen`). They are absent from source catalogs by design, so flagging them as `local-only` is a false positive.
44
46
 
@@ -9,7 +9,9 @@ description: What a non-interactive automation script owes its caller, and the s
9
9
 
10
10
  Without this skill, an automation script is written with an interactive tool's habits. Progress frames, icons, and color land on stdout, so the script stops composing in a pipe and the caller parses a spinner as data. The failure is invisible in a terminal and total in CI.
11
11
 
12
- The robustness failures are the ones that reach production. Without strict mode a failed stage inside a pipe exits zero and the script reports success on work that did not happen. An unset variable expands to nothing and a path built from it points somewhere nobody meant. Errors print and execution continues. And a single long `main()` holding every responsibility cannot be tested or reused, which is what turns a one-off script into one nobody will touch.
12
+ The robustness failures are the ones that reach production. Without strict mode a failed stage inside a pipe exits zero and the script reports success on work that did not happen.
13
+
14
+ An unset variable expands to nothing and a path built from it points somewhere nobody meant. Errors print and execution continues. And a single long `main()` holding every responsibility cannot be tested or reused, which is what turns a one-off script into one nobody will touch.
13
15
 
14
16
  ## Must
15
17
 
@@ -65,7 +65,9 @@ Classify at the section level, not the file level. A doc edited earlier in the s
65
65
 
66
66
  ## Action
67
67
 
68
- Rewrite only the stale sections. Do not touch sections unrelated to the diff. Write the updated file immediately after the preview. Claude Code's tool permission dialog is the confirmation gate. Do not wait for user input.
68
+ Rewrite only the stale sections. Do not touch sections unrelated to the diff.
69
+
70
+ Write the updated file immediately after the preview. Claude Code's tool permission dialog is the confirmation gate. Do not wait for user input.
69
71
 
70
72
  Never rewrite a `departed` section. Leave it as written and report it as a finding, since the repair belongs in the code rather than in the prose.
71
73
 
@@ -7,7 +7,9 @@ description: What the follow-up push is for, the gaps it closes, and how it spli
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, an edit made after a pull request is already open ships as a bare push. The body still describes the scope from before the edit, so a reviewer returning to the page reads a description the diff no longer matches. A reviewer who left comments gets no reply, and when a caller has already posted its own reply, a second one lands underneath it. A caller that rebased the branch before handing over hits a rejected push, since the tracking branch no longer reaches the head. A branch entered through a worktree hits the opposite shape, carrying an open pull request with no tracking ref at all, which read as a branch that had never been pushed.
10
+ Without this skill, an edit made after a pull request is already open ships as a bare push. The body still describes the scope from before the edit, so a reviewer returning to the page reads a description the diff no longer matches. A reviewer who left comments gets no reply, and when a caller has already posted its own reply, a second one lands underneath it.
11
+
12
+ A caller that rebased the branch before handing over hits a rejected push, since the tracking branch no longer reaches the head. A branch entered through a worktree hits the opposite shape, carrying an open pull request with no tracking ref at all, which read as a branch that had never been pushed.
11
13
 
12
14
  ## Must
13
15
 
@@ -23,9 +23,17 @@ A missing tracking ref is no longer a guard. An open pull request proves the bra
23
23
  1. Run `git status` to confirm the changes are intentional
24
24
  2. Run `git add -A` to stage every change
25
25
  3. Invoke `aitk:git-commit` to generate one conventional commit from the staged diff
26
- 4. Push. When `git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null` is empty, the branch has an open pull request and no tracking ref, so run `git push -u origin HEAD` to send the commit and set the ref in one step. Otherwise push to the tracking branch with `git push`, and when `git merge-base --is-ancestor @{u} HEAD` exits non-zero, a caller rewrote the branch and a plain push is rejected, so push with `--force-with-lease` instead. The lease is what stops the force from overwriting a commit this session never read. Run the ancestry test only where an upstream resolves, since it reads `@{u}`.
26
+ 4. Push, in one of two cases.
27
+ - When `git rev-parse --abbrev-ref --symbolic-full-name @{u} 2>/dev/null` is empty, the branch has an open pull request and no tracking ref, so run `git push -u origin HEAD` to send the commit and set the ref in one step.
28
+ - Otherwise push to the tracking branch with `git push`, and when `git merge-base --is-ancestor @{u} HEAD` exits non-zero, a caller rewrote the branch and a plain push is rejected, so push with `--force-with-lease` instead.
29
+
30
+ The lease is what stops the force from overwriting a commit this session never read. Run the ancestry test only where an upstream resolves, since it reads `@{u}`.
31
+
27
32
  5. Check for existing review comments: `gh api 'repos/{owner}/{repo}/pulls/<number>/comments' --jq 'length'`, resolving `<number>` from `gh pr view --json number`.
28
- 6. When invoked with `reply-owned`, skip this step's comment: the caller posts the reply. Otherwise, if the count is above zero, the followup addresses review feedback: post a one-line summary of the fix with `gh pr comment --body`, first running the scan in `.claude/standards/publish.md` against it, or `${CLAUDE_SKILL_DIR}/../../standards/publish.md` when the project does not have it, since the hook does not see an inline comment body. If it is zero, run `gh pr view --json url,title,body` and update the body with `gh pr edit --body` when the new commit changes scope, and the title with `gh pr edit --title` when the scope shifted enough to make it inaccurate.
33
+ 6. Route on the invocation and the comment count.
34
+ - When invoked with `reply-owned`, skip this step's comment: the caller posts the reply.
35
+ - Otherwise, if the count is above zero, the followup addresses review feedback: post a one-line summary of the fix with `gh pr comment --body`, first running the scan in `.claude/standards/publish.md` against it, or `${CLAUDE_SKILL_DIR}/../../standards/publish.md` when the project does not have it, since the hook does not see an inline comment body.
36
+ - If it is zero, run `gh pr view --json url,title,body` and update the body with `gh pr edit --body` when the new commit changes scope, and the title with `gh pr edit --title` when the scope shifted enough to make it inaccurate.
29
37
 
30
38
  ## After completion
31
39
 
@@ -9,6 +9,8 @@ description: What pull request generation is for, the gaps it closes, and what i
9
9
 
10
10
  Without this skill, a pull request body is written from memory of the branch rather than from its diff, so it describes the intent and omits what the work turned into. Testing boxes get ticked from intent, which records what was meant to run instead of what ran, and a reviewer trusts the list. A second push either errors on create or opens a duplicate pull request, and banned characters survive into a body the hook never sees.
11
11
 
12
+ Every pull request also lands unlabelled, so a merged list is a wall of titles with no way to filter it by surface. A reader looking for what changed in one domain reads all of them, and the conventional commit type in the title says what kind of change it is rather than where.
13
+
12
14
  A lookup that resolves by head branch alone carries its own failure. A branch name reused after an earlier pull request merged resolves to the closed one, so the run rewrites a merged pull request's title and body and reports its URL as the one it opened. Both fields are recoverable only through the issue timeline and the edit history, and nothing reports that the write landed on the wrong object.
13
15
 
14
16
  ## Must
@@ -21,6 +23,9 @@ A lookup that resolves by head branch alone carries its own failure. A branch na
21
23
  - Detect an open pull request and edit it in place, so a follow-up push keeps the body in sync instead of failing
22
24
  - Scope that detection to an open pull request on the current head and the default base, so neither a reused branch name nor a second base resolves the wrong one
23
25
  - Resolve the pull request once and reuse what that resolution returned, so the number recorded never depends on how a lookup ranks two pull requests sharing a head
26
+ - Label from the paths the branch changed, against a map the project declares, so the label set belongs to the project rather than to the skill
27
+ - Apply labels after the pull request exists, so a label the remote does not carry costs a warning rather than the pull request
28
+ - Report a refused label, since a warning nothing surfaces leaves the run indistinguishable from one that labelled
24
29
 
25
30
  ## Must not
26
31
 
@@ -28,12 +33,15 @@ A lookup that resolves by head branch alone carries its own failure. A branch na
28
33
  - Put a request for the reviewer in the Testing list, since a request is not a result
29
34
  - Create a second pull request when one is open
30
35
  - Edit a pull request that is not open, or record its number on a task
36
+ - Name a domain of any one project in the skill body or its references
37
+ - Create a label the map names and the remote lacks
31
38
  - Emit anything after the result line
32
39
 
33
40
  ## Guards
34
41
 
35
42
  - Branch name does not conform: stop and route to the skill that renames
36
43
  - No commits ahead of main: stop
44
+ - No label map in the project: label nothing and warn nothing, since an absent map is a decision rather than a gap
37
45
 
38
46
  ## Out of scope
39
47
 
@@ -11,6 +11,7 @@ Read these files in parallel:
11
11
 
12
12
  - `${CLAUDE_SKILL_DIR}/references/branch.md`: branch format, valid types, and constraints
13
13
  - `${CLAUDE_SKILL_DIR}/references/pr.md`: structure, rules, and banned phrases
14
+ - `${CLAUDE_SKILL_DIR}/references/labels.md`: label map format, matching, and the missing-label warning. Skip when the project has no `.claude/pr-labels.toml`.
14
15
  - `.claude/standards/prose.md` from the project root: voice and banned words for all generated text
15
16
  - `.claude/standards/markdown.md` from the project root: punctuation and formatting for all generated text
16
17
  - `.claude/standards/versioning.md` from the project root: phase label vs semver discipline
@@ -29,6 +30,7 @@ Then run these commands in parallel to gather git context:
29
30
  - `git branch --show-current 2>/dev/null || echo "unknown"`
30
31
  - `git log <base>..HEAD --oneline 2>/dev/null || echo "NO_COMMITS"`
31
32
  - `git diff <base> HEAD -- . ':(exclude)*.lock' ':(exclude)*-lock.json' 2>/dev/null || echo "NO_DIFF"`
33
+ - `git diff --name-only <base> HEAD 2>/dev/null || echo "NO_FILES"`
32
34
 
33
35
  ## Diff baseline
34
36
 
@@ -82,15 +84,24 @@ The lookup scopes to the base as well as the head. One head can carry open pull
82
84
 
83
85
  A detached HEAD gives `git branch --show-current` an empty result, which would read as no open pull request and create a second one. The branch-name guard above stops the run first, since an empty name does not match `<type>/<description>`.
84
86
 
87
+ ### Labels
88
+
89
+ Read `.claude/pr-labels.toml` from the project root. A project that has not declared a map gets no labels and no warning, since a label set this skill supplied would be a guess about that project's surfaces.
90
+
91
+ When the file resolves, match it against the name-only diff per `${CLAUDE_SKILL_DIR}/references/labels.md` and write the comma-separated result into `pr_labels` below. Leave `pr_labels` empty when no map resolves or no prefix matches, which skips the labelling command rather than running it against nothing.
92
+
85
93
  ### Final command
86
94
 
87
95
  Detect an open pull request on the current head and branch: edit it in place when one exists, create it otherwise. This keeps the body in sync on a follow-up push instead of erroring on `gh pr create`.
88
96
 
97
+ Labels apply after that branch converges, against a pull request that already exists. `gh pr create --label` refuses a label the remote does not carry and opens no pull request at all, so a mistyped row costs the run rather than the label. One command after the fact also covers the create and the edit path together.
98
+
89
99
  ```bash
90
100
  mkdir -p .claude/.tmp/pr
91
101
  cat <<'BODY' > .claude/.tmp/pr/body.md
92
102
  <body content following pr.md template exactly>
93
103
  BODY
104
+ pr_labels="<comma-separated labels, empty when the map resolves to nothing>"
94
105
  git push -u origin HEAD || exit 1
95
106
  base_branch=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name) || exit 1
96
107
  pr_number=$(gh pr list --head "$(git branch --show-current)" --base "$base_branch" --state open --json number --jq '.[0].number // empty')
@@ -100,6 +111,10 @@ else
100
111
  pr_url=$(gh pr create --title "<title>" --body-file .claude/.tmp/pr/body.md) || exit 1
101
112
  pr_number=${pr_url##*/}
102
113
  fi
114
+ if [ -n "$pr_labels" ]; then
115
+ gh pr edit "$pr_number" --add-label "$pr_labels" >/dev/null ||
116
+ printf 'Label apply failed. Create a missing label with: gh label create <name>\n' >&2
117
+ fi
103
118
  rm -rf .claude/.tmp/pr
104
119
  printf 'number=%s\nurl=%s\n' "$pr_number" "$pr_url"
105
120
  ```
@@ -124,8 +139,12 @@ The number is what lets the merge close the task. Every merge on `main` is a squ
124
139
 
125
140
  ## After execution
126
141
 
127
- Respond with exactly one line, using the `url` the final command printed:
142
+ Respond with one line, using the `url` the final command printed:
128
143
 
129
144
  `✅ PR: <url>`
130
145
 
146
+ Add a second line only when the labelling command printed its warning, quoting the label `gh` refused:
147
+
148
+ `⚠️ Labels not applied: <what gh reported>`
149
+
131
150
  Do not add any other text.
@@ -0,0 +1,59 @@
1
+ ---
2
+ title: Label reference
3
+ description: Path-to-label map format, prefix matching against the changed set, and the one-time label creation a map requires
4
+ ---
5
+
6
+ # Label reference
7
+
8
+ ## Scope
9
+
10
+ Governs the labels a pull request carries: the map a project declares, how a changed path resolves to a label, and what a label missing from the remote costs.
11
+
12
+ Does not govern:
13
+
14
+ - Pull request title and body: `pr.md`
15
+ - Branch naming: `branch.md`
16
+ - Issue labels, which `git-issue` derives from the issue type rather than from a diff
17
+
18
+ ## Map format
19
+
20
+ The map lives at `.claude/pr-labels.toml` in the project root. Each key under `[domains]` is a label name and its value is the list of path prefixes that earn it.
21
+
22
+ ```toml
23
+ [domains]
24
+ api = ["services/api/"]
25
+ web = ["apps/web/", "packages/ui/"]
26
+ ```
27
+
28
+ A label takes more than one prefix when two folders read as one surface. Two labels may claim overlapping prefixes, and a path under both earns both.
29
+
30
+ The map is authored by hand and nothing detects a directory it fails to cover, so a surface added after the map was written labels nothing until someone adds a row.
31
+
32
+ ## Matching
33
+
34
+ - Take the changed set from `git diff --name-only <base> HEAD`, resolved against the same base as the diff the body is written from
35
+ - A path earns a label when the path starts with one of that label's prefixes
36
+ - Collect the distinct labels across the whole set, ordered as the map declares them, so two runs over one branch produce one string
37
+ - Pass the result as a single comma-separated value. An empty result runs no labelling step.
38
+
39
+ ## Applying
40
+
41
+ Apply labels after the pull request resolves, never as a flag on the create. `gh pr create --label` fails whole on a label the remote does not carry, so a name the map got wrong opens no pull request at all and the run stops with the branch pushed and nothing to review. A `gh pr edit --add-label` against a pull request that already exists costs a warning instead, and it is one command across both the create and the edit path rather than two flags that have to stay in step.
42
+
43
+ `--add-label` adds and never removes. A label a person applied by hand is not this skill's to strip, so a domain that stops applying between two pushes keeps its label until someone takes it off.
44
+
45
+ ## A label the remote does not carry
46
+
47
+ Warn and continue rather than creating it, naming the command in the warning:
48
+
49
+ ```bash
50
+ gh label create <name> --description "<text>"
51
+ ```
52
+
53
+ Creating a label writes to the repository settings from a run the user invoked to open a pull request, and a label created from a typo in the map is harder to notice than a warning is.
54
+
55
+ The refusal names the label it rejected and applies none of the set, so a warning that reaches nobody leaves the run reading exactly like one that labelled. Surface it beside the result line rather than letting the pull request URL stand alone.
56
+
57
+ ## Release pull requests
58
+
59
+ Release automation opens its own pull requests without this skill and applies its own labels, so nothing here needs a skip condition for them.
@@ -6,7 +6,9 @@ disable-model-invocation: true
6
6
 
7
7
  # Ship
8
8
 
9
- Run the full post-feature workflow by invoking each skill in sequence using the Skill tool. After each skill returns, invoke the next step immediately in the same response. Do not output any text between steps and do not wait for user input. Tool permission dialogs are the only interrupts allowed. The final output is `✅ Shipped`.
9
+ Run the full post-feature workflow by invoking each skill in sequence using the Skill tool. After each skill returns, invoke the next step immediately in the same response.
10
+
11
+ Do not output any text between steps and do not wait for user input. Tool permission dialogs are the only interrupts allowed. The final output is `✅ Shipped`.
10
12
 
11
13
  ## Pre-check
12
14
 
@@ -9,7 +9,9 @@ description: Scope boundary for the docs audience split and its ordering against
9
9
 
10
10
  Without this skill, a session judges a `docs/` file agent-facing, moves it, and rewrites the inbound links in the same pass, so a classification the user rejects is no longer one command to undo.
11
11
 
12
- Three more failures share a cause. The skill reads a folder two other surfaces also write, and a proposal blind to them destroys work. A seed-derived `development.md` moved out of `docs/` comes back on the next seed sync. A move onto an existing `.claude/context/` filename overwrites the entry sitting there. A proposal drafted while `migration-claude-md` is proposing entries into the same folder cannot see those targets, and running the two in the wrong order turns a legitimate move into a skipped conflict.
12
+ Three more failures share a cause. The skill reads a folder two other surfaces also write, and a proposal blind to them destroys work.
13
+
14
+ A seed-derived `development.md` moved out of `docs/` comes back on the next seed sync. A move onto an existing `.claude/context/` filename overwrites the entry sitting there. A proposal drafted while `migration-claude-md` is proposing entries into the same folder cannot see those targets, and running the two in the wrong order turns a legitimate move into a skipped conflict.
13
15
 
14
16
  ## Must
15
17
 
@@ -11,10 +11,12 @@ The value is the stop. A launch that continues into log inspection, browser chec
11
11
 
12
12
  ## Guards
13
13
 
14
- - Resolve the entry before anything else. Take the flat `development.md` under `.claude/context/` when it exists, and `.claude/context/development/overview.md` when the domain outgrew one file and split into a folder, which is where the `## Scripts` table lands in a split. Test both paths, then read one. If neither resolves, stop with the line below and let the user decide. Do not read another file to reconstruct it, because a guess is worse than a stop when the user cannot see it was a guess.
14
+ - Resolve the entry before anything else. Take the flat `development.md` under `.claude/context/` when it exists, and `.claude/context/development/overview.md` when the domain outgrew one file and split into a folder, which is where the `## Scripts` table lands in a split. Test both paths, then read one. If neither resolves, stop with the line below and let the user decide.
15
15
  - If the entry documents no command matching the request, stop and list what it does document. Do not infer a command from a filename or a framework.
16
16
  - If the resolved command has an effect that outlives the process and stopping it does not undo, print it for the user to run and stop. Deploying, publishing, releasing, migrating, and resetting are the common shapes, and the test is the effect rather than the name. A script called `infra:apply` or `promote` qualifies.
17
17
 
18
+ Do not read another file to reconstruct an entry that did not resolve, because a guess is worse than a stop when the user cannot see it was a guess.
19
+
18
20
  The stop names the flat path in both cases, since a project carrying neither has no entry to point at and the flat one is where a project without a split keeps it:
19
21
 
20
22
  ```plaintext