@erclx/canon 5.37.0 → 5.39.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 (197) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/SKILL.md +12 -9
  4. package/claude/skills/auto-ship/SKILL.md +43 -23
  5. package/claude/skills/backlog-triage/SKILL.md +62 -53
  6. package/claude/skills/backlog-triage/references/apply.md +69 -0
  7. package/claude/skills/build-in-slices/SKILL.md +8 -4
  8. package/claude/skills/canon-cli/SKILL.md +5 -1
  9. package/claude/skills/canon-feedback/SKILL.md +18 -8
  10. package/claude/skills/canon-feedback-triage/SKILL.md +10 -3
  11. package/claude/skills/canvas-board/SKILL.md +36 -17
  12. package/claude/skills/ci-workflow/SKILL.md +5 -4
  13. package/claude/skills/code-craft/SKILL.md +10 -6
  14. package/claude/skills/codebase-layout/SKILL.md +3 -5
  15. package/claude/skills/context-fold/REQUIREMENT.md +4 -4
  16. package/claude/skills/context-fold/SKILL.md +42 -23
  17. package/claude/skills/context-fold/references/context-refresh.md +4 -3
  18. package/claude/skills/context-fold/references/context.md +79 -64
  19. package/claude/skills/create-rule/SKILL.md +7 -3
  20. package/claude/skills/create-skill/SKILL.md +27 -7
  21. package/claude/skills/create-skill/references/skill-reference.md +41 -17
  22. package/claude/skills/decision-escalate/SKILL.md +8 -5
  23. package/claude/skills/deploy-app/SKILL.md +1 -1
  24. package/claude/skills/deprecation-migration/SKILL.md +12 -4
  25. package/claude/skills/design-taste/SKILL.md +17 -11
  26. package/claude/skills/docs-sync/REQUIREMENT.md +1 -0
  27. package/claude/skills/docs-sync/SKILL.md +17 -6
  28. package/claude/skills/docs-sync/references/docs.md +54 -21
  29. package/claude/skills/docs-sync/references/readme.md +32 -8
  30. package/claude/skills/document-health/SKILL.md +3 -4
  31. package/claude/skills/draft-and-pick/SKILL.md +73 -47
  32. package/claude/skills/draft-doc/SKILL.md +9 -4
  33. package/claude/skills/draft-doc/references/context.md +4 -4
  34. package/claude/skills/draft-doc/references/docs.md +1 -0
  35. package/claude/skills/draft-doc/references/wiki.md +3 -2
  36. package/claude/skills/draft-figure/SKILL.md +9 -7
  37. package/claude/skills/draft-identity/SKILL.md +24 -52
  38. package/claude/skills/draft-identity/references/card-route.md +46 -0
  39. package/claude/skills/draft-ready/SKILL.md +19 -7
  40. package/claude/skills/draft-screencast/SKILL.md +6 -112
  41. package/claude/skills/draft-screencast/references/beats-template.md +119 -0
  42. package/claude/skills/draft-slides/SKILL.md +7 -4
  43. package/claude/skills/git-branch/SKILL.md +3 -3
  44. package/claude/skills/git-commit/SKILL.md +5 -3
  45. package/claude/skills/git-followup/SKILL.md +16 -9
  46. package/claude/skills/git-issue/SKILL.md +6 -5
  47. package/claude/skills/git-issue/references/issue.md +11 -10
  48. package/claude/skills/git-pr/SKILL.md +56 -44
  49. package/claude/skills/git-ship/SKILL.md +43 -34
  50. package/claude/skills/git-ship/references/ci-watch.md +31 -0
  51. package/claude/skills/git-split/SKILL.md +28 -100
  52. package/claude/skills/git-split/references/independent.md +40 -0
  53. package/claude/skills/git-split/references/stacked.md +73 -0
  54. package/claude/skills/git-stage/SKILL.md +9 -7
  55. package/claude/skills/git-worktree/SKILL.md +27 -49
  56. package/claude/skills/git-worktree/references/cleanup.md +55 -0
  57. package/claude/skills/markdown-craft/SKILL.md +2 -2
  58. package/claude/skills/markdown-craft/references/markdown.md +82 -52
  59. package/claude/skills/plan-feature/SKILL.md +52 -46
  60. package/claude/skills/plan-feature/references/batches.md +46 -0
  61. package/claude/skills/plan-groundwork/SKILL.md +60 -74
  62. package/claude/skills/plan-groundwork/references/groundwork.md +53 -24
  63. package/claude/skills/plan-groundwork/references/output.md +48 -0
  64. package/claude/skills/plan-intake/SKILL.md +28 -21
  65. package/claude/skills/plan-intake-answer/SKILL.md +14 -13
  66. package/claude/skills/read-frames/SKILL.md +2 -0
  67. package/claude/skills/record-screencast/SKILL.md +31 -11
  68. package/claude/skills/review-address/SKILL.md +76 -158
  69. package/claude/skills/review-address/references/rebase-only.md +34 -0
  70. package/claude/skills/review-craft/SKILL.md +27 -11
  71. package/claude/skills/review-pr/SKILL.md +91 -40
  72. package/claude/skills/review-pr/references/post.md +1 -1
  73. package/claude/skills/review-ui/SKILL.md +62 -37
  74. package/claude/skills/review-ui/references/hosted-preview.md +30 -0
  75. package/claude/skills/role-orchestrator/SKILL.md +105 -74
  76. package/claude/skills/role-orchestrator/references/orchestrator-filing.md +26 -0
  77. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +1 -1
  78. package/claude/skills/role-planner/SKILL.md +66 -64
  79. package/claude/skills/role-reviewer/SKILL.md +57 -46
  80. package/claude/skills/role-worker/SKILL.md +68 -63
  81. package/claude/skills/search-craft/SKILL.md +7 -5
  82. package/claude/skills/session-compact/SKILL.md +16 -11
  83. package/claude/skills/session-map/SKILL.md +31 -10
  84. package/claude/skills/session-relay/SKILL.md +32 -65
  85. package/claude/skills/session-resume/SKILL.md +18 -13
  86. package/claude/skills/session-worktree/SKILL.md +70 -42
  87. package/claude/skills/systematic-debugging/SKILL.md +6 -1
  88. package/claude/skills/target-check/SKILL.md +13 -6
  89. package/claude/skills/target-setup/SKILL.md +41 -30
  90. package/claude/skills/target-setup/references/verify.md +6 -5
  91. package/claude/skills/task-board/SKILL.md +68 -60
  92. package/claude/skills/task-board/references/create-report.md +36 -0
  93. package/claude/skills/task-board/references/tasks.md +3 -1
  94. package/claude/skills/task-complete/SKILL.md +20 -18
  95. package/claude/skills/teach-workspace/SKILL.md +61 -33
  96. package/claude/skills/test-craft/SKILL.md +2 -1
  97. package/claude/skills/test-first/SKILL.md +15 -9
  98. package/claude/skills/ui-checklist/SKILL.md +18 -16
  99. package/claude/skills/ux-audit/SKILL.md +9 -10
  100. package/claude/skills/ux-measure/SKILL.md +22 -18
  101. package/claude/skills/video-craft/SKILL.md +15 -7
  102. package/claude/skills/write-human/SKILL.md +9 -1
  103. package/claude/skills/youtube-transcripts/SKILL.md +2 -1
  104. package/docs/agents/context-audit-checks.md +19 -1
  105. package/docs/agents/context-audit.md +2 -2
  106. package/docs/agents/driver.md +1 -1
  107. package/docs/agents/hooks.md +21 -1
  108. package/docs/agents/index.md +10 -14
  109. package/docs/agents/indexes.md +25 -29
  110. package/docs/agents/install-and-sync.md +124 -235
  111. package/docs/agents/markdown-audit-density.md +39 -0
  112. package/docs/agents/markdown-audit-weight.md +9 -7
  113. package/docs/agents/markdown-audit.md +18 -14
  114. package/docs/agents/migrate.md +41 -16
  115. package/docs/agents/output-shape.md +60 -45
  116. package/docs/agents/overview.md +36 -12
  117. package/docs/agents/routing.md +1 -1
  118. package/docs/agents/rule-citations.md +1 -1
  119. package/docs/agents/skills-reach.md +1 -1
  120. package/docs/agents/targets.md +25 -77
  121. package/docs/target/migrations.md +1 -1
  122. package/docs/target/projects.md +3 -3
  123. package/docs/target/scenarios.md +1 -1
  124. package/docs/workflow/ai-workflow.md +2 -2
  125. package/docs/workflow/parallel-features.md +2 -2
  126. package/docs/workflow/skill-map.md +1 -1
  127. package/docs/workflow/visual-design-workflow.md +1 -1
  128. package/governance/detect.toml +6 -1
  129. package/package.json +6 -3
  130. package/scripts/core/install-check.sh +1 -1
  131. package/src/commands/claude.ts +1 -2
  132. package/src/commands/context.ts +106 -7
  133. package/src/commands/hooks.ts +63 -0
  134. package/src/commands/markdown.ts +169 -32
  135. package/src/commands/pr.ts +1 -1
  136. package/src/commands/records.ts +0 -1
  137. package/src/context/audit.ts +256 -5
  138. package/src/context/classify/prompts.ts +1 -1
  139. package/src/context/gate.ts +23 -7
  140. package/src/context/shape-gated.ts +28 -0
  141. package/src/design/document.ts +1 -1
  142. package/src/design/tokens.ts +1 -1
  143. package/src/docs/read.ts +15 -21
  144. package/src/gate/measures.ts +15 -190
  145. package/src/gate/stages.ts +21 -23
  146. package/src/hooks/reply-links.ts +110 -0
  147. package/src/markdown/density.ts +258 -0
  148. package/src/markdown/gate.ts +57 -18
  149. package/src/markdown/reference-shape.ts +103 -0
  150. package/src/markdown/scope.ts +174 -0
  151. package/src/markdown/structure.ts +10 -60
  152. package/src/sandbox/equivalence.ts +7 -9
  153. package/src/shipped/references.ts +1 -1
  154. package/src/teach/browser/head.ts +2 -2
  155. package/src/teach/browser/sidebar.ts +3 -3
  156. package/src/teach/browser/theme.ts +2 -2
  157. package/src/tooling/inject.ts +2 -2
  158. package/src/tooling/package.ts +15 -18
  159. package/src/tooling/verify-stack.ts +6 -3
  160. package/tooling/astro/configs/.oxfmtrc.json +8 -0
  161. package/tooling/astro/configs/.prettierrc +13 -0
  162. package/tooling/astro/manifest.toml +13 -0
  163. package/tooling/astro/reference.md +15 -5
  164. package/tooling/base/configs/.oxfmtrc.json +7 -0
  165. package/tooling/base/configs/scripts/verify.ts +1 -1
  166. package/tooling/base/manifest.toml +6 -6
  167. package/tooling/base/reference.md +12 -9
  168. package/tooling/base/seeds/.lintstagedrc +1 -3
  169. package/tooling/base/seeds/canon/context/ci.md +3 -3
  170. package/tooling/base/seeds/canon/context/development.md +2 -2
  171. package/tooling/claude/manifest.toml +5 -1
  172. package/tooling/claude/seeds/.claude/hooks/reply-links.sh +72 -0
  173. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +22 -1
  174. package/tooling/claude/seeds/.claude/settings.json +4 -0
  175. package/tooling/go/reference.md +2 -2
  176. package/tooling/nextjs/configs/.oxlintrc.json +223 -0
  177. package/tooling/nextjs/manifest.toml +2 -5
  178. package/tooling/nextjs/reference.md +4 -4
  179. package/tooling/php/manifest.toml +6 -1
  180. package/tooling/php/reference.md +2 -2
  181. package/tooling/python/manifest.toml +6 -1
  182. package/tooling/python/reference.md +4 -4
  183. package/tooling/vite-react/manifest.toml +1 -4
  184. package/tooling/vite-react/reference.md +3 -3
  185. package/tooling/web/configs/.oxlintrc.json +213 -0
  186. package/tooling/web/manifest.toml +9 -13
  187. package/tooling/web/reference.md +14 -14
  188. package/docs/agents/commands.md +0 -154
  189. package/docs/agents/docs.md +0 -27
  190. package/docs/agents/drift-surfaces.md +0 -201
  191. package/docs/agents/gov-detect.md +0 -47
  192. package/docs/agents/scripting.md +0 -142
  193. package/src/markdown/growth.ts +0 -43
  194. package/tooling/base/configs/.prettierrc +0 -12
  195. package/tooling/base/seeds/.prettierignore +0 -0
  196. package/tooling/nextjs/configs/eslint.config.js +0 -91
  197. package/tooling/web/configs/eslint.config.js +0 -82
