@opengsd/gsd-core 1.9.0 → 1.10.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 (223) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -3
  3. package/.opencode/plugins/gsd-core.js +8 -1
  4. package/agents/gsd-code-fixer.md +131 -34
  5. package/agents/gsd-debugger.md +12 -246
  6. package/agents/gsd-executor.md +7 -5
  7. package/agents/gsd-integration-checker.md +3 -0
  8. package/agents/gsd-plan-checker.md +9 -0
  9. package/agents/gsd-planner.md +5 -8
  10. package/agents/gsd-roadmapper.md +21 -3
  11. package/agents/gsd-verifier.md +14 -70
  12. package/bin/install.js +503 -341
  13. package/commands/gsd/mempalace-capture.md +1 -1
  14. package/commands/gsd/new-milestone.md +1 -1
  15. package/commands/gsd/plan-phase.md +1 -1
  16. package/gsd-core/bin/gsd-tools.cjs +607 -63
  17. package/gsd-core/bin/lib/active-workstream-store.cjs +25 -0
  18. package/gsd-core/bin/lib/agent-install-check.cjs +38 -6
  19. package/gsd-core/bin/lib/api-coverage.cjs +120 -0
  20. package/gsd-core/bin/lib/audit.cjs +89 -1
  21. package/gsd-core/bin/lib/broken-windows.cjs +36 -6
  22. package/gsd-core/bin/lib/capability-registry.cjs +96 -110
  23. package/gsd-core/bin/lib/capability-validator.cjs +12 -2
  24. package/gsd-core/bin/lib/check-command-router.cjs +43 -1
  25. package/gsd-core/bin/lib/command-aliases.cjs +72 -0
  26. package/gsd-core/bin/lib/commands.cjs +26 -25
  27. package/gsd-core/bin/lib/commonjs-marker.cjs +136 -0
  28. package/gsd-core/bin/lib/config-loader.cjs +1 -0
  29. package/gsd-core/bin/lib/config.cjs +12 -1
  30. package/gsd-core/bin/lib/context-composer.cjs +278 -0
  31. package/gsd-core/bin/lib/context-predicates.cjs +506 -0
  32. package/gsd-core/bin/lib/core-utils.cjs +91 -12
  33. package/gsd-core/bin/lib/docs.cjs +3 -2
  34. package/gsd-core/bin/lib/external-job.cjs +19 -4
  35. package/gsd-core/bin/lib/frontmatter.cjs +84 -12
  36. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +57 -6
  37. package/gsd-core/bin/lib/git-base-branch.cjs +58 -15
  38. package/gsd-core/bin/lib/graphify.cjs +142 -27
  39. package/gsd-core/bin/lib/gsd2-import.cjs +27 -4
  40. package/gsd-core/bin/lib/host-integration.cjs +13 -1
  41. package/gsd-core/bin/lib/init-command-router.cjs +83 -8
  42. package/gsd-core/bin/lib/init.cjs +1021 -57
  43. package/gsd-core/bin/lib/install-engine.cjs +64 -10
  44. package/gsd-core/bin/lib/install-profiles.cjs +27 -1
  45. package/gsd-core/bin/lib/installer-migration-authoring.cjs +3 -1
  46. package/gsd-core/bin/lib/installer-migration-report.cjs +4 -0
  47. package/gsd-core/bin/lib/installer-migrations/007-retire-config-root-commonjs-marker.cjs +149 -0
  48. package/gsd-core/bin/lib/installer-migrations/008-cursor-retire-commands-surface.cjs +55 -0
  49. package/gsd-core/bin/lib/installer-migrations/009-pi-retire-reserved-hooks-dir.cjs +199 -0
  50. package/gsd-core/bin/lib/installer-migrations.cjs +87 -1
  51. package/gsd-core/bin/lib/io.cjs +28 -3
  52. package/gsd-core/bin/lib/markdown-sectionizer.cjs +6 -0
  53. package/gsd-core/bin/lib/mcp-catalog.cjs +518 -0
  54. package/gsd-core/bin/lib/mcp-server.cjs +135 -3
  55. package/gsd-core/bin/lib/milestone.cjs +106 -51
  56. package/gsd-core/bin/lib/phase-id.cjs +63 -0
  57. package/gsd-core/bin/lib/phase-locator.cjs +138 -45
  58. package/gsd-core/bin/lib/phase.cjs +260 -25
  59. package/gsd-core/bin/lib/plan-dependency-graph.cjs +232 -0
  60. package/gsd-core/bin/lib/planning-workspace.cjs +4 -0
  61. package/gsd-core/bin/lib/project-root.cjs +48 -0
  62. package/gsd-core/bin/lib/prompt-budget.cjs +128 -165
  63. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +80 -0
  64. package/gsd-core/bin/lib/review-lane-descriptor.cjs +99 -0
  65. package/gsd-core/bin/lib/review-lane-runner.cjs +30 -6
  66. package/gsd-core/bin/lib/roadmap-command-router.cjs +42 -9
  67. package/gsd-core/bin/lib/roadmap-parser.cjs +100 -18
  68. package/gsd-core/bin/lib/roadmap.cjs +37 -7
  69. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +195 -62
  70. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +15 -3
  71. package/gsd-core/bin/lib/runtime-homes.cjs +154 -41
  72. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +105 -41
  73. package/gsd-core/bin/lib/section-manifest.cjs +209 -0
  74. package/gsd-core/bin/lib/shell-command-projection.cjs +113 -27
  75. package/gsd-core/bin/lib/smart-entry.cjs +12 -0
  76. package/gsd-core/bin/lib/state-transition.cjs +73 -8
  77. package/gsd-core/bin/lib/state.cjs +151 -62
  78. package/gsd-core/bin/lib/surface.cjs +12 -1
  79. package/gsd-core/bin/lib/uat-predicate.cjs +11 -1
  80. package/gsd-core/bin/lib/uat.cjs +320 -21
  81. package/gsd-core/bin/lib/unusable-input.cjs +9 -0
  82. package/gsd-core/bin/lib/verification.cjs +29 -12
  83. package/gsd-core/bin/lib/verify.cjs +29 -5
  84. package/gsd-core/bin/lib/workflow-fragments.cjs +557 -0
  85. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +181 -18
  86. package/gsd-core/bin/lib/workstream-inventory.cjs +519 -27
  87. package/gsd-core/bin/lib/workstream.cjs +6 -0
  88. package/gsd-core/bin/lib/worktree-base-ref.cjs +50 -6
  89. package/gsd-core/bin/lib/worktree-safety.cjs +276 -118
  90. package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
  91. package/gsd-core/references/artifact-types.md +10 -3
  92. package/gsd-core/references/autonomous-ui-design-contract.md +42 -0
  93. package/gsd-core/references/debugger-techniques.md +255 -0
  94. package/gsd-core/references/research-documentation-lookup.md +5 -3
  95. package/gsd-core/references/specless-probe-fallback.md +7 -6
  96. package/gsd-core/references/verifier-wiring-patterns.md +100 -0
  97. package/gsd-core/references/worktree-branch-check.md +2 -2
  98. package/gsd-core/templates/summary-complex.md +2 -0
  99. package/gsd-core/templates/summary-minimal.md +2 -0
  100. package/gsd-core/templates/summary-standard.md +2 -0
  101. package/gsd-core/templates/summary.md +2 -0
  102. package/gsd-core/workflows/audit-milestone.md +3 -0
  103. package/gsd-core/workflows/autonomous/steps/converge-banner.md +1 -0
  104. package/gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md +11 -0
  105. package/gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md +7 -0
  106. package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +21 -0
  107. package/gsd-core/workflows/autonomous/steps/converge-loop.md +7 -0
  108. package/gsd-core/workflows/autonomous.md +32 -69
  109. package/gsd-core/workflows/code-review/steps/dispatch-fix.md +39 -0
  110. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +83 -0
  111. package/gsd-core/workflows/code-review.md +42 -145
  112. package/gsd-core/workflows/complete-milestone/steps/git-tag.md +29 -0
  113. package/gsd-core/workflows/complete-milestone.md +23 -81
  114. package/gsd-core/workflows/debug.md +9 -12
  115. package/gsd-core/workflows/diagnose-issues.md +22 -0
  116. package/gsd-core/workflows/discovery-phase.md +4 -4
  117. package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +15 -0
  118. package/gsd-core/workflows/discuss-phase-assumptions.md +5 -16
  119. package/gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md +51 -0
  120. package/gsd-core/workflows/docs-update.md +8 -51
  121. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +34 -2
  122. package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +50 -0
  123. package/gsd-core/workflows/execute-phase/steps/partial-wave.md +31 -0
  124. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +19 -0
  125. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +42 -0
  126. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +43 -37
  127. package/gsd-core/workflows/execute-phase.md +65 -137
  128. package/gsd-core/workflows/execute-plan.md +1 -1
  129. package/gsd-core/workflows/help/modes/full.md +6 -1
  130. package/gsd-core/workflows/ingest-docs.md +2 -1
  131. package/gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md +16 -0
  132. package/gsd-core/workflows/new-milestone/steps/reset-phase-safety.md +19 -0
  133. package/gsd-core/workflows/new-milestone.md +21 -38
  134. package/gsd-core/workflows/new-project/steps/auto-mode-config.md +176 -0
  135. package/gsd-core/workflows/new-project/steps/auto-mode-detection.md +32 -0
  136. package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +18 -0
  137. package/gsd-core/workflows/new-project.md +13 -226
  138. package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +15 -0
  139. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +110 -0
  140. package/gsd-core/workflows/plan-phase/steps/prd-express-gate.md +8 -0
  141. package/gsd-core/workflows/plan-phase/steps/research-only-early-exit.md +17 -0
  142. package/gsd-core/workflows/plan-phase/steps/research-only-modifiers.md +16 -0
  143. package/gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md +17 -0
  144. package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +149 -0
  145. package/gsd-core/workflows/plan-phase.md +49 -193
  146. package/gsd-core/workflows/progress/steps/forensic-audit.md +125 -0
  147. package/gsd-core/workflows/progress/steps/mvp-display.md +18 -0
  148. package/gsd-core/workflows/progress.md +11 -153
  149. package/gsd-core/workflows/quick/steps/discussion-phase.md +124 -0
  150. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +111 -0
  151. package/gsd-core/workflows/quick/steps/quick-verification.md +46 -0
  152. package/gsd-core/workflows/quick/steps/research-phase.md +72 -0
  153. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +37 -0
  154. package/gsd-core/workflows/quick.md +20 -390
  155. package/gsd-core/workflows/resume-project.md +3 -0
  156. package/gsd-core/workflows/review/steps/reviewer-instances-note-1.md +4 -0
  157. package/gsd-core/workflows/review/steps/reviewer-instances-note-2.md +3 -0
  158. package/gsd-core/workflows/review.md +15 -8
  159. package/gsd-core/workflows/section-manifest.json +219 -0
  160. package/gsd-core/workflows/sketch.md +1 -1
  161. package/gsd-core/workflows/spec-phase.md +17 -14
  162. package/gsd-core/workflows/spike-wrap-up.md +20 -5
  163. package/gsd-core/workflows/spike.md +50 -16
  164. package/gsd-core/workflows/sync-skills.md +49 -11
  165. package/gsd-core/workflows/transition/steps/workstream-collision-check.md +17 -0
  166. package/gsd-core/workflows/transition.md +8 -21
  167. package/gsd-core/workflows/ui-phase.md +8 -7
  168. package/gsd-core/workflows/update/steps/channel-banner.md +7 -0
  169. package/gsd-core/workflows/update.md +18 -7
  170. package/gsd-core/workflows/verify-phase.md +4 -7
  171. package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +36 -0
  172. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +21 -0
  173. package/gsd-core/workflows/verify-work.md +8 -58
  174. package/hooks/dist/gsd-agent-isolation-guard.js +428 -0
  175. package/hooks/dist/gsd-check-update-worker.js +14 -5
  176. package/hooks/dist/gsd-cursor-subagent-start.js +532 -26
  177. package/hooks/dist/gsd-read-injection-scanner.js +7 -0
  178. package/hooks/dist/gsd-statusline.js +72 -6
  179. package/hooks/dist/gsd-worktree-path-guard.js +2 -1
  180. package/hooks/dist/gsd-write-guard.js +359 -0
  181. package/hooks/dist/lib/isolation-sentinel.js +268 -0
  182. package/hooks/dist/managed-hooks-registry.cjs +2 -0
  183. package/hooks/gsd-agent-isolation-guard.js +428 -0
  184. package/hooks/gsd-check-update-worker.js +14 -5
  185. package/hooks/gsd-cursor-subagent-start.js +532 -26
  186. package/hooks/gsd-read-injection-scanner.js +7 -0
  187. package/hooks/gsd-statusline.js +72 -6
  188. package/hooks/gsd-worktree-path-guard.js +2 -1
  189. package/hooks/gsd-write-guard.js +359 -0
  190. package/hooks/hooks.json +12 -0
  191. package/hooks/lib/isolation-sentinel.js +268 -0
  192. package/hooks/managed-hooks-registry.cjs +2 -0
  193. package/package.json +14 -5
  194. package/pi/gsd.cjs +57 -12
  195. package/scripts/build-hooks.js +9 -0
  196. package/scripts/changeset/lint.cjs +9 -2
  197. package/scripts/changeset/serialize.cjs +5 -1
  198. package/scripts/gen-capability-matrix.cjs +1 -1
  199. package/scripts/gen-context-index.cjs +448 -0
  200. package/scripts/gen-inventory-manifest.cjs +101 -1
  201. package/scripts/gen-prompt-budget-parity-corpus.cjs +645 -0
  202. package/scripts/gen-registry.cjs +39 -15
  203. package/scripts/gen-section-manifest.cjs +638 -0
  204. package/scripts/generate-package-identity.cjs +4 -2
  205. package/scripts/lint-allow-test-rule-refs.allowlist.json +17 -31
  206. package/scripts/lint-compiled-artifact-sync.cjs +6 -1
  207. package/scripts/lint-docs-command-form.cjs +195 -0
  208. package/scripts/lint-docs-required.cjs +9 -1
  209. package/scripts/lint-emitted-drift-ack.cjs +215 -20
  210. package/scripts/lint-example-parser-parity.cjs +395 -0
  211. package/scripts/lint-test-file-count.allowlist.json +27 -1
  212. package/scripts/mutation-matrix.cjs +13 -0
  213. package/scripts/prompt-injection-scan.sh +27 -6
  214. package/scripts/registry-schema.cjs +323 -94
  215. package/scripts/run-tests.cjs +3 -2
  216. package/scripts/validate-registry.cjs +10 -6
  217. package/skills/gsd-autonomous/SKILL.md +1 -1
  218. package/skills/gsd-execute-phase/SKILL.md +1 -1
  219. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  220. package/skills/gsd-new-milestone/SKILL.md +1 -1
  221. package/skills/gsd-plan-phase/SKILL.md +2 -2
  222. package/vscode/package.json +1 -1
  223. package/scripts/gen-emitted-baseline.cjs +0 -145