@@ -39,18 +39,20 @@ Then run these commands in parallel to gather git context:
39
39
 
40
40
  ## Diff baseline
41
41
 
42
- Prefer `origin/main` over local `main`. Both reads resolve against `<base>`, so the commits listed and the changes described come from one scope. Never read a two-dot range against local `main` for either half: it resolves no merge base, so once local `main` moves, the diff reports its newer commits as reversed changes and the log lists commits already on the remote.
42
+ Prefer `origin/main` over local `main`. Both reads resolve against `<base>`, so the commits listed and the changes described come from one scope.
43
43
 
44
- The baseline is unusable in two cases:
44
+ Never read a two-dot range against local `main` for either half. It resolves no merge base, so once local `main` moves, the diff reports its newer commits as reversed changes and the log lists commits already on the remote.
45
+
46
+ ### Unusable baseline
47
+
48
+ The baseline is unusable in two cases, and the no-commits guard below catches both, so stop there rather than describing an empty diff:
45
49
 
46
50
  - No merge base resolves against either ref.
47
51
  - The base equals HEAD, whichever ref resolved it. Nothing is committed ahead of the base to compare against.
48
52
 
49
- Either case leaves both reads empty, which the no-commits guard below catches. Stop there rather than composing a description from an empty diff.
50
-
51
53
  ## Guards
52
54
 
53
- - If branch name does not match `<type>/<description>` format (valid types are defined in `${CLAUDE_SKILL_DIR}/../git-branch/references/branch.md`), stop and output:
55
+ - If the branch name does not match `<type>/<description>`, with the types `branch.md` defines, stop and output:
54
56
  `❌ Branch name does not follow conventions. Run /git-branch to rename first.`
55
57
  - If no commits ahead of main, stop and output:
56
58
  `❌ No commits ahead of main. Nothing to PR.`
@@ -59,6 +61,8 @@ Either case leaves both reads empty, which the no-commits guard below catches. S
59
61
 
60
62
  ### Preview
61
63
 
64
+ Output the preview first.
65
+
62
66
  - **Title:** <title>
63
67
  - **Files changed:** <count>
64
68
  - **Analysis:** <brief summary of impact>
@@ -73,9 +77,12 @@ Leave a box unchecked only for the human-only cases the reference defines, and n
73
77
 
74
78
  ### Pre-publish scan
75
79
 
76
- Before running the final command, run the scan in `${CLAUDE_SKILL_DIR}/references/publish.md` against the PR title and body. The title and body go straight to the remote with nothing checking them on the way, so run the scan regardless of what backs it downstream. It covers the phase-label check as well as the characters, since both go to a reader who has no task board. It applies on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/pr.md`.
80
+ Before running the final command, run the scan in `${CLAUDE_SKILL_DIR}/references/publish.md` against the PR title and body, on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/pr.md`. The title and body go straight to the remote, so run it whatever backs it downstream.
81
+
82
+ - It covers the phase-label check as well as the characters, since both reach a reader who has no task board
83
+ - It stays required where a `pull_request` job runs the same verb, since an older `canon` carries no such job and none of the newer keys
77
84
 
78
- Write the body here, ahead of the final command, since the scan below needs a file to read it from:
85
+ Write the body here, ahead of the final command, since the scan needs a file to read it from:
79
86
 
80
87
  ```bash
81
88
  mkdir -p .canon/tmp/pr
@@ -90,70 +97,75 @@ Then run:
90
97
  canon labels scan --title "<title>" --body-file .canon/tmp/pr/body.md --json
91
98
  ```
92
99
 
93
- Branch on the JSON record rather than the exit code. An operator's shell can wrap `canon` in a function whose status comes from a trailing command, flattening a non-zero exit to 0, the same reason the labels step below branches on its own record rather than the exit.
100
+ ### Reading the scan
101
+
102
+ Branch on the JSON record rather than the exit code, since a shell function wrapping `canon` can flatten a non-zero exit to 0. Stop and fix the title or body on any key below, and do not proceed to `### Final command` until a re-run comes back clean on all six.
94
103
 
95
- Stop and fix the title or body on a non-empty `phaseLabels`, `boardReferences`, `sessionLinks`, `titleFormatIssues`, `bannedCharacters`, or a `sections` record with anything in `outside` or `missing`. Do not proceed to `### Final command` until a re-run comes back clean on all six. `titleFormatIssues` names which `## Title` rule in `${CLAUDE_SKILL_DIR}/references/pr.md` the title breaks, structure, casing, or length, so fix the named rule rather than guessing. `sections.outside` lists each heading to rename or drop, `sections.missing` each required heading to add, and `bannedCharacters` names the character to restructure the sentence around. Leave `cutsRelease` and `semverTags` alone, since a release-please pull request legitimately carries version references its own fixed shape explains.
104
+ | Key | Fix |
105
+ | ------------------- | ------------------------------------------------------------------------------------ |
106
+ | `phaseLabels` | Remove the phase label |
107
+ | `boardReferences` | Remove the board reference |
108
+ | `sessionLinks` | Remove the session link |
109
+ | `titleFormatIssues` | Fix the `## Title` rule in `pr.md` it names, being structure, casing, or length |
110
+ | `bannedCharacters` | Restructure the sentence around the named character |
111
+ | `sections` | Rename or drop each heading in `outside`, and add each required heading in `missing` |
96
112
 
97
- The scan stays required even where a `pull_request` workflow job runs the same verb, since a project holding an older `canon` carries no such job and no `titleFormatIssues`, `sections`, or `bannedCharacters` key.
113
+ Leave `cutsRelease` and `semverTags` alone, since a release-please pull request legitimately carries version references its own fixed shape explains.
98
114
 
99
115
  ### Resolving the pull request
100
116
 
101
117
  The run resolves the pull request once, in the final command below, and every later step reads what that command printed. Nothing else looks the number up again.
102
118
 
103
- Never detect by head branch alone. A lookup that ignores state returns the closed pull request a reused branch name left behind, and the run rewrites it. Scoping the lookup to `state=open` returns empty there and sends the run down the create path.
104
-
105
- The lookup scopes to the base as well as the head. One head can carry open pull requests against two bases, and a lookup reading the first result would pick between them by list order. Resolving the base from the repository's default branch is what makes the detection and the create agree on which pull request the run is about.
106
-
107
- Every call goes through `gh api` against the REST endpoints rather than through `gh pr` or `gh repo view`, which run on GraphQL. A cloud session's GitHub access blocks GraphQL and serves REST, so the same block converges on a laptop and on a cloud VM.
119
+ - Never detect by head branch alone. A lookup ignoring state returns the closed pull request a reused branch name left behind, so scope it to `state=open`.
120
+ - Scope the lookup to the base as well as the head, resolved from the default branch, so detection and create agree on one pull request. A head can carry two bases.
121
+ - Call `gh api` against REST rather than `gh pr` or `gh repo view`, which run on GraphQL. A cloud session's GitHub access blocks GraphQL and serves REST.
108
122
 
109
123
  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>`.
110
124
 
111
125
  ### Labels
112
126
 
113
- Read `${CLAUDE_SKILL_DIR}/references/labels.md` on reaching this step, starting at its `## Labels at run time` section, for the verb to ask, the record to branch on, the fallback, and when `pr_labels` stays empty. The final command below takes the set it resolves as `pr_labels` and the record's `uncovered` paths as `pr_uncovered`, which only its fallback path reads.
127
+ Read `${CLAUDE_SKILL_DIR}/references/labels.md` on reaching this step, starting at its `## Labels at run time` section, for the verb to ask, the record to branch on, the fallback, and when `pr_labels` stays empty.
114
128
 