@@ -0,0 +1,219 @@
1
+ {
2
+ "workflows": {
3
+ "autonomous": [
4
+ {
5
+ "id": "converge-fail-fast",
6
+ "when": "state:plan-strategy-converge",
7
+ "read": "gsd-core/workflows/autonomous/steps/converge-fail-fast.md"
8
+ },
9
+ {
10
+ "id": "converge-banner",
11
+ "when": "state:plan-strategy-converge",
12
+ "read": "gsd-core/workflows/autonomous/steps/converge-banner.md"
13
+ },
14
+ {
15
+ "id": "converge-dispatch-bg",
16
+ "when": "state:plan-strategy-converge",
17
+ "read": "gsd-core/workflows/autonomous/steps/converge-dispatch-bg.md"
18
+ },
19
+ {
20
+ "id": "converge-dispatch-inline",
21
+ "when": "state:plan-strategy-converge",
22
+ "read": "gsd-core/workflows/autonomous/steps/converge-dispatch-inline.md"
23
+ },
24
+ {
25
+ "id": "converge-loop",
26
+ "when": "state:plan-strategy-converge",
27
+ "read": "gsd-core/workflows/autonomous/steps/converge-loop.md"
28
+ }
29
+ ],
30
+ "code-review": [
31
+ {
32
+ "id": "structural-pre-pass",
33
+ "when": "state:fallow-enabled",
34
+ "read": "gsd-core/workflows/code-review/steps/structural-pre-pass.md"
35
+ },
36
+ {
37
+ "id": "dispatch-fix",
38
+ "when": "flag:--fix",
39
+ "read": "gsd-core/workflows/code-review/steps/dispatch-fix.md"
40
+ }
41
+ ],
42
+ "complete-milestone": [
43
+ {
44
+ "id": "git-tag",
45
+ "when": "state:git-create-tag",
46
+ "read": "gsd-core/workflows/complete-milestone/steps/git-tag.md"
47
+ }
48
+ ],
49
+ "discuss-phase-assumptions": [
50
+ {
51
+ "id": "auto-advance-dispatch",
52
+ "when": "state:auto-advance-active",
53
+ "read": "gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md"
54
+ }
55
+ ],
56
+ "docs-update": [
57
+ {
58
+ "id": "dispatch-monorepo-packages",
59
+ "when": "state:is-monorepo",
60
+ "read": "gsd-core/workflows/docs-update/steps/dispatch-monorepo-packages.md"
61
+ }
62
+ ],
63
+ "execute-phase": [
64
+ {
65
+ "id": "partial-wave",
66
+ "when": "flag:--wave",
67
+ "read": "gsd-core/workflows/execute-phase/steps/partial-wave.md"
68
+ },
69
+ {
70
+ "id": "gap-closure-artifacts",
71
+ "when": "state:gap-closure-phase",
72
+ "read": "gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md"
73
+ },
74
+ {
75
+ "id": "regression-gate",
76
+ "when": "state:has-prior-phases",
77
+ "read": "gsd-core/workflows/execute-phase/steps/regression-gate.md"
78
+ }
79
+ ],
80
+ "new-milestone": [
81
+ {
82
+ "id": "project-md-milestone-write",
83
+ "when": "state:flat-mode",
84
+ "read": "gsd-core/workflows/new-milestone/steps/project-md-milestone-write.md"
85
+ },
86
+ {
87
+ "id": "reset-phase-safety",
88
+ "when": "flag:--reset-phase-numbers",
89
+ "read": "gsd-core/workflows/new-milestone/steps/reset-phase-safety.md"
90
+ }
91
+ ],
92
+ "new-project": [
93
+ {
94
+ "id": "auto-mode-detection",
95
+ "when": "flag:--auto",
96
+ "read": "gsd-core/workflows/new-project/steps/auto-mode-detection.md"
97
+ },
98
+ {
99
+ "id": "codebase-map-offer",
100
+ "when": "state:needs-codebase-map",
101
+ "read": "gsd-core/workflows/new-project/steps/codebase-map-offer.md"
102
+ },
103
+ {
104
+ "id": "auto-mode-config",
105
+ "when": "flag:--auto",
106
+ "read": "gsd-core/workflows/new-project/steps/auto-mode-config.md"
107
+ }
108
+ ],
109
+ "plan-phase": [
110
+ {
111
+ "id": "reviews-prerequisite",
112
+ "when": "flag:--reviews",
113
+ "read": "gsd-core/workflows/plan-phase/steps/reviews-prerequisite.md"
114
+ },
115
+ {
116
+ "id": "prd-express-gate",
117
+ "when": "flag:--prd",
118
+ "read": "gsd-core/workflows/plan-phase/steps/prd-express-gate.md"
119
+ },
120
+ {
121
+ "id": "adr-ingest-express-path",
122
+ "when": "flag:--ingest",
123
+ "read": "gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md"
124
+ },
125
+ {
126
+ "id": "research-only-modifiers",
127
+ "when": "flag:--research-phase",
128
+ "read": "gsd-core/workflows/plan-phase/steps/research-only-modifiers.md"
129
+ },
130
+ {
131
+ "id": "research-only-early-exit",
132
+ "when": "flag:--research-phase",
133
+ "read": "gsd-core/workflows/plan-phase/steps/research-only-early-exit.md"
134
+ },
135
+ {
136
+ "id": "chunked-planning-mode",
137
+ "when": "state:chunked-mode",
138
+ "read": "gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md"
139
+ }
140
+ ],
141
+ "progress": [
142
+ {
143
+ "id": "mvp-display",
144
+ "when": "state:phase-mvp-mode",
145
+ "read": "gsd-core/workflows/progress/steps/mvp-display.md"
146
+ },
147
+ {
148
+ "id": "forensic-audit",
149
+ "when": "flag:--forensic",
150
+ "read": "gsd-core/workflows/progress/steps/forensic-audit.md"
151
+ }
152
+ ],
153
+ "quick": [
154
+ {
155
+ "id": "discussion-phase",
156
+ "when": "flag:--discuss",
157
+ "read": "gsd-core/workflows/quick/steps/discussion-phase.md"
158
+ },
159
+ {
160
+ "id": "research-phase",
161
+ "when": "flag:--research",
162
+ "read": "gsd-core/workflows/quick/steps/research-phase.md"
163
+ },
164
+ {
165
+ "id": "plan-checker-loop",
166
+ "when": "flag:--validate",
167
+ "read": "gsd-core/workflows/quick/steps/plan-checker-loop.md"
168
+ },
169
+ {
170
+ "id": "worktree-pre-dispatch-commit",
171
+ "when": "state:worktrees-enabled",
172
+ "read": "gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md"
173
+ },
174
+ {
175
+ "id": "quick-verification",
176
+ "when": "flag:--validate",
177
+ "read": "gsd-core/workflows/quick/steps/quick-verification.md"
178
+ }
179
+ ],
180
+ "review": [
181
+ {
182
+ "id": "reviewer-instances-note-1",
183
+ "when": "state:reviewer-instances-configured",
184
+ "read": "gsd-core/workflows/review/steps/reviewer-instances-note-1.md"
185
+ },
186
+ {
187
+ "id": "reviewer-instances-note-2",
188
+ "when": "state:reviewer-instances-configured",
189
+ "read": "gsd-core/workflows/review/steps/reviewer-instances-note-2.md"
190
+ }
191
+ ],
192
+ "transition": [
193
+ {
194
+ "id": "workstream-collision-check",
195
+ "when": "state:workstream-active",
196
+ "read": "gsd-core/workflows/transition/steps/workstream-collision-check.md"
197
+ }
198
+ ],
199
+ "update": [
200
+ {
201
+ "id": "channel-banner",
202
+ "when": "state:next-channel",
203
+ "read": "gsd-core/workflows/update/steps/channel-banner.md"
204
+ }
205
+ ],
206
+ "verify-work": [
207
+ {
208
+ "id": "automated-ui-verification",
209
+ "when": "state:ui-phase-active",
210
+ "read": "gsd-core/workflows/verify-work/steps/automated-ui-verification.md"
211
+ },
212
+ {
213
+ "id": "mvp-uat-framing",
214
+ "when": "state:phase-mvp-mode",
215
+ "read": "gsd-core/workflows/verify-work/steps/mvp-uat-framing.md"
216
+ }
217
+ ]
218
+ }
219
+ }
@@ -134,7 +134,7 @@ If spikes exist for this project, read them to ground the sketches in reality. M
134
134
 