115
- ### Final command
129
+ The final command takes the resolved set as `pr_labels` and the record's `uncovered` paths as `pr_uncovered`, which only its fallback path reads.
116
130
 
117
- Read `${CLAUDE_SKILL_DIR}/references/final-command.md` on reaching this step for the one command that pushes, finds or creates the pull request over REST, re-scans its live body for a session link, applies the labels through `canon labels apply`, and prints `number=`, `url=`, `head=`, `owed=`, `missingOnRemote=`, and `uncovered=`, and for the check binding every write to this branch's pull request.
118
-
119
- ### Post the rendered-surface evidence
120
-
121
- Run this step on every pull request this skill opens or edits. Read `${CLAUDE_SKILL_DIR}/references/evidence.md` for finding the checklist and the local server, posting the evidence comparison, posting the checklist alone, and posting the preview address, each against the `<number>` the final command printed. Never judge from the diff whether an evidence image changed, since the verb answers `no-evidence` for a branch that changed none and a session cannot see an image it did not author.
122
-
123
- ### Record the number on the task
124
-
125
- Write the `number` the final command printed onto the task the branch is closing, through `canon tasks pull-request`, and never resolve it again. Read `${CLAUDE_SKILL_DIR}/references/task-number.md` on reaching this step for which task it names, the invocation, the refusals it skips silently, and why the number lands here. Skip it when the final command refused on a head mismatch and printed no number.
126
-
127
- ## After execution
131
+ ### Final command
128
132
 
129
- Respond with one line, using the `url` the final command printed:
133
+ Read `${CLAUDE_SKILL_DIR}/references/final-command.md` on reaching this step, for the one command that pushes and finds or creates the pull request over REST, and for the check binding every write to this branch's pull request.
130
134
 
131
- `✅ PR: <url>`
135
+ That command re-scans the live body for a session link, applies the labels through `canon labels apply`, and prints `number=`, `url=`, `head=`, `owed=`, `missingOnRemote=`, and `uncovered=`.
132
136
 
133
- Add a line for each path in the `uncovered=` value the final command printed, naming the path and the map it belongs in:
137
+ ### Post the rendered-surface evidence
134
138
 
135
- `⚠️ No label covers <path>. Add a row to canon/config/pr-labels.toml or a [declined] entry.`
139
+ Run this step on every pull request this skill opens or edits. Read `${CLAUDE_SKILL_DIR}/references/evidence.md` for finding the checklist and the local server and for posting the evidence comparison, the checklist alone, and the preview address, each against the `<number>` the final command printed.
136
140
 
137
- Add a further line only when `owed=` or `missingOnRemote=` printed a value, naming each owed label, `owed=` less the names in `missingOnRemote=`, and separately the names in `missingOnRemote=`, since `owed=` already holds every absent label. Drop either half that is empty:
141
+ Never judge from the diff whether an evidence image changed, since the verb answers `no-evidence` for a branch that changed none and a session cannot see an image it did not author.
138
142
 
139
- `⚠️ Labels not applied: <owed labels not in missingOnRemote>. Not on the remote: <missingOnRemote labels>.`
143
+ ### Record the number on the task
140
144
 
141
- Add a line when a checklist was posted, naming the pull request it landed on and which comment carries it:
145
+ Write the `number` the final command printed onto the task the branch is closing, through `canon tasks pull-request`, and never resolve it again. Skip it when the final command refused on a head mismatch and printed no number.
142
146
 
143
- `📋 Posted the UI checklist to <number>, in the evidence comment.`
147
+ Read `${CLAUDE_SKILL_DIR}/references/task-number.md` on reaching this step for which task it names, the invocation, the refusals it skips silently, and why the number lands here.
144
148
 
145
- `📋 Posted the UI checklist to <number>, on its own.`
149
+ ## After execution
146
150
 
147
- Add a line when the preview step returned an address:
151
+ Respond with `✅ PR: <url>`, using the `url` the final command printed, then add only the lines below whose condition holds. Add no other text.
148
152
 
149
- `🔗 Preview: <url>`
153
+ | Condition | Line |
154
+ | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
155
+ | Each path in `uncovered=` | `⚠️ No label covers <path>. Add a row to canon/config/pr-labels.toml or a [declined] entry.` |
156
+ | `owed=` or `missingOnRemote=` printed a value | `⚠️ Labels not applied: <owed labels not in missingOnRemote>. Not on the remote: <missingOnRemote labels>.` |
157
+ | A checklist posted in the evidence comment | `📋 Posted the UI checklist to <number>, in the evidence comment.` |
158
+ | A checklist posted alone | `📋 Posted the UI checklist to <number>, on its own.` |
159
+ | The preview step returned an address | `🔗 Preview: <url>` |
160
+ | The evidence step posted the local link | `🖥️ Local preview: <url>` |
161
+ | The local step refused and evidence or a checklist posted | `🖥️ No local preview: <reason>` |
150
162
 
151
- Add a line when the evidence step posted the local link:
163
+ ### The labels line
152
164
 
153
- `🖥️ Local preview: <url>`
165
+ `owed=` already holds every absent label, so the first half names `owed=` less the names in `missingOnRemote=`, and the second names `missingOnRemote=` alone. Drop either half that is empty.
154
166
 
155
- Add a line instead when the local step refused as `no-server` or `no-listener-reader` and the evidence or checklist step posted something, since that pull request changes a rendered surface and a reviewer could have used the link. To add it later, start the server, run `canon pr local --json`, then run `canon pr evidence <number> --local <url> --json`, adding `--checklist` when one is still owed, and post the body the way the evidence step does. `git-followup` only carries a line forward, so it cannot add one the comment never had:
167
+ ### The no-local-preview line
156
168
 
157
- `🖥️ No local preview: <reason>`
169
+ It fires when the local step refused as `no-server` or `no-listener-reader`, since that pull request changes a rendered surface and a reviewer could have used the link. `git-followup` only carries a line forward, so it cannot add one the comment never had.
158
170
 
159
- Do not add any other text.
171
+ To add the link later, start the server and run `canon pr local --json`, then `canon pr evidence <number> --local <url> --json`, adding `--checklist` when one is still owed. Post the body the way the evidence step does.
@@ -9,15 +9,19 @@ metadata:
9
9
 
10
10
  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.
11
11
 
12
- 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`, emitted on the wake after the step 9 watch exits on `passing` rather than when the turn ends on the watch line, unless a wrapping caller states it closes on its own block, which `auto-ship` does.
12
+ 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`, emitted on the wake after the step 9 watch exits on `passing`, unless a wrapping caller such as `auto-ship` closes on its own block.
13
13
 
14
14
  ## Verify
15
15
 
16
- Run the verify commands `CLAUDE.md` names (lint, typecheck, tests) before the sequence starts. On a failure, stop: `❌ Verify failed. Fix the reported errors and run /git-ship again.` Make no fix attempt. This skill is the resume point after a stop, so the fix is the one the user is already making.
16
+ Run the verify commands `CLAUDE.md` names (lint, typecheck, tests) before the sequence starts. On a failure, stop: `❌ Verify failed. Fix the reported errors and run /git-ship again.` Make no fix attempt, since this skill is the resume point and the user is already making the fix.
17
17
 
18
18
  When `CLAUDE.md` names no verify command, say so on one line and continue. A project with no suite is not a project with a failing one.
19
19
 
20
- Verify runs ahead of the sync skills so a stop leaves the tree exactly as the user left it. Re-running a suite the caller already ran costs one command, and the path it closes is the one that has no other guard: `auto-ship` verifies at its own Step 3 and then hands three of its stop points straight back here, so a fix made by hand after one of those stops otherwise reaches the remote with nothing re-run.
20
+ ### Why verify runs first
21
+
22
+ Verify runs ahead of the sync skills so a stop leaves the tree exactly as the user left it. Re-running a suite the caller already ran costs one command.
23
+
24
+ The path it closes has no other guard. `auto-ship` verifies at its own Step 3 and hands three of its stop points back here, so a hand fix after one of those would otherwise reach the remote with nothing re-run.
21
25
 
22
26
  ## Pre-check
23
27
 
@@ -29,60 +33,65 @@ Run `git diff --cached --name-only 2>/dev/null` to check for staged files. If ou
29
33
  2. Invoke `canon:task-complete` to mark the outcomes the diff shipped
30
34
  3. Invoke `canon:docs-sync` to sync public docs against changes since main
31
35
  4. Run `git add -A` to stage any files the sync skills wrote
32
- 5. Run `canon tasks plan-reach <plan> --json` and report both lists it carries. Name the plan this branch built under, by path or by slug. Read `claimed` first and say who holds each path, since that is the half a reader acts on, then say how many of the changed paths `undeclared` names. Branch on the record rather than on the exit code, which a shell function wrapping `canon` can flatten to zero. This step reports and never stops the sequence.
33
- 6. Invoke `canon:git-stage` to group staged changes and commit by concern, only when `git diff --cached --name-only` prints a path. When it prints nothing, the work already reached history in slices, so continue to step 7.
36
+ 5. Run `canon tasks plan-reach <plan> --json`, naming this branch's plan by path or slug, and report both lists per `### Reading the reach` below. This step never stops the sequence.
37
+ 6. Invoke `canon:git-stage` to commit by concern, only when `git diff --cached --name-only` prints a path. When it prints nothing, the work already reached history in slices, so continue.
34
38
  7. Invoke `canon:git-branch` to rename branch to match conventional format
35
39
  8. Invoke `canon:git-pr` to push branch and open pull request
36
40
  9. After the PR opens, watch CI in the background, so the session stays reachable while CI runs. Read `### Watching CI` below for the commands and the wake.
37
41
 
38
- A caller wrapping this sequence may act between step 8 and step 9, which is the one gap the order leaves open, since the pull request exists there and nothing has read its checks yet. `auto-ship` marks the pull request draft in it. Nothing else may go there, and a caller that needs a step anywhere else in the sequence is asking for a change to this body rather than for a place to stand.
42
+ A caller wrapping this sequence may act between step 8 and step 9, the one gap the order leaves open, since the pull request exists and nothing has read its checks. `auto-ship` marks the pull request draft there. A caller needing a step anywhere else is asking for a change to this body.
39
43
 
40
- ### Watching CI
44
+ ### Reading the reach
41
45
 
42
- Run `canon pr checks <number> --json` once in the foreground. When no record comes back at all, the target's CLI predates the verb, and the watch command is `gh pr checks <number> --watch`. The loop below would never exit on such a target, since an empty read never satisfies its test.
46
+ Read `claimed` first and say who holds each path, since that is the half a reader acts on, then say how many changed paths `undeclared` names. Branch on the record rather than the exit code, which a shell function wrapping `canon` can flatten to zero.
43
47
 
44
- Otherwise start this loop through the Bash tool with `run_in_background` and a 60-minute timeout:
48
+ ### Why the reach reads at step 5
45
49
 
46
- ```bash
47
- until canon pr checks <number> --json | jq -e '.state != "pending" or .conflicted == true' >/dev/null; do sleep 30; done; canon pr checks <number> --json
48
- ```
50
+ The branch is whole at step 5 and nowhere earlier. Steps 1 and 3 write past what the plan declared, and no pull request exists to carry the answer until step 8.
49
51
 
50
- Emit `⏳ Watching CI on #<number> in the background` and end the turn. Print nothing more while the watch runs. The session wakes when the command exits, and the wake resumes this step rather than restarting the sequence at step 1. A wake that lands while the session is inside another skill, such as a `review-address` pass a message started during the watch, goes to whichever step is waiting on CI.
52
+ It reports rather than acts because every crossing measured on the wave it was filed against merged clean. The undeclared list runs long enough on an ordinary branch that a gate would fire on nearly every ship.
51
53
 
52
- On the wake, branch on the final record's fields rather than on the exit:
54
+ ### When the verb is absent
53
55
 
54
- - `state: passing`: read the evidence thread under `### Settling the evidence thread` below, then continue to After completion on `settled`.
55
- - `state: failing`: stop the sequence and report the failing check with its URL.
56
- - `conflicted: true`: stop the sequence and report that the branch conflicts with its base, since no run will start for it. A rebase is the repair.
56
+ An installed binary carrying no `plan-reach` subcommand reports the reach unread rather than clear. Say that, and continue.
57
57
 
58
- #### Refused and unsettled reads
58
+ The verb ships with the CLI and this body with the plugin, so an older binary meets a missing subcommand. Reading that absence as clean would report the check passing on every branch that never ran it.
59
59
 
60
- - A `reason` and no `state`: the read was refused, such as `no-remote-branch` for a branch deleted on the remote. Stop and report that `reason`. A missing `state` is never a pass.
61
- - The command hit its timeout and printed no final record: report CI unsettled after 60 minutes, and emit no `✅ Shipped`.
62
- - The `gh pr checks --watch` fallback ran, which prints a check table rather than a record. Only a printed table carrying at least one check, every one passing, continues to After completion. Any failing check stops the sequence naming it with its URL. Empty or errored output stops the sequence and reports the message, since `no checks reported on the '<branch>' branch` is what a conflicted branch prints, and that fallback has no `conflicted` field to separate it from lag.
60
+ ### Watching CI
63
61
 