135
135
  **a.** Glob for `./.claude/skills/spike-findings-*/SKILL.md` and read any that exist, plus their `references/*.md`. These contain validated patterns and requirements.
136
136
 
137
- **b.** Read `.planning/spikes/MANIFEST.md` if it exists — check the Requirements section for non-negotiable design constraints (e.g., "must support streaming", "must render markdown"). These requirements should be visible in the mockup even though the mockup doesn't implement them for real.
137
+ **b.** Read `.planning/spikes/MANIFEST.md` if it exists — it may hold separate `### {idea-key}` sections for several unrelated ideas. Check the Requirements list of the idea key relevant to this sketch's design direction (or all of them if none clearly matches) for non-negotiable design constraints (e.g., "must support streaming", "must render markdown"). These requirements should be visible in the mockup even though the mockup doesn't implement them for real.
138
138
 
139
139
  **c.** Read `.planning/spikes/CONVENTIONS.md` if it exists — the established stack informs what's buildable and what interaction patterns are idiomatic.
140
140
 
@@ -126,7 +126,7 @@ Acceptance Criteria:[score 0.0–1.0]
126
126
  Ambiguity: [score] ([calculate])
127
127
  ```
128
128
 
129
- **If `--auto` and initial ambiguity already ≤ 0.20 with all minimums met:** Skip interview — derive SPEC.md directly from roadmap + requirements. Log: `[auto] Phase requirements are already sufficiently clear — generating SPEC.md from existing context.` Jump to Step 6.
129
+ **If `--auto` and initial ambiguity already ≤ 0.20 with all minimums met:** Skip interview — derive SPEC.md directly from roadmap + requirements. Log: `[auto] Phase requirements are already sufficiently clear — generating SPEC.md from existing context.` Jump to Step 5.5.
130
130
 
131
131
  **Otherwise:** Continue to Step 4.
132
132
 
@@ -159,15 +159,15 @@ After round [N]:
159
159
 
160
160
  If gate passes (ambiguity ≤ 0.20 AND all minimums met):
161
161
 
162
- **If `--auto`:** Jump to Step 6.
162
+ **If `--auto`:** Jump to Step 5.5.
163
163
 
164
164
  **Otherwise:** AskUserQuestion:
165
165
  - header: "Spec Gate Passed"
166
166
  - question: "Ambiguity is [score] — requirements are clear enough to write SPEC.md. Proceed?"
167
167
  - options:
168
- - "Yes — write SPEC.md" → Jump to Step 6
168
+ - "Yes — write SPEC.md" → Jump to Step 5.5
169
169
  - "One more round" → Continue interview
170
- - "Done talking — write it" → Jump to Step 6
170
+ - "Done talking — write it" → Jump to Step 5.5
171
171
 
172
172
  **If max rounds reached (6) and gate not passed:**
173
173
 
@@ -251,7 +251,8 @@ if ! node -e 'const a=require(process.argv[1]);if(!Array.isArray(a)||a.length===
251
251
  exit 1
252
252
  fi
253
253
  # Invoke the compiled engine and CAPTURE its report — it computes which categories apply per
254
- # requirement. The covered/backstop/dismissed/unresolved rows in $COVERAGE drive the
254
+ # requirement. The resolved/dismissed/unresolved rows in $COVERAGE (resolved items carry
255
+ # verification: explicit|backstop) drive the
255
256
  # resolution loop below (canonical taxonomy compute, NOT LLM re-derivation from prose).
256
257
  # The engine FAILS CLOSED (exit 2) on an invalid authored shape or bad input — so the capture
257
258
  # MUST be exit-checked. A bare `COVERAGE=$(node …)` swallows that exit code, leaves $COVERAGE
@@ -288,21 +289,22 @@ an empty `## Edge Coverage` section after explicit confirmation.
288
289
  For each Requirement gathered so far:
289
290
  1. Classify its shape and raise only applicable edge categories (relevance filter — see
290
291
  the taxonomy in the reference). Reuse any edges the Round-4 Failure Analyst already
291
- surfaced as pre-`covered`.
292
+ surfaced as pre-resolved.
292
293
  2. For each raised category, propose a CONCRETE candidate edge (not "consider
293
294
  boundaries" — e.g. "R2 merges intervals; what about `[[1,2],[2,3]]` that only touch?").
294
295
  3. Resolve each with the user (AskUserQuestion; text mode → numbered list):
295
296
  - **Specify it** → write a new pass/fail line into Acceptance Criteria AND mark the
296
- edge `covered`.
297
+ edge `resolved` with `verification: explicit`.
297
298
  - **Dismiss (reason)** → mark `dismissed` with a required non-empty reason.
298
- - **Backstop with a test** → mark `backstop`; note "held-out edge test" for plan-phase.
299
+ - **Backstop with a test** → mark `resolved` with `verification: backstop`; note
300
+ "held-out edge test" for plan-phase.
299
301
  - **Defer** → leave `unresolved`.
300
302
  - An `unclassified` row (probe `unclassified — review manually`) means the requirement's
301
303
  prose matched no shape cue (#1110) — treat it like any other candidate (**Specify**,
302
304
  **Dismiss (reason)**, or **Defer**). A manual-review nudge, not a hard block.
303
305
 
304
306
  **Soft gate (after resolving):**
305
- - All applicable edges resolved → proceed to Step 6.
307
+ - All applicable edges resolved → proceed to Step 5.6.
306
308
  - Any `unresolved` → AskUserQuestion:
307
309
  - header: "Edge Coverage"
308
310
  - question: "[N] edge(s) are unresolved: [list]. What do you want to do?"
@@ -311,13 +313,14 @@ For each Requirement gathered so far:
311
313
  - On "anyway": write SPEC.md with those rows marked `⚠ Edge unresolved — planner must
312
314
  treat as assumption`.
313
315
 
314
- **`--auto` mode:** auto-`covered` where a defensible acceptance criterion can be written;
315
- otherwise auto-`backstop` (never auto-dismiss — a wrong dismissal is the exact silent
316
- failure being eliminated). Log: `[auto] edge coverage: C covered, B backstop, U unresolved`.
316
+ **`--auto` mode:** auto-`resolved` (verification: explicit) where a defensible acceptance
317
+ criterion can be written; otherwise auto-`resolved` (verification: backstop) (never
318
+ auto-dismiss — a wrong dismissal is the exact silent failure being eliminated). Log:
319
+ `[auto] edge coverage: E explicit, B backstop, U unresolved`.
317
320
 
318
321
  **`unclassified` exception (#1110):** `--auto` leaves an `unclassified` candidate
319
322
  **`unresolved`** (the soft gate surfaces it as a flagged planner assumption) — it never
320
- auto-`backstop`s it. A missing shape is not evidence an edge exists, so minting a held-out
323
+ auto-resolves it with `verification: backstop`. A missing shape is not evidence an edge exists, so minting a held-out
321
324
  edge obligation on a requirement that may be genuinely edge-free would be a false claim and
322
325
  risks a vacuous edge test. Leaving it `unresolved` keeps the zero-cue requirement visible
323
326
  (never a silent drop) without fabricating an edge — which is exactly #1110's purpose: surface
@@ -425,7 +428,7 @@ downstream rather than blocking authoring.
425
428
 
426
429
  Use the SPEC.md template from @~/.claude/gsd-core/templates/spec.md.
427
430
 
428
- - Populate the **Edge Coverage** section from Step 5.5 (covered/dismissed/backstop/unresolved rows).
431
+ - Populate the **Edge Coverage** section from Step 5.5 (resolved/dismissed/unresolved rows; resolved items carry `verification: explicit|backstop`).
429
432
  - Populate the **Prohibitions** section from Step 5.6 (resolved/dismissed/unresolved rows with the test|judgment tier).
430
433
 
431
434
  **Requirements for every requirement entry:**
@@ -22,8 +22,12 @@ Read all files referenced by the invoking prompt's execution_context before star
22
22
  <step name="gather">
23
23
  ## Gather Spike Inventory
24
24
 
25
- 1. Read `.planning/spikes/MANIFEST.md` for the overall idea context and requirements
26
- 2. Glob `.planning/spikes/*/README.md` and parse YAML frontmatter from each
25
+ 1. Read `.planning/spikes/MANIFEST.md` for the `## Ideas` sections (each idea's paragraph and
26
+ its own scoped Requirements list) and the `## Spikes` table (its Idea column tells you which
27
+ idea key each spike row belongs to).
28
+ 2. Glob `.planning/spikes/*/README.md` and parse YAML frontmatter from each — each spike's
29
+ `idea:` field is the idea key that owns it. If a README predates #1700 and has no `idea:`
30
+ field, resolve its idea key from the matching `## Spikes` table row's Idea column instead.
27
31
  3. Check if `./.claude/skills/spike-findings-*/SKILL.md` exists for this project
28
32
  - If yes: read its `processed_spikes` list from the metadata section and filter those out
29
33
  - If no: all spikes are candidates
@@ -101,7 +105,12 @@ For each feature-area group, write a reference file at `references/[feature-area
101
105
 
102
106
  ## Requirements
103
107
 
104
- [Non-negotiable design decisions from MANIFEST.md Requirements section that apply to this feature area. These MUST be honored in the real build. E.g., "Must use streaming JSON output", "Must support reconnection".]
108
+ [Non-negotiable design decisions pulled ONLY from the Requirements list of the idea key(s) that
109
+ own the spikes in this feature-area group — match each spike's `idea:` frontmatter (or Idea
110
+ column) to its `### {idea-key}` Requirements list in MANIFEST.md. These MUST be honored in the
111
+ real build. E.g., "Must use streaming JSON output", "Must support reconnection".
112
+
113
+ Never include a requirement from an idea key that has no spike in this group.]
105
114
 
106
115
  ## How to Build It
107
116
 
@@ -136,7 +145,8 @@ description: Implementation blueprint from spike experiments. Requirements, prov
136
145
  <context>
137
146
  ## Project: [project-dir-name]
138
147
 
139
- [One paragraph from MANIFEST.md describing the overall idea]
148
+ [One paragraph per idea key represented among the wrapped spikes, taken from that idea's
149
+ `### {idea-key}` section in MANIFEST.md — not the whole MANIFEST.md if it holds unrelated ideas.]
140
150
 
141
151
  Spike sessions wrapped: [date(s)]
142
152
  </context>
@@ -144,7 +154,11 @@ Spike sessions wrapped: [date(s)]
144
154
  <requirements>
145
155
  ## Requirements
146
156
 
147
- [Copied directly from MANIFEST.md Requirements section. These are non-negotiable design decisions that emerged from the user's choices during spiking. Every feature area reference must honor these.]
157
+ [Union of the Requirements lists for every idea key represented among the spikes being wrapped
158
+ in this session — never the whole MANIFEST.md. These are non-negotiable design decisions that
159
+ emerged from the user's choices while spiking those specific idea(s). Every feature area
160
+ reference must honor these. If this wrap-up spans more than one idea key, group the list by
161
+ idea key so a future reader can tell which requirement belongs to which idea.]
148
162
 
149
163
  - [requirement 1]
150
164
  - [requirement 2]
@@ -299,6 +313,7 @@ After the summary, present next-step options:
299
313
  - [ ] Spikes grouped by feature area
300
314
  - [ ] Spike-findings skill exists at `./.claude/skills/` with SKILL.md (including requirements), references/, sources/
301
315
  - [ ] Reference files are implementation blueprints with Requirements, How to Build It, What to Avoid, Constraints
316
+ - [ ] Requirements in each reference file and in SKILL.md are scoped to the idea key(s) actually represented among the wrapped spikes — never blended with an unrelated idea's requirements
302
317
  - [ ] `.planning/spikes/CONVENTIONS.md` created or updated with recurring stack/structure/pattern choices
303
318
  - [ ] `.planning/spikes/WRAP-UP-SUMMARY.md` written for project history
304
319
  - [ ] Project CLAUDE.md has auto-load routing line
@@ -53,7 +53,8 @@ If no `.planning/spikes/` directory exists, tell the user there's nothing to ana
53
53
 
54
54
  Otherwise, load in this order:
55
55
 
56
- **a. MANIFEST.md** — the overall idea, requirements, and spike table with verdicts.
56
+ **a. MANIFEST.md** — every idea section under `## Ideas` (each idea's paragraph and its own
57
+ scoped Requirements) and the `## Spikes` table with verdicts (each row tagged by idea).
57
58
 
58
59
  **b. Findings skills** — glob `./.claude/skills/spike-findings-*/SKILL.md` and read any that exist, plus their `references/*.md`. These contain curated knowledge from prior wrap-ups.
59
60
 
@@ -74,7 +75,8 @@ If integration risks exist, present them as concrete proposed spikes with names
74
75
 
75
76
  ### Analyze for Frontier Spikes
76
77
 
77
- Think laterally about the overall idea from MANIFEST.md and what's been proven so far. Consider:
78
+ Think laterally about every idea section from MANIFEST.md and what's been proven so far for
79
+ each. Consider:
78
80
 
79
81
  - **Gaps in the vision:** Capabilities assumed but unproven.
80
82
  - **Discovered dependencies:** Findings that reveal new questions.
@@ -86,7 +88,7 @@ Present frontier spikes as concrete proposals numbered from the highest existing
86
88
 
87
89
  ### Get Alignment and Execute
88
90
 
89
- Present all integration and frontier candidates, then ask which to run. When the user picks spikes, write definitions into `.planning/spikes/MANIFEST.md` (appending to existing table) and proceed directly to building them starting at `research`.
91
+ Present all integration and frontier candidates, then ask which to run. When the user picks spikes, write definitions into `.planning/spikes/MANIFEST.md` (appending to the existing table, with each row's Idea column set to the idea key(s) it extends or validates) and proceed directly to building them starting at `research`.
90
92
  </step>
91
93
 
92
94
  <step name="setup_directory">
@@ -212,33 +214,63 @@ If 2+ credible approaches exist, plan to build quick variants within the spike a
212
214
  </step>
213
215
 
214
216
  <step name="create_manifest">
215
- Create or update `.planning/spikes/MANIFEST.md`:
217
+ Create or update `.planning/spikes/MANIFEST.md`.
218
+
219
+ **Assign an idea key.** Derive a short, stable, kebab-case slug (2-4 words) summarizing the
220
+ idea being spiked right now, e.g. `realtime-llm-streaming`. Reuse the exact same idea key for
221
+ every spike in this session and any later session that continues the same idea. Only mint a
222
+ new idea key when the current idea is not a continuation of one already indexed in
223
+ MANIFEST.md — never reuse an existing idea key for an unrelated idea, and never merge two
224
+ different ideas under one key.
225
+
226
+ If `.planning/spikes/MANIFEST.md` doesn't exist, create it:
216
227
 
217
228
  ```markdown
218
229
  # Spike Manifest
219
230
 
220
- ## Idea
221
- [One paragraph describing the overall idea being explored]
231
+ ## Ideas
232
+
233
+ ### {idea-key}
234
+ [One paragraph describing this idea]
222
235
 
223
- ## Requirements
224
- [Design decisions that emerged from the user's choices during spiking. Non-negotiable for the real build. Updated as spikes progress.]
236
+ **Requirements:**
237
+ [Design decisions that emerged from the user's choices while spiking THIS idea. Non-negotiable
238
+ for the real build of this idea. Updated as spikes progress. Never copy or merge requirements
239
+ from a different idea key into this list.]
225
240
 
226
241
  - [e.g., "Must use streaming JSON output, not single-response"]
227
242
  - [e.g., "Must support reconnection on network failure"]
228
243
 
229
244
  ## Spikes
230
245
 
231
- | # | Name | Type | Validates | Verdict | Tags |
232
- |---|------|------|-----------|---------|------|
246
+ | # | Idea | Name | Type | Validates | Verdict | Tags |
247
+ |---|------|------|------|-----------|---------|------|
233
248
  ```
234
249
 
235
- **Track requirements as they emerge.** When the user expresses a preference during spiking, add it to the Requirements section immediately.
250
+ If `.planning/spikes/MANIFEST.md` already exists:
251
+
252
+ - **Same idea key already has a `### {idea-key}` section under `## Ideas`:** append to that
253
+ section's Requirements list as new requirements emerge. Never overwrite or rewrite its
254
+ `## Idea` paragraph.
255
+ - **New idea key, not yet present:** append a new `### {idea-key}` subsection under `## Ideas`,
256
+ after any existing idea sections. Never touch, merge into, or delete another idea's section.
257
+ - **A pre-#1700 MANIFEST.md with the old flat shape** (a single top-level `## Idea` / `##
258
+ Requirements` pair, no `## Ideas` heading): treat its existing content as one implicit idea.
259
+ Derive an idea key from its `## Idea` paragraph, migrate it in place to `## Ideas` >
260
+ `### {idea-key}` — preserving the paragraph and every existing Requirements bullet and
261
+ Spikes row verbatim — then continue as above. Do this migration once; do not repeat it once
262
+ `## Ideas` exists.
263
+
264
+ Every row appended to `## Spikes` carries an **Idea** column set to the idea key it belongs to.
265
+
266
+ **Track requirements as they emerge.** When the user expresses a preference during spiking, add
267
+ it to the current idea's Requirements list immediately — never to a different idea's list.
236
268
  </step>
237
269
 
238
270
  <step name="reground">
239
271
  ## Re-Ground Before Each Spike
240
272
 
241
- Before starting each spike (not just the first), re-read `.planning/spikes/MANIFEST.md` and `.planning/spikes/CONVENTIONS.md` to prevent drift within long sessions. Check the Requirements section — make sure the spike doesn't contradict any established requirements.
273
+ Before starting each spike (not just the first), re-read `.planning/spikes/MANIFEST.md` and `.planning/spikes/CONVENTIONS.md` to prevent drift within long sessions. Check the current idea's `### {idea-key}` Requirements list — make sure the spike doesn't contradict any established requirement for this idea. Do not apply another idea's requirements.
242
274
  </step>
243
275
 
244
276
  <step name="build_spikes">
@@ -287,6 +319,7 @@ Multiple files per spike are expected for complex questions (e.g., `test-basic.j
287
319
  ```markdown
288
320
  ---
289
321
  spike: NNN
322
+ idea: {idea-key}
290
323
  name: descriptive-name
291
324
  type: standard
292
325
  validates: "Given [precondition], when [action], then [expected outcome]"
@@ -337,7 +370,8 @@ tags: [tag1, tag2]
337
370
  → Does this match what you expected? Describe what you see.
338
371
  ──────────────────────────────────────────────────────────────
339
372
 
340
- **h.** Update `.planning/spikes/MANIFEST.md` with the spike's row.
373
+ **h.** Update `.planning/spikes/MANIFEST.md` with the spike's row, setting the Idea column to
374
+ this spike's idea key.
341
375
 
342
376
  **i.** Commit (if `COMMIT_DOCS` is true):
343
377
  ```bash
@@ -450,10 +484,10 @@ gsd_run query commit "docs(spikes): update conventions" --files .planning/spikes
450
484
  - [ ] Depth over speed — edge cases tested, surprising findings followed, investigation trail documented
451
485
  - [ ] Comparison spikes built back-to-back with head-to-head verdict
452
486
  - [ ] Spikes needing human interaction have forensic log layer
453
- - [ ] Requirements tracked in MANIFEST.md as they emerge from user choices
487
+ - [ ] Requirements tracked in MANIFEST.md, scoped to the idea key that produced them, as they emerge from user choices
454
488
  - [ ] CONVENTIONS.md created or updated with patterns that emerged
455
- - [ ] Each spike README has complete frontmatter, Investigation Trail, and Results
456
- - [ ] MANIFEST.md is current (with Type column and Requirements section)
489
+ - [ ] Each spike README has complete frontmatter (including its idea key), Investigation Trail, and Results
490
+ - [ ] MANIFEST.md is current (with Idea and Type columns, and each idea's own scoped Requirements section)
457
491
  - [ ] Commits use `docs(spike-NNN): [VERDICT]` format
458
492
  - [ ] Consolidated report presented with next-step routing
459
493
  </success_criteria>
@@ -17,7 +17,7 @@ Sync managed `gsd-*` skill directories from one canonical runtime's skills root
17
17
 
18
18
  If neither `--dry-run` nor `--apply` is specified, dry-run is the default.
19
19
 
20
- **Supported runtime names:** `claude`, `codex`, `grok`, `copilot`, `cursor`, `windsurf`, `opencode`, `gemini`, `kilo`, `augment`, `trae`, `qwen`, `codebuddy`, `cline`, `antigravity` (grok uses the `~/.agents` layout)
20
+ **Supported runtime names:** `antigravity`, `augment`, `claude`, `cline`, `codebuddy`, `codex`, `copilot`, `cursor`, `grok`, `hermes`, `kilo`, `kimi`, `kimi-code`, `opencode`, `pi`, `qwen`, `trae`, `windsurf`, `zcode` — the full capability registry runtime set (`gsd-core/bin/lib/capability-registry.cjs`'s `runtimes`) plus `grok` (a live, dedicated `~/.agents`-layout resolution branch in `getGlobalConfigDir` predating the capability registry — overridable via `GROK_AGENTS_HOME`), excluding `vscode`: it is `installSurface: 'none'` (#2103) and `getGlobalSkillsBase('vscode')` returns `null`, so a skills-root sync to/from it always aborts at Step 2's resolution guard — there is nowhere on disk to sync to.
21
21
 
22
22
  ---
23
23
 
@@ -35,7 +35,7 @@ fi
35
35
 
36
36
  # Parse --to
37
37
  if [[ "$@" == *"--to all"* ]]; then
38
- TO_RUNTIMES=(claude codex grok copilot cursor windsurf opencode gemini kilo augment trae qwen codebuddy cline antigravity)
38
+ TO_RUNTIMES=(antigravity augment claude cline codebuddy codex copilot cursor grok hermes kilo kimi kimi-code opencode pi qwen trae windsurf zcode)
39
39
  elif [[ "$@" == *"--to"* ]]; then
40
40
  TO_RUNTIMES=( $(echo "$@" | grep -oP '(?<=--to )\S+') )
41
41
  fi
@@ -55,29 +55,43 @@ fi
55
55
 
56
56
  ## Step 2: Resolve Skills Roots
57
57
 
58
- Use `install.js --skills-root` to resolve paths — this reuses the single authoritative path table rather than duplicating it:
58
+ Resolve paths via `gsd_run query skills-root` — this reuses the single authoritative path table via the shipped `gsd-tools` binary (#3024: the installer entry point is not shipped in installed trees, but `gsd-tools` is):
59
59
 
60
60
  ```bash
61
- INSTALL_JS="$(dirname "$0")/../gsd-core/bin/install.js"
62
- # If running from a global install, resolve relative to the GSD package
63
- INSTALL_JS_GLOBAL="$HOME/.claude/gsd-core/bin/install.js"
64
- [[ ! -f "$INSTALL_JS" ]] && INSTALL_JS="$INSTALL_JS_GLOBAL"
65
-
66
- SRC_SKILLS_ROOT=$(node "$INSTALL_JS" --skills-root "$FROM_RUNTIME")
61
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
62
+ SRC_SKILLS_ROOT=$(gsd_run query skills-root "$FROM_RUNTIME" --raw)
63
+ if [ $? -ne 0 ] || [ -z "$SRC_SKILLS_ROOT" ]; then
64
+ echo "error: failed to resolve skills root for runtime '$FROM_RUNTIME' (gsd_run query skills-root $FROM_RUNTIME --raw)" >&2
65
+ exit 1
66
+ fi
67
67
 
68
68
  for DEST_RUNTIME in "${TO_RUNTIMES[@]}"; do
69
- DEST_SKILLS_ROOTS["$DEST_RUNTIME"]=$(node "$INSTALL_JS" --skills-root "$DEST_RUNTIME")
69
+ RESOLVED_DEST_ROOT=$(gsd_run query skills-root "$DEST_RUNTIME" --raw)
70
+ if [ $? -ne 0 ] || [ -z "$RESOLVED_DEST_ROOT" ]; then
71
+ echo "error: failed to resolve skills root for runtime '$DEST_RUNTIME' (gsd_run query skills-root $DEST_RUNTIME --raw)" >&2
72
+ exit 1
73
+ fi
70
74
  done
71
75
  ```
72
76
 
77
+ This loop validates every destination in `TO_RUNTIMES` up front — a bad runtime id anywhere in a multi-destination `--to` aborts here, before Step 3 or Step 5 touch anything. The resolved value itself is not retained: each of Steps 3 and 5 re-resolves `DEST_ROOT` for the specific `$DEST_RUNTIME` it is currently processing (see those steps), so `$DEST_ROOT` is always unambiguously scoped to one destination and never threaded through a shared array.
78
+
73
79
  **Guard:** If the source skills root does not exist, print:
74
80
  ```
75
81
  error: source skills root not found: <path>
76
82
  Is GSD installed globally for the '<runtime>' runtime?
77
- Run: node ~/.claude/gsd-core/bin/install.js --global --<runtime>
83
+ Run: npx -y @opengsd/gsd-core@latest --global --<runtime>
78
84
  ```
79
85
  Then exit.
80
86
 
87
+ **Guard:** If resolving the skills root for the source OR any destination runtime fails (`gsd_run query skills-root <runtime> --raw` exits non-zero or prints nothing — see Step 2's bash), print:
88
+ ```
89
+ error: failed to resolve skills root for runtime '<runtime>'
90
+ command: gsd_run query skills-root <runtime> --raw
91
+ Is '<runtime>' a registered runtime id? See supported runtime names above.
92
+ ```
93
+ Then exit. Never proceed to Step 3 or Step 5 with an empty or unresolved root — an empty `$DEST_ROOT` turns `rm -rf "$DEST_ROOT/$SKILL"` into `rm -rf "/$SKILL"`.
94
+
81
95
  **Guard:** If `--to` contains the same runtime as `--from`, skip that destination silently.
82
96
 
83
97
  ---
@@ -87,6 +101,16 @@ Then exit.
87
101
  For each destination runtime:
88
102
 
89
103
  ```bash
104
+ # Bind the destination root for this iteration's destination runtime. Already
105
+ # validated to resolve successfully in Step 2's eager-validation loop;
106
+ # re-resolving here (rather than reading back a shared array) keeps this
107
+ # value unambiguously scoped to the destination currently being processed.
108
+ DEST_ROOT=$(gsd_run query skills-root "$DEST_RUNTIME" --raw)
109
+ if [ $? -ne 0 ] || [ -z "$DEST_ROOT" ]; then
110
+ echo "error: failed to resolve skills root for runtime '$DEST_RUNTIME' (gsd_run query skills-root $DEST_RUNTIME --raw)" >&2
111
+ exit 1
112
+ fi
113
+
90
114
  # List gsd-* subdirectories in source
91
115
  SRC_SKILLS=$(ls -1 "$SRC_SKILLS_ROOT" 2>/dev/null | grep '^gsd-')
92
116
 
@@ -142,8 +166,22 @@ If `--dry-run` (or no flag): skip this step entirely and exit after printing the
142
166
  For each destination with changes:
143
167
 
144
168
  ```bash
169
+ # Bind DEST_ROOT for this iteration's destination (see Step 3's identical
170
+ # re-resolution note — Step 2 already validated this resolves successfully).
171
+ DEST_ROOT=$(gsd_run query skills-root "$DEST_RUNTIME" --raw)
172
+
173
+ [[ "$SRC_SKILLS_ROOT" == /* ]] || { echo "error: SRC_SKILLS_ROOT is empty or not absolute: '$SRC_SKILLS_ROOT'" >&2; exit 1; }
174
+ [[ "$DEST_ROOT" == /* ]] || { echo "error: DEST_ROOT is empty or not absolute: '$DEST_ROOT'" >&2; exit 1; }
175
+
145
176
  mkdir -p "$DEST_ROOT"
146
177
 
178
+ # #3025: verbatim cp -r copies the SOURCE runtime's converted skill form, which
179
+ # corrupts skills for destinations that need a different conversion (e.g. Claude
180
+ # SKILL.md → Codex TOML agent). Until the installer exposes a per-skill conversion
181
+ # CLI, sync is limited to runtime pairs that share the same skill format.
182
+ # Run `gsd install --<dest-runtime> --local` to get correctly converted skills
183
+ # for a destination that uses a different format.
184
+
147
185
  for SKILL in $CREATE_LIST $UPDATE_LIST; do
148
186
  rm -rf "$DEST_ROOT/$SKILL"
149
187
  cp -r "$SRC_SKILLS_ROOT/$SKILL" "$DEST_ROOT/$SKILL"