64
- Do not auto-fix any of these. The watch line and a stop report from any branch above are the two exceptions to the no-text-between-steps rule.
62
+ Run `canon pr checks <number> --json` once in the foreground. When no record comes back at all, the CLI predates the verb, so read `${CLAUDE_SKILL_DIR}/references/ci-watch.md` for the fallback watch. Otherwise start this loop through the Bash tool with `run_in_background` and a 60-minute timeout:
65
63
 
66
- ### Settling the evidence thread
64
+ ```bash
65
+ until canon pr checks <number> --json | jq -e '.state != "pending" or .conflicted == true' >/dev/null; do sleep 30; done; canon pr checks <number> --json
66
+ ```
67
67
 
68
- On a `passing` wake, run `canon pr evidence <number> --check --json` against the number step 8 returned. It reads the pull request's comments and edits none, so the comment a reviewer already ticked stays as it is. Branch on `reason` and `owed` rather than the exit.
68
+ Emit `⏳ Watching CI on #<number> in the background` and end the turn, printing nothing more while the watch runs. The wake resumes this step rather than restarting at step 1, and a wake landing inside another skill, such as a `review-address` pass, goes to whichever step is waiting on CI.
69
69
 
70
- - `settled`: nothing is owed, which is also what a branch that changed no rendered surface reads. Continue to After completion.
71
- - `owed`: run each step the record's `owed` list names, from `canon:git-pr`'s `references/evidence.md`, evidence first and then preview. Re-read once with the same command. Continue to After completion only on `settled`. Any other reading stops the sequence and reports the `reason` with the `owed` list, and the sequence never loops back for a second pass. A preview step that refuses, or a deploy that failed, leaves `preview` owed on the re-read, so that is the stop and not a retry.
72
- - Any other `reason`, such as `gh-failed`: the thread went unread. Stop and report the `reason`, since an unread thread is not a settled one.
73
- - No record at all, or an unknown flag error: the installed binary predates `--check`. Report the thread unread rather than settled, and continue to After completion without emitting a claim that it was checked.
70
+ ### Reading the wake
74
71
 
75
- The read is a closing step and the draft mark stays the only thing between steps 8 and 9. A caller that closes on its own block, as `auto-ship` does, waits on the same CI wake, so the read lands here and not in that body.
72
+ Branch on the final record's fields rather than on the exit. Do not auto-fix any reading, and the watch line and a stop report are the two exceptions to the no-text-between-steps rule.
76
73
 
77
- ### Why the reach reads at step 5
74
+ | Record | Route |
75
+ | --------------------------------------- | ------------------------------------------------------------------------------------- |
76
+ | `state: passing` | Settle the evidence thread below, then continue to After completion on `settled` |
77
+ | `state: failing` | Stop the sequence and report the failing check with its URL |
78
+ | `conflicted: true` | Stop and report the branch conflicts with its base, since no run will start. Rebase. |
79
+ | A `reason` and no `state`, or a timeout | Read `${CLAUDE_SKILL_DIR}/references/ci-watch.md` for the refused and unsettled reads |
80
+
81
+ ### Settling the evidence thread
78
82
 
79
- The branch is whole there and nowhere earlier. Steps 1 and 3 write past whatever the plan declared, so a reading taken ahead of them misses the chain's own additions, and no pull request exists until step 8 to carry the answer anywhere.
83
+ On a `passing` wake, run `canon pr evidence <number> --check --json` against the number step 8 returned. It reads the comments and edits none, so a comment a reviewer ticked stays as it is. Branch on `reason` and `owed` rather than the exit.
80
84
 
81
- It is the one step here that reports rather than acts, which is why it never stops the sequence. Every crossing measured on the wave it was filed against merged clean, and the undeclared list runs long enough on an ordinary branch that a gate would fire on nearly every ship.
85
+ | Reading | Route |
86
+ | --------------------------------------- | ------------------------------------------------------------------------------------------------------- |
87
+ | `settled` | Nothing is owed, as on a branch that changed no rendered surface, so continue |
88
+ | `owed` | Run each step the `owed` list names, then re-read once, as below |
89
+ | Any other `reason`, such as `gh-failed` | Stop and report it, since an unread thread is not a settled one |
90
+ | No record, or an unknown flag error | The binary predates `--check`, so report the thread unread and continue without claiming it was checked |
82
91
 
83
- ### When the verb is absent
92
+ On `owed`, run the named steps from `canon:git-pr`'s `references/evidence.md`, evidence first and then preview, and re-read with the same command. Continue only on `settled`, and stop on any other reading with the `reason` and the `owed` list, never looping back.
84
93
 
85
- An installed binary carrying no `plan-reach` subcommand reports the reach unread rather than clear. Say that, and continue. The verb ships with the CLI and this body ships with the plugin, so a target on an older binary meets a missing subcommand, and a body reading that absence as a clean answer would report the check passing on every branch that never ran it.
94
+ A refused preview step or a failed deploy leaves `preview` owed on the re-read, so that is the stop and not a retry. The read is a closing step, so the draft mark stays the only thing between steps 8 and 9, and a caller closing on its own block waits on the same wake.
86
95
 
87
96
  ## After completion
88
97
 
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: CI watch fallback and refusals
3
+ description: What the git-ship CI watch does when the installed CLI predates the checks verb, when a read is refused, and when the watch times out
4
+ ---
5
+
6
+ # CI watch fallback and refusals
7
+
8
+ Applies to step 9 of `git-ship` once the watch wakes on anything but a `state` of `passing` or `failing` or a `conflicted: true` record, and to a target whose CLI carries no `canon pr checks`.
9
+
10
+ ## The fallback watch
11
+
12
+ When `canon pr checks <number> --json` returns no record at all, the target's CLI predates the verb, and the watch command is `gh pr checks <number> --watch`. The polling loop would never exit on such a target, since an empty read never satisfies its test.
13
+
14
+ The fallback prints a check table rather than a record, and has no `conflicted` field to separate a conflict from lag.
15
+
16
+ | Output | Route |
17
+ | ------------------------------------- | ----------------------------------------- |
18
+ | At least one check, every one passing | Continue to After completion |
19
+ | Any failing check | Stop the sequence, naming it with its URL |
20
+ | Empty or errored | Stop the sequence and report the message |
21
+
22
+ Empty output stops rather than waits, since `no checks reported on the '<branch>' branch` is what a conflicted branch prints.
23
+
24
+ ## Refused and unsettled reads
25
+
26
+ Neither of these is a pass, and neither emits `✅ Shipped`.
27
+
28
+ - A `reason` and no `state` means the read was refused, such as `no-remote-branch` for a branch deleted on the remote. Stop and report that `reason`.
29
+ - A watch that hit its timeout and printed no final record is CI unsettled after 60 minutes, so report it that way
30
+
31
+ Do not auto-fix any of these. A stop report is one of the two exceptions to the no-text-between-steps rule.
@@ -39,15 +39,18 @@ Run these commands in parallel to gather git context:
39
39
 
40
40
  ### Primary concern
41
41
 
42
- - Identify the primary concern of the current branch. Rename it using `git branch -m` if the current name does not already match. Skip the rename if it already matches. Secondary concerns are extracted as new focused branches via cherry-pick.
43
- - If no single concern dominates (dumping-ground branch with no clear primary), split all commits into new focused branches and add `git branch -d <current>` to delete the original.
42
+ The current branch keeps its primary concern, and each secondary concern leaves as a new focused branch via cherry-pick.
43
+
44
+ - Rename the current branch with `git branch -m` when its name does not match the primary concern, and skip the rename when it does
45
+ - If no single concern dominates, as on a dumping-ground branch, split every commit into new branches and add `git branch -d <current>`
44
46
  - Propose one new branch per secondary concern following branch.md format.
45
47
 
46
48
  ### Independent and stacked
47
49
 
48
- - Classify groups as independent or stacked before generating commands.
50
+ Classify the groups before generating commands, since the mode decides each branch's base.
51
+
49
52
  - Independent groups: each group's commits apply to `main` without the others. Base every branch on `main`.
50
- - Stacked groups: groups are ordered and each depends on the commits before it. Base each branch on the previous group's branch. Cherry-pick only that group's commits onto it. The base branch already carries all prior commits.
53
+ - Stacked groups: groups are ordered and each depends on the commits before it. Base each branch on the previous group's branch and cherry-pick only that group's commits.
51
54
 
52
55
  ## Response format
53
56
 
@@ -64,118 +67,43 @@ Run these commands in parallel to gather git context:
64
67
 
65
68
  **All <total> commits accounted for.**
66
69
 
67
- - For the primary concern (the current branch), show `<current_branch> → <new_name>` only when renaming. Show `<current_branch>` alone if the existing name already matches the concern.
70
+ - For the primary concern, show `<current_branch> → <new_name>` only when renaming, and `<current_branch>` alone otherwise
68
71
  - For stacked mode, list rows in merge order: branches based on `main` first, then each layer above. For independent mode, list the primary concern first.
69
72
 
70
- If Mode is Stacked, append this line to the preview:
71
-
72
- `🔁 Sequential squash-merge loop. Squash-merge each PR bottom-up with --delete-branch. After each merge, signal me so I can restack the next branch onto main before you merge it.`
73
+ ### Merge order line
73
74
 
74
- If Mode is Independent, append this line to the preview:
75
+ Append the line for the run's mode to the preview.
75
76
 
76
- `🔁 Squash-merge secondaries first, primary last. The primary keeps every cherry-picked commit, so merging it first lands every secondary's content on main and leaves the secondary PRs empty after rebase.`
77
+ | Mode | Line |
78
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
79
+ | Stacked | `🔁 Sequential squash-merge loop. Squash-merge each PR bottom-up with --delete-branch. After each merge, signal me so I can restack the next branch onto main before you merge it.` |
80
+ | Independent | `🔁 Squash-merge secondaries first, primary last. The primary keeps every cherry-picked commit, so merging it first lands every secondary's content on main and leaves the secondary PRs empty after rebase.` |
77
81
 
78
82
  After outputting the preview, execute the final commands immediately. Claude Code's tool permission dialog is the confirmation gate. Do not wait for user input.
79
83
 
80
- Before running them, run the scan in `${CLAUDE_SKILL_DIR}/../git-pr/references/publish.md` against every title and body. Each body stages under `.canon/tmp/` and leaves through `gh`, so the hook sees neither and this scan is the only gate. Each resulting branch reaches the `pull_request` check the git-pr surface carries once its own pull request opens, but not before, so this scan is what catches a leak ahead of that.
84
+ ### Pre-publish scan
81
85
 
82
- ### Final commands
86
+ Before running them, run the scan in `${CLAUDE_SKILL_DIR}/../git-pr/references/publish.md` against every title and body. Each body stages under `.canon/tmp/` and leaves through `gh`, so the hook sees neither.
83
87
 
84
- For independent mode, base every branch on `main`:
85
-
86
- ```bash
87
- # Rename current branch to reflect primary concern
88
- git branch -m <current_branch> <new_name>
89
-
90
- # Create, cherry-pick, push, and open PR for each secondary branch
91
- mkdir -p .canon/tmp/pr/split
92
- git switch -c <branch> main && git cherry-pick <sha> <sha> \
93
- && git push -u origin <branch> \
94
- && (cat <<'BODY' > .canon/tmp/pr/split/<branch>.md
95
- <body following pr.md template, written from the cherry-picked commits>
96
- BODY
97
- ) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<branch> -f base=main -F body=@.canon/tmp/pr/split/<branch>.md --jq .html_url \
98
- && printf 'opened=true\n' \
99
- && rm .canon/tmp/pr/split/<branch>.md
100
-
101
- # Return to primary branch, push, and open its PR
102
- git checkout <new_name> && git push -u origin <new_name> \
103
- && (cat <<'BODY' > .canon/tmp/pr/split/<new_name>.md
104
- <body following pr.md template, written from the primary's commits>
105
- BODY
106
- ) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<new_name> -f base=main -F body=@.canon/tmp/pr/split/<new_name>.md --jq .html_url \
107
- && printf 'opened=true\n' \
108
- && rm .canon/tmp/pr/split/<new_name>.md
109
-
110
- # Clean up the body-file dir if all PRs succeeded (no-op when non-empty)
111
- rmdir .canon/tmp/pr/split 2>/dev/null || true
112
- ```
113
-
114
- Every pull request opens through the REST pulls endpoint rather than the `gh pr` create subcommand, which runs on GraphQL and fails where a cloud session's GitHub proxy refuses it. The endpoint requires `base`, so each call names the branch its layer sits on. `-F` reads the body file, where `-f` would post the path itself.
115
-
116
- A create the endpoint refuses, such as one for a head that already has an open pull request, exits non-zero and stops the chain before `opened=true` prints and before the body file is removed. The `opened=true` line is what a pull request creation log reads to count the opening, since the REST call prints a URL and never names itself.
117
-
118
- For stacked mode, base each branch on the previous and cherry-pick only that group's commits:
119
-
120
- ```bash
121
- # Rename current branch to reflect primary concern
122
- git branch -m <current_branch> <new_name>
123
-
124
- mkdir -p .canon/tmp/pr/split
125
-
126
- # Group 1: based on main
127
- git switch -c <branch-1> main && git cherry-pick <g1-sha> <g1-sha> \
128
- && git push -u origin <branch-1> \
129
- && (cat <<'BODY' > .canon/tmp/pr/split/<branch-1>.md
130
- <body following pr.md template, written from the cherry-picked commits>
131
- BODY
132
- ) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<branch-1> -f base=main -F body=@.canon/tmp/pr/split/<branch-1>.md --jq .html_url \
133
- && printf 'opened=true\n' \
134
- && rm .canon/tmp/pr/split/<branch-1>.md
135
-
136
- # Group 2: based on <branch-1>, this group's commits only
137
- git checkout -b <branch-2> && git cherry-pick <g2-sha> <g2-sha> \
138
- && git push -u origin <branch-2> \
139
- && (cat <<'BODY' > .canon/tmp/pr/split/<branch-2>.md
140
- <body following pr.md template, written from the cherry-picked commits>
141
- BODY
142
- ) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<branch-2> -f base=<branch-1> -F body=@.canon/tmp/pr/split/<branch-2>.md --jq .html_url \
143
- && printf 'opened=true\n' \
144
- && rm .canon/tmp/pr/split/<branch-2>.md
145
-
146
- # Return to primary branch, push, and open its PR on the last group's branch
147
- git checkout <new_name> && git push -u origin <new_name> \
148
- && (cat <<'BODY' > .canon/tmp/pr/split/<new_name>.md
149
- <body following pr.md template, written from the primary's commits>
150
- BODY
151
- ) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<new_name> -f base=<branch-2> -F body=@.canon/tmp/pr/split/<new_name>.md --jq .html_url \
152
- && printf 'opened=true\n' \
153
- && rm .canon/tmp/pr/split/<new_name>.md
154
-
155
- # Clean up the body-file dir if all PRs succeeded (no-op when non-empty)
156
- rmdir .canon/tmp/pr/split 2>/dev/null || true
157
- ```
88
+ Each branch reaches the `pull_request` check only once its own pull request opens, so this scan is what catches a leak ahead of that.
158
89
 
159
- ## After execution
90
+ ### Final commands
160
91
 
161
- Respond with exactly one line:
92
+ Read the command block for the run's mode on reaching this step, and skip the other.
162
93
 
163
- `✅ Renamed: <old> → <new> | PRs: <primary-url>, <url1>, <url2>`
94
+ - Independent mode: `${CLAUDE_SKILL_DIR}/references/independent.md`
95
+ - Stacked mode: `${CLAUDE_SKILL_DIR}/references/stacked.md`
164
96
 
165
- Read each URL off the line its create printed through `--jq .html_url`.
97
+ Every pull request opens through the REST pulls endpoint rather than the `gh pr` create subcommand, which runs on GraphQL and fails where a cloud session's GitHub proxy refuses it. The endpoint requires `base`, so each call names its layer's branch, and `-F` reads the body file where `-f` would post the path.
166
98
 
167
- Do not add any other text.
99
+ A create the endpoint refuses, such as one for a head with an open pull request, exits non-zero and stops the chain before `opened=true` prints and the body file is removed. A pull request creation log counts openings off `opened=true`, since the REST call prints a URL and never names itself.
168
100
 
169
- ## Stacked merge loop
101
+ ## After execution
170
102
 
171
- When the user signals the previous stacked PR has merged, restack the next one.
103
+ Respond with exactly one line and add no other text, reading each URL off the line its create printed through `--jq .html_url`:
172
104
 
173
- 1. Rebase and push. The own-commit-count comes from the original split table.
174
- `git fetch origin main && git checkout <branch> && git rebase --onto origin/main HEAD~<own-commit-count> && git push --force-with-lease`
175
- 2. Verify the PR's base auto-retargeted to main with `gh api repos/{owner}/{repo}/pulls/<num> --jq .base.ref`, a REST read a cloud session's GitHub proxy serves where it refuses GraphQL. If not, retarget it with `gh api -X PATCH repos/{owner}/{repo}/pulls/<num> -f base=main --silent`.
176
- 3. Reply: `✅ <branch> rebased onto main. Ready for squash-merge.`
105
+ `✅ Renamed: <old> → <new> | PRs: <primary-url>, <url1>, <url2>`
177
106
 
178
- Edge cases:
107
+ ## Stacked merge loop
179
108
 
180
- - If this branch's commits modify a file added by an unmerged upstream PR, wait for that PR to merge before rebasing.
181
- - If the PR was orphaned by base-branch deletion, recreate it with the same create the final commands run, passing `-f head=<branch> -f base=main` and a regenerated body, and print `opened=true` after it.
109
+ When the user signals the previous stacked PR has merged, restack the next one. Read `${CLAUDE_SKILL_DIR}/references/stacked.md` from its `## Stacked merge loop` section for the rebase, the retarget, the reply, and the two edge cases. An independent split skips it.
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Independent split commands
3
+ description: The final commands git-split runs in independent mode, basing every new branch on main and opening each pull request over REST
4
+ ---
5
+
6
+ # Independent split commands
7
+
8
+ Applies to a `git-split` run whose preview reads `Mode: Independent`. Every branch is based on `main`, since each group's commits apply there without the others.
9
+
10
+ ## Final commands
11
+
12
+ ```bash
13
+ # Rename current branch to reflect primary concern
14
+ git branch -m <current_branch> <new_name>
15
+
16
+ # Create, cherry-pick, push, and open PR for each secondary branch
17
+ mkdir -p .canon/tmp/pr/split
18
+ git switch -c <branch> main && git cherry-pick <sha> <sha> \
19
+ && git push -u origin <branch> \
20
+ && (cat <<'BODY' > .canon/tmp/pr/split/<branch>.md
21
+ <body following pr.md template, written from the cherry-picked commits>
22
+ BODY
23
+ ) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<branch> -f base=main -F body=@.canon/tmp/pr/split/<branch>.md --jq .html_url \
24
+ && printf 'opened=true\n' \
25
+ && rm .canon/tmp/pr/split/<branch>.md
26
+
27
+ # Return to primary branch, push, and open its PR
28
+ git checkout <new_name> && git push -u origin <new_name> \
29
+ && (cat <<'BODY' > .canon/tmp/pr/split/<new_name>.md
30
+ <body following pr.md template, written from the primary's commits>
31
+ BODY
32
+ ) && gh api -X POST 'repos/{owner}/{repo}/pulls' -f title="<title>" -f head=<new_name> -f base=main -F body=@.canon/tmp/pr/split/<new_name>.md --jq .html_url \
33
+ && printf 'opened=true\n' \
34
+ && rm .canon/tmp/pr/split/<new_name>.md
35
+
36
+ # Clean up the body-file dir if all PRs succeeded (no-op when non-empty)
37
+ rmdir .canon/tmp/pr/split 2>/dev/null || true
38
+ ```
39
+
40
+ Repeat the secondary block once per secondary branch. The skill body states why each create goes through the REST endpoint and what `opened=true` marks.