@opengsd/gsd-path 1.4.0 → 1.6.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 (476) hide show
  1. package/CHANGELOG.md +460 -341
  2. package/DOCS.md +16 -5
  3. package/FULL.md +67 -6
  4. package/HOOKS.md +158 -10
  5. package/MIGRATE.md +12 -0
  6. package/QUICK.md +4 -2
  7. package/README.md +136 -116
  8. package/RUNTIME.md +24 -6
  9. package/UPDATE.md +39 -3
  10. package/WORKFLOW.md +80 -4
  11. package/package.json +5 -2
  12. package/platforms/shared-agents/dispatch.md +13 -0
  13. package/scripts/_common.py +256 -2
  14. package/scripts/archive_milestone.py +14 -13
  15. package/scripts/build_recovery.py +155 -58
  16. package/scripts/build_state.py +274 -8
  17. package/scripts/check_docs_audit.py +77 -4
  18. package/scripts/check_handoffs.py +635 -57
  19. package/scripts/check_task_briefs.py +293 -32
  20. package/scripts/detect_project.py +260 -20
  21. package/scripts/discussion_records.py +9 -1
  22. package/scripts/discussion_validate.py +93 -35
  23. package/scripts/dispatch_driver.py +549 -53
  24. package/scripts/git_guard.py +27 -8
  25. package/scripts/guard_hook.py +2630 -210
  26. package/scripts/install.mjs +99 -11
  27. package/scripts/install.py +231 -46
  28. package/scripts/integration.py +244 -65
  29. package/scripts/isolation.py +539 -70
  30. package/scripts/loop_run.py +16 -4
  31. package/scripts/members.py +77 -32
  32. package/scripts/migrate_core.py +2 -0
  33. package/scripts/model_policy.py +5 -1
  34. package/scripts/path_config.py +3 -3
  35. package/scripts/pipeline_diagnose.py +17 -2
  36. package/scripts/pipeline_git.py +131 -42
  37. package/scripts/pipeline_state.py +139 -39
  38. package/scripts/pipeline_undo.py +118 -16
  39. package/scripts/promote_lookahead.py +3 -3
  40. package/scripts/review_findings.py +180 -44
  41. package/scripts/roadmap.py +9 -1
  42. package/scripts/runtime_store.py +21 -2
  43. package/scripts/skill-resources.json +9 -2
  44. package/scripts/state_checkpoint.py +39 -36
  45. package/scripts/state_promote.py +15 -4
  46. package/scripts/status_runtime.py +22 -4
  47. package/scripts/task_context.py +14 -3
  48. package/scripts/wizard.mjs +1 -0
  49. package/scripts/workflow_run.py +14 -4
  50. package/scripts/worktree_paths.py +54 -2
  51. package/skills/gsd-path/DEFINE.md +34 -5
  52. package/skills/gsd-path/PLAN.md +14 -3
  53. package/skills/gsd-path/RESEARCH.md +11 -0
  54. package/skills/gsd-path/ROADMAP.md +16 -6
  55. package/skills/gsd-path/SHIP.md +32 -5
  56. package/skills/gsd-path/SKILL.md +52 -24
  57. package/skills/gsd-path/references/build-native.md +112 -10
  58. package/skills/gsd-path/references/build-recovery.md +13 -0
  59. package/skills/gsd-path/references/coder.md +7 -3
  60. package/skills/gsd-path/references/dispatch.md +13 -0
  61. package/skills/gsd-path/references/docs-auditor.md +5 -0
  62. package/skills/gsd-path/references/operating-rules.md +11 -3
  63. package/skills/gsd-path/references/planner.md +26 -4
  64. package/skills/gsd-path/references/reviewer-final.md +20 -2
  65. package/skills/gsd-path/references/reviewer-wave.md +56 -12
  66. package/skills/gsd-path/references/reviewer.md +3 -1
  67. package/skills/gsd-path/references/runtime-selection.md +9 -0
  68. package/skills/gsd-path/references/spec-probes.md +150 -0
  69. package/skills/gsd-path/scripts/_common.py +256 -2
  70. package/skills/gsd-path/scripts/archive_milestone.py +14 -13
  71. package/skills/gsd-path/scripts/build_recovery.py +155 -58
  72. package/skills/gsd-path/scripts/build_state.py +274 -8
  73. package/skills/gsd-path/scripts/check_docs_audit.py +77 -4
  74. package/skills/gsd-path/scripts/check_handoffs.py +635 -57
  75. package/skills/gsd-path/scripts/check_task_briefs.py +293 -32
  76. package/skills/gsd-path/scripts/detect_project.py +260 -20
  77. package/skills/gsd-path/scripts/discussion_records.py +9 -1
  78. package/skills/gsd-path/scripts/discussion_validate.py +93 -35
  79. package/skills/gsd-path/scripts/dispatch_driver.py +549 -53
  80. package/skills/gsd-path/scripts/git_guard.py +27 -8
  81. package/skills/gsd-path/scripts/integration.py +244 -65
  82. package/skills/gsd-path/scripts/isolation.py +539 -70
  83. package/skills/gsd-path/scripts/loop_run.py +16 -4
  84. package/skills/gsd-path/scripts/members.py +77 -32
  85. package/skills/gsd-path/scripts/model_policy.py +5 -1
  86. package/skills/gsd-path/scripts/path_config.py +3 -3
  87. package/skills/gsd-path/scripts/pipeline_git.py +131 -42
  88. package/skills/gsd-path/scripts/pipeline_state.py +139 -39
  89. package/skills/gsd-path/scripts/promote_lookahead.py +3 -3
  90. package/skills/gsd-path/scripts/review_findings.py +180 -44
  91. package/skills/gsd-path/scripts/roadmap.py +9 -1
  92. package/skills/gsd-path/scripts/state_checkpoint.py +39 -36
  93. package/skills/gsd-path/scripts/state_promote.py +15 -4
  94. package/skills/gsd-path/scripts/status_runtime.py +22 -4
  95. package/skills/gsd-path/scripts/task_context.py +14 -3
  96. package/skills/gsd-path/scripts/workflow_run.py +14 -4
  97. package/skills/gsd-path/scripts/worktree_paths.py +54 -2
  98. package/skills/gsd-path/templates/docs-audit.md +5 -1
  99. package/skills/gsd-path/templates/final-review.md +11 -2
  100. package/skills/gsd-path/templates/intent.md +30 -0
  101. package/skills/gsd-path/templates/patch-findings.md +3 -3
  102. package/skills/gsd-path/templates/plan.md +17 -2
  103. package/skills/gsd-path/templates/research-handoff.md +14 -3
  104. package/skills/gsd-path/templates/state.md +2 -1
  105. package/skills/gsd-path/templates/task.md +1 -0
  106. package/skills/gsd-path/templates/wave-review.md +28 -9
  107. package/skills/gsd-path-build/references/build-native.md +112 -10
  108. package/skills/gsd-path-build/references/build-recovery.md +13 -0
  109. package/skills/gsd-path-build/references/coder.md +7 -3
  110. package/skills/gsd-path-build/references/dispatch.md +13 -0
  111. package/skills/gsd-path-build/references/operating-rules.md +11 -3
  112. package/skills/gsd-path-build/references/reviewer-final.md +20 -2
  113. package/skills/gsd-path-build/references/reviewer-wave.md +56 -12
  114. package/skills/gsd-path-build/references/reviewer.md +3 -1
  115. package/skills/gsd-path-build/references/runtime-selection.md +9 -0
  116. package/skills/gsd-path-build/references/spec-probes.md +150 -0
  117. package/skills/gsd-path-build/scripts/_common.py +256 -2
  118. package/skills/gsd-path-build/scripts/archive_milestone.py +14 -13
  119. package/skills/gsd-path-build/scripts/build_recovery.py +155 -58
  120. package/skills/gsd-path-build/scripts/build_state.py +274 -8
  121. package/skills/gsd-path-build/scripts/check_handoffs.py +635 -57
  122. package/skills/gsd-path-build/scripts/check_task_briefs.py +293 -32
  123. package/skills/gsd-path-build/scripts/detect_project.py +260 -20
  124. package/skills/gsd-path-build/scripts/discussion_records.py +9 -1
  125. package/skills/gsd-path-build/scripts/discussion_validate.py +93 -35
  126. package/skills/gsd-path-build/scripts/dispatch_driver.py +549 -53
  127. package/skills/gsd-path-build/scripts/integration.py +244 -65
  128. package/skills/gsd-path-build/scripts/isolation.py +539 -70
  129. package/skills/gsd-path-build/scripts/loop_run.py +16 -4
  130. package/skills/gsd-path-build/scripts/members.py +77 -32
  131. package/skills/gsd-path-build/scripts/model_policy.py +5 -1
  132. package/skills/gsd-path-build/scripts/path_config.py +3 -3
  133. package/skills/gsd-path-build/scripts/pipeline_git.py +131 -42
  134. package/skills/gsd-path-build/scripts/pipeline_state.py +139 -39
  135. package/skills/gsd-path-build/scripts/promote_lookahead.py +3 -3
  136. package/skills/gsd-path-build/scripts/review_findings.py +180 -44
  137. package/skills/gsd-path-build/scripts/roadmap.py +9 -1
  138. package/skills/gsd-path-build/scripts/state_checkpoint.py +39 -36
  139. package/skills/gsd-path-build/scripts/state_promote.py +15 -4
  140. package/skills/gsd-path-build/scripts/task_context.py +14 -3
  141. package/skills/gsd-path-build/scripts/workflow_run.py +14 -4
  142. package/skills/gsd-path-build/scripts/worktree_paths.py +54 -2
  143. package/skills/gsd-path-build/templates/task.md +1 -0
  144. package/skills/gsd-path-build/templates/wave-review.md +28 -9
  145. package/skills/gsd-path-decide/references/dispatch.md +13 -0
  146. package/skills/gsd-path-decide/references/operating-rules.md +11 -3
  147. package/skills/gsd-path-decide/references/runtime-selection.md +9 -0
  148. package/skills/gsd-path-decide/scripts/_common.py +256 -2
  149. package/skills/gsd-path-decide/scripts/archive_milestone.py +14 -13
  150. package/skills/gsd-path-decide/scripts/build_recovery.py +155 -58
  151. package/skills/gsd-path-decide/scripts/check_handoffs.py +635 -57
  152. package/skills/gsd-path-decide/scripts/check_task_briefs.py +293 -32
  153. package/skills/gsd-path-decide/scripts/detect_project.py +260 -20
  154. package/skills/gsd-path-decide/scripts/discussion_records.py +9 -1
  155. package/skills/gsd-path-decide/scripts/discussion_validate.py +93 -35
  156. package/skills/gsd-path-decide/scripts/integration.py +244 -65
  157. package/skills/gsd-path-decide/scripts/isolation.py +539 -70
  158. package/skills/gsd-path-decide/scripts/loop_run.py +16 -4
  159. package/skills/gsd-path-decide/scripts/members.py +77 -32
  160. package/skills/gsd-path-decide/scripts/model_policy.py +5 -1
  161. package/skills/gsd-path-decide/scripts/path_config.py +3 -3
  162. package/skills/gsd-path-decide/scripts/pipeline_git.py +131 -42
  163. package/skills/gsd-path-decide/scripts/pipeline_state.py +139 -39
  164. package/skills/gsd-path-decide/scripts/promote_lookahead.py +3 -3
  165. package/skills/gsd-path-decide/scripts/roadmap.py +9 -1
  166. package/skills/gsd-path-decide/scripts/state_checkpoint.py +39 -36
  167. package/skills/gsd-path-decide/scripts/state_promote.py +15 -4
  168. package/skills/gsd-path-decide/scripts/worktree_paths.py +54 -2
  169. package/skills/gsd-path-define/SKILL.md +34 -5
  170. package/skills/gsd-path-define/references/build-recovery.md +13 -0
  171. package/skills/gsd-path-define/references/operating-rules.md +11 -3
  172. package/skills/gsd-path-define/references/runtime-selection.md +9 -0
  173. package/skills/gsd-path-define/references/spec-probes.md +150 -0
  174. package/skills/gsd-path-define/scripts/_common.py +256 -2
  175. package/skills/gsd-path-define/scripts/archive_milestone.py +14 -13
  176. package/skills/gsd-path-define/scripts/build_recovery.py +155 -58
  177. package/skills/gsd-path-define/scripts/check_handoffs.py +635 -57
  178. package/skills/gsd-path-define/scripts/check_task_briefs.py +293 -32
  179. package/skills/gsd-path-define/scripts/detect_project.py +260 -20
  180. package/skills/gsd-path-define/scripts/discussion_records.py +9 -1
  181. package/skills/gsd-path-define/scripts/discussion_validate.py +93 -35
  182. package/skills/gsd-path-define/scripts/integration.py +244 -65
  183. package/skills/gsd-path-define/scripts/isolation.py +539 -70
  184. package/skills/gsd-path-define/scripts/loop_run.py +16 -4
  185. package/skills/gsd-path-define/scripts/members.py +77 -32
  186. package/skills/gsd-path-define/scripts/model_policy.py +5 -1
  187. package/skills/gsd-path-define/scripts/path_config.py +3 -3
  188. package/skills/gsd-path-define/scripts/pipeline_git.py +131 -42
  189. package/skills/gsd-path-define/scripts/pipeline_state.py +139 -39
  190. package/skills/gsd-path-define/scripts/promote_lookahead.py +3 -3
  191. package/skills/gsd-path-define/scripts/roadmap.py +9 -1
  192. package/skills/gsd-path-define/scripts/state_checkpoint.py +39 -36
  193. package/skills/gsd-path-define/scripts/state_promote.py +15 -4
  194. package/skills/gsd-path-define/scripts/worktree_paths.py +54 -2
  195. package/skills/gsd-path-define/templates/intent.md +30 -0
  196. package/skills/gsd-path-define/templates/state.md +2 -1
  197. package/skills/gsd-path-discuss/references/operating-rules.md +11 -3
  198. package/skills/gsd-path-discuss/references/runtime-selection.md +9 -0
  199. package/skills/gsd-path-discuss/scripts/_common.py +256 -2
  200. package/skills/gsd-path-discuss/scripts/discussion_records.py +9 -1
  201. package/skills/gsd-path-discuss/scripts/loop_run.py +16 -4
  202. package/skills/gsd-path-discuss/scripts/model_policy.py +5 -1
  203. package/skills/gsd-path-discuss/scripts/path_config.py +3 -3
  204. package/skills/gsd-path-discuss/scripts/worktree_paths.py +54 -2
  205. package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
  206. package/skills/gsd-path-docs-audit/references/docs-auditor.md +5 -0
  207. package/skills/gsd-path-docs-audit/references/operating-rules.md +11 -3
  208. package/skills/gsd-path-docs-audit/references/runtime-selection.md +9 -0
  209. package/skills/gsd-path-docs-audit/scripts/_common.py +256 -2
  210. package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +14 -13
  211. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +155 -58
  212. package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +77 -4
  213. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +635 -57
  214. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +293 -32
  215. package/skills/gsd-path-docs-audit/scripts/detect_project.py +260 -20
  216. package/skills/gsd-path-docs-audit/scripts/discussion_records.py +9 -1
  217. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +93 -35
  218. package/skills/gsd-path-docs-audit/scripts/integration.py +244 -65
  219. package/skills/gsd-path-docs-audit/scripts/isolation.py +539 -70
  220. package/skills/gsd-path-docs-audit/scripts/loop_run.py +16 -4
  221. package/skills/gsd-path-docs-audit/scripts/members.py +77 -32
  222. package/skills/gsd-path-docs-audit/scripts/model_policy.py +5 -1
  223. package/skills/gsd-path-docs-audit/scripts/path_config.py +3 -3
  224. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +131 -42
  225. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +139 -39
  226. package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +3 -3
  227. package/skills/gsd-path-docs-audit/scripts/roadmap.py +9 -1
  228. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +39 -36
  229. package/skills/gsd-path-docs-audit/scripts/state_promote.py +15 -4
  230. package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +54 -2
  231. package/skills/gsd-path-docs-audit/templates/docs-audit.md +5 -1
  232. package/skills/gsd-path-forensics/references/operating-rules.md +11 -3
  233. package/skills/gsd-path-forensics/references/runtime-selection.md +9 -0
  234. package/skills/gsd-path-forensics/scripts/_common.py +256 -2
  235. package/skills/gsd-path-forensics/scripts/discussion_records.py +9 -1
  236. package/skills/gsd-path-forensics/scripts/loop_run.py +16 -4
  237. package/skills/gsd-path-forensics/scripts/model_policy.py +5 -1
  238. package/skills/gsd-path-forensics/scripts/path_config.py +3 -3
  239. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +17 -2
  240. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +118 -16
  241. package/skills/gsd-path-forensics/scripts/worktree_paths.py +54 -2
  242. package/skills/gsd-path-inspect/references/dispatch.md +13 -0
  243. package/skills/gsd-path-inspect/references/docs-auditor.md +5 -0
  244. package/skills/gsd-path-inspect/references/operating-rules.md +11 -3
  245. package/skills/gsd-path-inspect/references/runtime-selection.md +9 -0
  246. package/skills/gsd-path-inspect/scripts/_common.py +256 -2
  247. package/skills/gsd-path-inspect/scripts/archive_milestone.py +14 -13
  248. package/skills/gsd-path-inspect/scripts/build_recovery.py +155 -58
  249. package/skills/gsd-path-inspect/scripts/check_docs_audit.py +77 -4
  250. package/skills/gsd-path-inspect/scripts/check_handoffs.py +635 -57
  251. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +293 -32
  252. package/skills/gsd-path-inspect/scripts/detect_project.py +260 -20
  253. package/skills/gsd-path-inspect/scripts/discussion_records.py +9 -1
  254. package/skills/gsd-path-inspect/scripts/discussion_validate.py +93 -35
  255. package/skills/gsd-path-inspect/scripts/integration.py +244 -65
  256. package/skills/gsd-path-inspect/scripts/isolation.py +539 -70
  257. package/skills/gsd-path-inspect/scripts/loop_run.py +16 -4
  258. package/skills/gsd-path-inspect/scripts/members.py +77 -32
  259. package/skills/gsd-path-inspect/scripts/model_policy.py +5 -1
  260. package/skills/gsd-path-inspect/scripts/path_config.py +3 -3
  261. package/skills/gsd-path-inspect/scripts/pipeline_git.py +131 -42
  262. package/skills/gsd-path-inspect/scripts/pipeline_state.py +139 -39
  263. package/skills/gsd-path-inspect/scripts/promote_lookahead.py +3 -3
  264. package/skills/gsd-path-inspect/scripts/roadmap.py +9 -1
  265. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +39 -36
  266. package/skills/gsd-path-inspect/scripts/state_promote.py +15 -4
  267. package/skills/gsd-path-inspect/scripts/workflow_run.py +14 -4
  268. package/skills/gsd-path-inspect/scripts/worktree_paths.py +54 -2
  269. package/skills/gsd-path-inspect/templates/docs-audit.md +5 -1
  270. package/skills/gsd-path-inspect/templates/state.md +2 -1
  271. package/skills/gsd-path-loop/references/operating-rules.md +11 -3
  272. package/skills/gsd-path-loop/references/runtime-selection.md +9 -0
  273. package/skills/gsd-path-loop/scripts/_common.py +256 -2
  274. package/skills/gsd-path-loop/scripts/discussion_records.py +9 -1
  275. package/skills/gsd-path-loop/scripts/loop_run.py +16 -4
  276. package/skills/gsd-path-loop/scripts/model_policy.py +5 -1
  277. package/skills/gsd-path-loop/scripts/path_config.py +3 -3
  278. package/skills/gsd-path-loop/scripts/worktree_paths.py +54 -2
  279. package/skills/gsd-path-migrate/SKILL.md +8 -0
  280. package/skills/gsd-path-migrate/references/operating-rules.md +11 -3
  281. package/skills/gsd-path-migrate/references/runtime-selection.md +9 -0
  282. package/skills/gsd-path-migrate/scripts/_common.py +256 -2
  283. package/skills/gsd-path-migrate/scripts/discussion_records.py +9 -1
  284. package/skills/gsd-path-migrate/scripts/loop_run.py +16 -4
  285. package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -0
  286. package/skills/gsd-path-migrate/scripts/model_policy.py +5 -1
  287. package/skills/gsd-path-migrate/scripts/path_config.py +3 -3
  288. package/skills/gsd-path-plan/SKILL.md +14 -3
  289. package/skills/gsd-path-plan/references/build-recovery.md +13 -0
  290. package/skills/gsd-path-plan/references/dispatch.md +13 -0
  291. package/skills/gsd-path-plan/references/operating-rules.md +11 -3
  292. package/skills/gsd-path-plan/references/planner.md +26 -4
  293. package/skills/gsd-path-plan/references/runtime-selection.md +9 -0
  294. package/skills/gsd-path-plan/references/spec-probes.md +150 -0
  295. package/skills/gsd-path-plan/scripts/_common.py +256 -2
  296. package/skills/gsd-path-plan/scripts/archive_milestone.py +14 -13
  297. package/skills/gsd-path-plan/scripts/build_recovery.py +155 -58
  298. package/skills/gsd-path-plan/scripts/check_handoffs.py +635 -57
  299. package/skills/gsd-path-plan/scripts/check_task_briefs.py +293 -32
  300. package/skills/gsd-path-plan/scripts/detect_project.py +260 -20
  301. package/skills/gsd-path-plan/scripts/discussion_records.py +9 -1
  302. package/skills/gsd-path-plan/scripts/discussion_validate.py +93 -35
  303. package/skills/gsd-path-plan/scripts/integration.py +244 -65
  304. package/skills/gsd-path-plan/scripts/isolation.py +539 -70
  305. package/skills/gsd-path-plan/scripts/loop_run.py +16 -4
  306. package/skills/gsd-path-plan/scripts/members.py +77 -32
  307. package/skills/gsd-path-plan/scripts/model_policy.py +5 -1
  308. package/skills/gsd-path-plan/scripts/path_config.py +3 -3
  309. package/skills/gsd-path-plan/scripts/pipeline_git.py +131 -42
  310. package/skills/gsd-path-plan/scripts/pipeline_state.py +139 -39
  311. package/skills/gsd-path-plan/scripts/promote_lookahead.py +3 -3
  312. package/skills/gsd-path-plan/scripts/roadmap.py +9 -1
  313. package/skills/gsd-path-plan/scripts/state_checkpoint.py +39 -36
  314. package/skills/gsd-path-plan/scripts/state_promote.py +15 -4
  315. package/skills/gsd-path-plan/scripts/workflow_run.py +14 -4
  316. package/skills/gsd-path-plan/scripts/worktree_paths.py +54 -2
  317. package/skills/gsd-path-plan/templates/patch-findings.md +3 -3
  318. package/skills/gsd-path-plan/templates/plan.md +17 -2
  319. package/skills/gsd-path-plan/templates/task.md +1 -0
  320. package/skills/gsd-path-research/SKILL.md +11 -0
  321. package/skills/gsd-path-research/references/dispatch.md +13 -0
  322. package/skills/gsd-path-research/references/operating-rules.md +11 -3
  323. package/skills/gsd-path-research/references/runtime-selection.md +9 -0
  324. package/skills/gsd-path-research/scripts/_common.py +256 -2
  325. package/skills/gsd-path-research/scripts/archive_milestone.py +14 -13
  326. package/skills/gsd-path-research/scripts/build_recovery.py +155 -58
  327. package/skills/gsd-path-research/scripts/check_handoffs.py +635 -57
  328. package/skills/gsd-path-research/scripts/check_task_briefs.py +293 -32
  329. package/skills/gsd-path-research/scripts/detect_project.py +260 -20
  330. package/skills/gsd-path-research/scripts/discussion_records.py +9 -1
  331. package/skills/gsd-path-research/scripts/discussion_validate.py +93 -35
  332. package/skills/gsd-path-research/scripts/integration.py +244 -65
  333. package/skills/gsd-path-research/scripts/isolation.py +539 -70
  334. package/skills/gsd-path-research/scripts/loop_run.py +16 -4
  335. package/skills/gsd-path-research/scripts/members.py +77 -32
  336. package/skills/gsd-path-research/scripts/model_policy.py +5 -1
  337. package/skills/gsd-path-research/scripts/path_config.py +3 -3
  338. package/skills/gsd-path-research/scripts/pipeline_git.py +131 -42
  339. package/skills/gsd-path-research/scripts/pipeline_state.py +139 -39
  340. package/skills/gsd-path-research/scripts/promote_lookahead.py +3 -3
  341. package/skills/gsd-path-research/scripts/roadmap.py +9 -1
  342. package/skills/gsd-path-research/scripts/state_checkpoint.py +39 -36
  343. package/skills/gsd-path-research/scripts/state_promote.py +15 -4
  344. package/skills/gsd-path-research/scripts/worktree_paths.py +54 -2
  345. package/skills/gsd-path-research/templates/research-handoff.md +14 -3
  346. package/skills/gsd-path-roadmap/SKILL.md +16 -6
  347. package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
  348. package/skills/gsd-path-roadmap/references/operating-rules.md +11 -3
  349. package/skills/gsd-path-roadmap/references/runtime-selection.md +9 -0
  350. package/skills/gsd-path-roadmap/scripts/_common.py +256 -2
  351. package/skills/gsd-path-roadmap/scripts/archive_milestone.py +14 -13
  352. package/skills/gsd-path-roadmap/scripts/build_recovery.py +155 -58
  353. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +635 -57
  354. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +293 -32
  355. package/skills/gsd-path-roadmap/scripts/detect_project.py +260 -20
  356. package/skills/gsd-path-roadmap/scripts/discussion_records.py +9 -1
  357. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +93 -35
  358. package/skills/gsd-path-roadmap/scripts/integration.py +244 -65
  359. package/skills/gsd-path-roadmap/scripts/isolation.py +539 -70
  360. package/skills/gsd-path-roadmap/scripts/loop_run.py +16 -4
  361. package/skills/gsd-path-roadmap/scripts/members.py +77 -32
  362. package/skills/gsd-path-roadmap/scripts/model_policy.py +5 -1
  363. package/skills/gsd-path-roadmap/scripts/path_config.py +3 -3
  364. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +131 -42
  365. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +139 -39
  366. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +3 -3
  367. package/skills/gsd-path-roadmap/scripts/roadmap.py +9 -1
  368. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +39 -36
  369. package/skills/gsd-path-roadmap/scripts/state_promote.py +15 -4
  370. package/skills/gsd-path-roadmap/scripts/worktree_paths.py +54 -2
  371. package/skills/gsd-path-ship/SKILL.md +32 -5
  372. package/skills/gsd-path-ship/references/dispatch.md +13 -0
  373. package/skills/gsd-path-ship/references/operating-rules.md +11 -3
  374. package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
  375. package/skills/gsd-path-ship/references/reviewer-wave.md +56 -12
  376. package/skills/gsd-path-ship/references/reviewer.md +3 -1
  377. package/skills/gsd-path-ship/references/runtime-selection.md +9 -0
  378. package/skills/gsd-path-ship/references/spec-probes.md +150 -0
  379. package/skills/gsd-path-ship/scripts/_common.py +256 -2
  380. package/skills/gsd-path-ship/scripts/archive_milestone.py +14 -13
  381. package/skills/gsd-path-ship/scripts/build_recovery.py +155 -58
  382. package/skills/gsd-path-ship/scripts/build_state.py +274 -8
  383. package/skills/gsd-path-ship/scripts/check_handoffs.py +635 -57
  384. package/skills/gsd-path-ship/scripts/check_task_briefs.py +293 -32
  385. package/skills/gsd-path-ship/scripts/detect_project.py +260 -20
  386. package/skills/gsd-path-ship/scripts/discussion_records.py +9 -1
  387. package/skills/gsd-path-ship/scripts/discussion_validate.py +93 -35
  388. package/skills/gsd-path-ship/scripts/integration.py +244 -65
  389. package/skills/gsd-path-ship/scripts/isolation.py +539 -70
  390. package/skills/gsd-path-ship/scripts/loop_run.py +16 -4
  391. package/skills/gsd-path-ship/scripts/members.py +77 -32
  392. package/skills/gsd-path-ship/scripts/model_policy.py +5 -1
  393. package/skills/gsd-path-ship/scripts/path_config.py +3 -3
  394. package/skills/gsd-path-ship/scripts/pipeline_git.py +131 -42
  395. package/skills/gsd-path-ship/scripts/pipeline_state.py +139 -39
  396. package/skills/gsd-path-ship/scripts/promote_lookahead.py +3 -3
  397. package/skills/gsd-path-ship/scripts/roadmap.py +9 -1
  398. package/skills/gsd-path-ship/scripts/state_checkpoint.py +39 -36
  399. package/skills/gsd-path-ship/scripts/state_promote.py +15 -4
  400. package/skills/gsd-path-ship/scripts/workflow_run.py +14 -4
  401. package/skills/gsd-path-ship/scripts/worktree_paths.py +54 -2
  402. package/skills/gsd-path-ship/templates/final-review.md +11 -2
  403. package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
  404. package/skills/gsd-path-ship/templates/wave-review.md +28 -9
  405. package/skills/gsd-path-undo/references/operating-rules.md +11 -3
  406. package/skills/gsd-path-undo/references/runtime-selection.md +9 -0
  407. package/skills/gsd-path-undo/scripts/_common.py +256 -2
  408. package/skills/gsd-path-undo/scripts/discussion_records.py +9 -1
  409. package/skills/gsd-path-undo/scripts/loop_run.py +16 -4
  410. package/skills/gsd-path-undo/scripts/model_policy.py +5 -1
  411. package/skills/gsd-path-undo/scripts/path_config.py +3 -3
  412. package/skills/gsd-path-undo/scripts/pipeline_undo.py +118 -16
  413. package/skills/gsd-path-undo/scripts/worktree_paths.py +54 -2
  414. package/skills/path/DEFINE.md +34 -5
  415. package/skills/path/PLAN.md +14 -3
  416. package/skills/path/RESEARCH.md +11 -0
  417. package/skills/path/ROADMAP.md +16 -6
  418. package/skills/path/SHIP.md +32 -5
  419. package/skills/path/SKILL.md +52 -24
  420. package/skills/path/references/build-native.md +112 -10
  421. package/skills/path/references/build-recovery.md +13 -0
  422. package/skills/path/references/coder.md +7 -3
  423. package/skills/path/references/dispatch.md +13 -0
  424. package/skills/path/references/docs-auditor.md +5 -0
  425. package/skills/path/references/operating-rules.md +11 -3
  426. package/skills/path/references/planner.md +26 -4
  427. package/skills/path/references/reviewer-final.md +20 -2
  428. package/skills/path/references/reviewer-wave.md +56 -12
  429. package/skills/path/references/reviewer.md +3 -1
  430. package/skills/path/references/runtime-selection.md +9 -0
  431. package/skills/path/references/spec-probes.md +150 -0
  432. package/skills/path/scripts/_common.py +256 -2
  433. package/skills/path/scripts/archive_milestone.py +14 -13
  434. package/skills/path/scripts/build_recovery.py +155 -58
  435. package/skills/path/scripts/build_state.py +274 -8
  436. package/skills/path/scripts/check_docs_audit.py +77 -4
  437. package/skills/path/scripts/check_handoffs.py +635 -57
  438. package/skills/path/scripts/check_task_briefs.py +293 -32
  439. package/skills/path/scripts/detect_project.py +260 -20
  440. package/skills/path/scripts/discussion_records.py +9 -1
  441. package/skills/path/scripts/discussion_validate.py +93 -35
  442. package/skills/path/scripts/dispatch_driver.py +549 -53
  443. package/skills/path/scripts/git_guard.py +27 -8
  444. package/skills/path/scripts/integration.py +244 -65
  445. package/skills/path/scripts/isolation.py +539 -70
  446. package/skills/path/scripts/loop_run.py +16 -4
  447. package/skills/path/scripts/members.py +77 -32
  448. package/skills/path/scripts/model_policy.py +5 -1
  449. package/skills/path/scripts/path_config.py +3 -3
  450. package/skills/path/scripts/pipeline_git.py +131 -42
  451. package/skills/path/scripts/pipeline_state.py +139 -39
  452. package/skills/path/scripts/promote_lookahead.py +3 -3
  453. package/skills/path/scripts/review_findings.py +180 -44
  454. package/skills/path/scripts/roadmap.py +9 -1
  455. package/skills/path/scripts/state_checkpoint.py +39 -36
  456. package/skills/path/scripts/state_promote.py +15 -4
  457. package/skills/path/scripts/status_runtime.py +22 -4
  458. package/skills/path/scripts/task_context.py +14 -3
  459. package/skills/path/scripts/workflow_run.py +14 -4
  460. package/skills/path/scripts/worktree_paths.py +54 -2
  461. package/skills/path/templates/docs-audit.md +5 -1
  462. package/skills/path/templates/final-review.md +11 -2
  463. package/skills/path/templates/intent.md +30 -0
  464. package/skills/path/templates/patch-findings.md +3 -3
  465. package/skills/path/templates/plan.md +17 -2
  466. package/skills/path/templates/research-handoff.md +14 -3
  467. package/skills/path/templates/state.md +2 -1
  468. package/skills/path/templates/task.md +1 -0
  469. package/skills/path/templates/wave-review.md +28 -9
  470. package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  471. package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  472. package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  473. package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  474. package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  475. package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  476. package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
@@ -212,9 +212,10 @@ export const EXPLICIT_ONLY_TARGETS = new Set([
212
212
  "cursor",
213
213
  "zed",
214
214
  "kimi",
215
+ "muse",
215
216
  "shared-agents",
216
217
  ]);
217
- const SHARED_AGENT_TARGETS = new Set(["codex", "antigravity", "zed"]);
218
+ const SHARED_AGENT_TARGETS = new Set(["codex", "antigravity", "zed", "muse"]);
218
219
  export const SHARED_AGENT_PROFILE = "shared-agents";
219
220
  export const CURSOR_AGENT_FILENAME = "gsd-path.md";
220
221
  export const CURSOR_AGENT_BACKUP_NAME = "cursor-agent-gsd-path.md";
@@ -228,7 +229,7 @@ const MANIFEST = JSON.parse(
228
229
  );
229
230
 
230
231
  function sharedInvocations(text) {
231
- const pattern = /(`?)(\$gsd-path(?:-[a-z0-9]+)*|\$path)( status)?\1(?: \(Codex\) (?:and|or) (`?)\/(gsd-path(?:-[a-z0-9]+)*|path)( status)?\4 \((?:other hosts|Antigravity\/Zed)\))?/g;
232
+ const pattern = /(`?)(\$gsd-path(?:-[a-z0-9]+)*|\$path)( status)?\1(?: \(Codex\) (?:and|or) (`?)\/(gsd-path(?:-[a-z0-9]+)*|path)( status)?\4 \((?:other hosts|Antigravity\/Zed\/Muse)\))?/g;
232
233
  return text.replace(pattern, (_match, quote, token, arguments_, pairedQuote, pairedSkill, pairedArguments) => {
233
234
  const skill = token.slice(1);
234
235
  const argumentsText = arguments_ || "";
@@ -237,7 +238,7 @@ function sharedInvocations(text) {
237
238
  }
238
239
  const codex = `${MANIFEST.hosts.codex.invocation_prefix}${skill}`;
239
240
  const others = `${MANIFEST.hosts.antigravity.invocation_prefix}${skill}`;
240
- return `${quote}${codex}${argumentsText}${quote} (Codex) or ${quote}${others}${argumentsText}${quote} (Antigravity/Zed)`;
241
+ return `${quote}${codex}${argumentsText}${quote} (Codex) or ${quote}${others}${argumentsText}${quote} (Antigravity/Zed/Muse)`;
241
242
  });
242
243
  }
243
244
  export function skillNamesForManifest(manifest) {
@@ -355,7 +356,7 @@ export function defaultRoot(target, env = process.env) {
355
356
  }
356
357
  if (target === "antigravity") return absolutePath("~/.gemini/antigravity-cli/skills");
357
358
  if (target === "cursor") return absolutePath("~/.cursor/skills");
358
- if (target === "zed") return absolutePath("~/.agents/skills");
359
+ if (target === "zed" || target === "muse") return absolutePath("~/.agents/skills");
359
360
  if (target === "kiro") {
360
361
  return absolutePath(path.join(env.KIRO_HOME || expandUser("~/.kiro"), "skills"));
361
362
  }
@@ -386,7 +387,9 @@ function isOwnedRouterAlias(skillDir) {
386
387
  const versionFile = path.join(skillDir, "VERSION");
387
388
  if (!isFile(versionFile)) return isManagedProjectRuntime(runtime); // installs before alias version stamping
388
389
  try {
389
- return /^[0-9]+(?:\.[0-9]+)+$/.test(fs.readFileSync(versionFile, "utf8").trim());
390
+ return /^[0-9]+(?:\.[0-9]+)+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.test(
391
+ fs.readFileSync(versionFile, "utf8").trim()
392
+ );
390
393
  } catch {
391
394
  return false;
392
395
  }
@@ -1037,7 +1040,7 @@ async function applyTarget(plan, stagedRoot, transaction) {
1037
1040
  const destination = path.join(plan.root, name);
1038
1041
  hooks.reserveDirectory(destination);
1039
1042
  transaction.installed.push(destination);
1040
- fs.cpSync(path.join(stagedRoot, name), destination, { recursive: true, errorOnExist: true, force: false });
1043
+ copyIntoReservedDirectory(path.join(stagedRoot, name), destination);
1041
1044
  await tick();
1042
1045
  }
1043
1046
  if (cursorAgent !== null) {
@@ -1051,6 +1054,18 @@ function reserveDirectory(destination) {
1051
1054
  fs.mkdirSync(destination);
1052
1055
  }
1053
1056
 
1057
+ // Node 26 rejects recursive cpSync when the destination directory already exists
1058
+ // and errorOnExist is set. Reserve the skill directory, then copy each staged entry.
1059
+ export function copyIntoReservedDirectory(source, destination) {
1060
+ for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
1061
+ fs.cpSync(path.join(source, entry.name), path.join(destination, entry.name), {
1062
+ recursive: true,
1063
+ errorOnExist: true,
1064
+ force: false,
1065
+ });
1066
+ }
1067
+ }
1068
+
1054
1069
  function reserveFile(destination) {
1055
1070
  const descriptor = fs.openSync(destination, "wx", 0o644);
1056
1071
  try {
@@ -1192,7 +1207,7 @@ export function deploymentPlans(plans) {
1192
1207
  if (group.length > 1) {
1193
1208
  if (!targets.every((name) => SHARED_AGENT_TARGETS.has(name))) {
1194
1209
  throw new InstallerError(
1195
- `only Codex, Antigravity, and Zed may share a skills root: ${targets.join(", ")}`
1210
+ `only Codex, Antigravity, Zed, and Muse may share a skills root: ${targets.join(", ")}`
1196
1211
  );
1197
1212
  }
1198
1213
  profile = SHARED_AGENT_PROFILE;
@@ -1545,8 +1560,53 @@ export async function install(sourceRoot, plans, options = {}) {
1545
1560
  return results;
1546
1561
  }
1547
1562
 
1563
+ // The desktop app's rule: a VERSION stamp or a SKILL.md that names gsd-path.
1564
+ function isInstalledSkill(skillDir) {
1565
+ if (isFile(path.join(skillDir, "VERSION"))) return true;
1566
+ try {
1567
+ return fs.readFileSync(path.join(skillDir, "SKILL.md"), "utf8").includes("gsd-path");
1568
+ } catch {
1569
+ return false;
1570
+ }
1571
+ }
1572
+
1573
+ // Removes installed skills only. Project contracts and hooks stay.
1574
+ export function uninstall(plans, { dryRun = false } = {}) {
1575
+ const found = deploymentPlans(plans).map((plan) => {
1576
+ const owned = [];
1577
+ const kept = [];
1578
+ for (const name of isDirectory(plan.root) ? fs.readdirSync(plan.root).sort() : []) {
1579
+ if (!isManagedName(name)) continue;
1580
+ const entry = path.join(plan.root, name);
1581
+ (isManagedInstallEntry(plan.root, name) && isInstalledSkill(entry) ? owned : kept).push(entry);
1582
+ }
1583
+ const agent = path.join(path.dirname(plan.root), "agents", CURSOR_AGENT_FILENAME);
1584
+ if (plan.profile === "cursor" && isFile(agent)) owned.push(agent);
1585
+ return { label: plan.targets.join("+"), root: plan.root, owned, kept };
1586
+ });
1587
+ const results = [];
1588
+ const ownership = acquireInstallLocks(
1589
+ dryRun ? [] : found.filter(({ owned }) => owned.length).map(({ root }) => root)
1590
+ );
1591
+ try {
1592
+ for (const { label, root, owned, kept } of found) {
1593
+ for (const entry of kept) results.push(`${label}: kept ${entry} (not owned by GSD Path)`);
1594
+ for (const entry of owned) {
1595
+ if (!dryRun) removePath(entry);
1596
+ results.push(`${label}: ${dryRun ? "would remove" : "removed"} ${entry}`);
1597
+ }
1598
+ if (!owned.length) results.push(`${label}: nothing to remove (${root})`);
1599
+ }
1600
+ } catch (error) {
1601
+ throw new InstallerError(`uninstall stopped: ${messageOf(error)}; fix the cause and run it again`);
1602
+ } finally {
1603
+ releaseInstallLocks(ownership.locks, ownership.createdDirectories);
1604
+ }
1605
+ return results;
1606
+ }
1607
+
1548
1608
  // Documented project-relative skill roots (verified against each host's
1549
- // official skills docs). Codex, Zed, and Antigravity all discover the
1609
+ // official skills docs). Codex, Zed, Muse, and Antigravity all discover the
1550
1610
  // project-level .agents/skills standard directory.
1551
1611
  export function localRoot(target, projectDir) {
1552
1612
  const relative = LOCAL_ROOTS[target];
@@ -1565,10 +1625,16 @@ export function detectInstalls(targets, rootFor) {
1565
1625
  return plans;
1566
1626
  }
1567
1627
 
1628
+ const UNINSTALL_CONFLICTS = [
1629
+ "update", "hooks", "hooks-init", "hooks-refresh", "hooks-refresh-full",
1630
+ "runtime-restore", "runtime-upgrade", "runtime-migrate", "doctor", "member-of",
1631
+ ];
1632
+
1568
1633
  export function parseCli(argv) {
1569
1634
  const options = {
1570
1635
  all: { type: "boolean", default: false },
1571
1636
  update: { type: "boolean", default: false },
1637
+ uninstall: { type: "boolean", default: false },
1572
1638
  "dry-run": { type: "boolean", default: false },
1573
1639
  local: { type: "boolean", default: false },
1574
1640
  project: { type: "string" },
@@ -1655,13 +1721,16 @@ function usage() {
1655
1721
  "Docs: DOCS.md (hub) · QUICK.md (first run) · FULL.md · UPDATE.md\n\n" +
1656
1722
  "usage: gsd-path (no flags on a terminal opens the interactive wizard)\n" +
1657
1723
  " gsd-path [--all] [--update] [--local] [--dry-run] [--project PATH]\n" +
1658
- " [--hooks] [--hooks-init] [--hooks-refresh] [--hooks-refresh-full] [target flags]\n\n" +
1724
+ " [--hooks] [--hooks-init] [--hooks-refresh] [--hooks-refresh-full] [target flags]\n" +
1725
+ " gsd-path --uninstall [--all] [--local] [--dry-run] [target flags]\n\n" +
1659
1726
  " First install: gsd-path --all --dry-run && gsd-path --all\n" +
1660
1727
  " New repo: gsd-path --all --project /path/to/repo\n" +
1661
1728
  " Update skills: gsd-path --update (or npx @opengsd/gsd-path@latest --update)\n\n" +
1662
1729
  `targets: ${flags}\n` +
1663
1730
  " --update refresh existing installs in place; with --project also\n" +
1664
1731
  " keeps its selected runtime and project contracts\n" +
1732
+ " --uninstall remove installed GSD Path skills from the selected targets;\n" +
1733
+ " keeps other skills, host settings, project contracts, and hooks\n" +
1665
1734
  " --local install into this project's per-host skill dirs\n" +
1666
1735
  " --project PATH write project contracts and status runtime; requires Python 3.9+\n" +
1667
1736
  " --doctor read-only health check of installs, hooks, and state\n" +
@@ -1712,6 +1781,20 @@ export async function main(argv, env = process.env) {
1712
1781
  : path.resolve(SCRIPT_DIRECTORY, "..");
1713
1782
  const project =
1714
1783
  values.project !== undefined ? absolutePath(values.project) : null;
1784
+ if (values.uninstall) {
1785
+ const conflicts = UNINSTALL_CONFLICTS.filter((name) => values[name]).map((name) => `--${name}`);
1786
+ if (conflicts.length) {
1787
+ ui.error(`--uninstall cannot be combined with ${conflicts.join(", ")}`);
1788
+ return 2;
1789
+ }
1790
+ if (project !== null) {
1791
+ ui.error(
1792
+ "--uninstall removes installed skills only; project contracts and hooks are not removed " +
1793
+ "(.project/, .gsd-path/, the AGENTS.md block, guard hooks). Run it without --project."
1794
+ );
1795
+ return 2;
1796
+ }
1797
+ }
1715
1798
  const migrateAndUpdate = values["runtime-migrate"] && values.update;
1716
1799
  if (migrateAndUpdate && (project === null || values["runtime-restore"] || values["runtime-upgrade"] || values.doctor || values["hooks-init"] || values["hooks-refresh"] || values["hooks-refresh-full"])) {
1717
1800
  ui.error("--runtime-migrate --update requires --project and cannot be combined with another runtime, doctor, or hook operation");
@@ -1807,7 +1890,10 @@ export async function main(argv, env = process.env) {
1807
1890
  }
1808
1891
  }
1809
1892
  const sourceRootForInstall = sourceRoot;
1810
- const scope = local ? `project ${values.update ? "update in" : "install into"} ${process.cwd()}` : `global ${values.update ? "update" : "install"}`;
1893
+ const [verb, localVerb] = values.uninstall
1894
+ ? ["uninstall", "uninstall from"]
1895
+ : values.update ? ["update", "update in"] : ["install", "install into"];
1896
+ const scope = local ? `project ${localVerb} ${process.cwd()}` : `global ${verb}`;
1811
1897
  const mode = scope + (values["dry-run"] ? " · dry run" : "");
1812
1898
  ui.banner(mode);
1813
1899
  let plans;
@@ -1840,7 +1926,7 @@ export async function main(argv, env = process.env) {
1840
1926
  }
1841
1927
  const spin = ui.spinner("Preparing");
1842
1928
  try {
1843
- const results = await install(sourceRootForInstall, plans, {
1929
+ const results = values.uninstall ? uninstall(plans, { dryRun: values["dry-run"] }) : await install(sourceRootForInstall, plans, {
1844
1930
  project,
1845
1931
  dryRun: values["dry-run"],
1846
1932
  env,
@@ -1855,6 +1941,8 @@ export async function main(argv, env = process.env) {
1855
1941
  }
1856
1942
  const closing = values["dry-run"]
1857
1943
  ? "Dry run — nothing was written."
1944
+ : values.uninstall
1945
+ ? "Done. Restart active agent sessions."
1858
1946
  : values.update
1859
1947
  ? "Updated. Previous copies are in each root's disabled-gsd-skills backup."
1860
1948
  : "Done. Restart active agent sessions, then invoke the router explicitly.";
@@ -124,7 +124,7 @@ STATUS_STATE_FIELDS = frozenset(
124
124
  "integration_source",
125
125
  }
126
126
  )
127
- STATUS_INTEGRATION_MODES = frozenset({"direct", "pull-request"})
127
+ STATUS_INTEGRATION_MODES = frozenset({"direct", "pull-request", "external-landing"})
128
128
  STATUS_INTEGRATION_SOURCES = frozenset({"default", "milestone"})
129
129
  STATUS_SLUG = re.compile(r"^[a-z0-9][a-z0-9-]*$")
130
130
  STATUS_BRANCH = re.compile(r"^gsd-path/M(\d{3,})$")
@@ -220,30 +220,52 @@ def _cursor_guard_entry(interpreter: str) -> dict:
220
220
  }
221
221
 
222
222
 
223
- def pre_commit_hook(interpreter: str) -> str:
224
- return (
225
- "#!/bin/sh\n"
226
- "# gsd-path guard: archive immutability before commit.\n"
227
- f"exec {interpreter} \"$(git rev-parse --show-toplevel)/"
228
- f"{HOOKS_DIRECTORY}/git_guard.py\" pre-commit\n"
223
+ CHAINED_HOOK_SUFFIX = ".gsd-path-chained"
224
+
225
+
226
+ def _chained_hook_lines(name: str, guard: str) -> List[str]:
227
+ """Shell lines that run the guard, then the hook that was there before it."""
228
+ lines = [f'chained="$(dirname "$0")/{name}{CHAINED_HOOK_SUFFIX}"']
229
+ if name == "pre-push":
230
+ # Git gives pre-push its ref updates on stdin; both hooks need them.
231
+ return lines + [
232
+ "input=$(cat)",
233
+ '[ -n "$input" ] && input="$input\n"',
234
+ f'printf %s "$input" | {guard} || exit 1',
235
+ 'if [ -x "$chained" ]; then printf %s "$input" | exec "$chained" "$@"; fi',
236
+ ]
237
+ return lines + [f"{guard} || exit 1", 'if [ -x "$chained" ]; then exec "$chained" "$@"; fi']
238
+
239
+
240
+ def _git_hook(name: str, purpose: str, arguments: str, interpreter: str, chained: bool) -> str:
241
+ """chained=True also runs `<hook>.gsd-path-chained`, the user's own hook."""
242
+ guard = (
243
+ f"{interpreter} \"$(git rev-parse --show-toplevel)/"
244
+ f"{HOOKS_DIRECTORY}/git_guard.py\" {name}{arguments}"
229
245
  )
246
+ head = f"#!/bin/sh\n# gsd-path guard: {purpose}\n"
247
+ if not chained:
248
+ return f"{head}exec {guard}\n"
249
+ return head + "\n".join(_chained_hook_lines(name, guard)) + "\n"
230
250
 
231
251
 
232
- def commit_msg_hook(interpreter: str) -> str:
233
- return (
234
- "#!/bin/sh\n"
235
- "# gsd-path guard: archive immutability and ship-commit purity.\n"
236
- f"exec {interpreter} \"$(git rev-parse --show-toplevel)/"
237
- f"{HOOKS_DIRECTORY}/git_guard.py\" commit-msg \"$1\"\n"
252
+ def pre_commit_hook(interpreter: str, chained: bool = False) -> str:
253
+ return _git_hook(
254
+ "pre-commit", "archive immutability before commit.", "", interpreter, chained
238
255
  )
239
256
 
240
257
 
241
- def pre_push_hook(interpreter: str) -> str:
242
- return (
243
- "#!/bin/sh\n"
244
- "# gsd-path guard: bound branches publish only as ship commits.\n"
245
- f"exec {interpreter} \"$(git rev-parse --show-toplevel)/"
246
- f"{HOOKS_DIRECTORY}/git_guard.py\" pre-push \"$@\"\n"
258
+ def commit_msg_hook(interpreter: str, chained: bool = False) -> str:
259
+ return _git_hook(
260
+ "commit-msg", "archive immutability and ship-commit purity.", ' "$1"',
261
+ interpreter, chained,
262
+ )
263
+
264
+
265
+ def pre_push_hook(interpreter: str, chained: bool = False) -> str:
266
+ return _git_hook(
267
+ "pre-push", "bound branches publish only as ship commits.", ' "$@"',
268
+ interpreter, chained,
247
269
  )
248
270
 
249
271
 
@@ -254,7 +276,6 @@ GIT_HOOKS = (
254
276
  )
255
277
  GIT_HOOK_NAMES = tuple(name for name, _ in GIT_HOOKS)
256
278
  MEMBER_HOOK_MARKER = "gsd-path member guard"
257
- CHAINED_HOOK_SUFFIX = ".gsd-path-chained"
258
279
 
259
280
 
260
281
  def member_hook(interpreter: str, name: str) -> str:
@@ -271,19 +292,8 @@ def member_hook(interpreter: str, name: str) -> str:
271
292
  ' echo "gsd-path guard: member marker is unreadable; run members.py repair --repo <coordinator>" >&2',
272
293
  " exit 1",
273
294
  "}",
274
- f'chained="$(dirname "$0")/{name}{CHAINED_HOOK_SUFFIX}"',
275
295
  ]
276
- if name == "pre-push":
277
- # Git gives pre-push its ref updates on stdin; both hooks need them.
278
- lines += [
279
- "input=$(cat)",
280
- '[ -n "$input" ] && input="$input\n"',
281
- f'printf %s "$input" | {guard} || exit 1',
282
- 'if [ -x "$chained" ]; then printf %s "$input" | exec "$chained" "$@"; fi',
283
- ]
284
- else:
285
- lines += [f"{guard} || exit 1", 'if [ -x "$chained" ]; then exec "$chained" "$@"; fi']
286
- return "\n".join(lines) + "\n"
296
+ return "\n".join(lines + _chained_hook_lines(name, guard)) + "\n"
287
297
 
288
298
 
289
299
  def install_member_hooks(coordinator: Path, member: Path, dry_run: bool = False) -> List[str]:
@@ -505,9 +515,9 @@ HOST_NOTES = {
505
515
  "kiro": KIRO_NOTE,
506
516
  }
507
517
  EXPLICIT_ONLY_TARGETS = frozenset(
508
- {"claude", "grok", "copilot", "qwen", "cursor", "zed", "kimi", "shared-agents"}
518
+ {"claude", "grok", "copilot", "qwen", "cursor", "zed", "kimi", "muse", "shared-agents"}
509
519
  )
510
- SHARED_AGENT_TARGETS = frozenset({"codex", "antigravity", "zed"})
520
+ SHARED_AGENT_TARGETS = frozenset({"codex", "antigravity", "zed", "muse"})
511
521
  SHARED_AGENT_PROFILE = "shared-agents"
512
522
  CURSOR_AGENT_FILENAME = "gsd-path.md"
513
523
  CURSOR_AGENT_BACKUP_NAME = "cursor-agent-gsd-path.md"
@@ -533,7 +543,7 @@ def _shared_invocations(text: str) -> str:
533
543
  others = f"{hosts['antigravity']['invocation_prefix']}{skill}"
534
544
  return (
535
545
  f"{quote}{codex}{arguments}{quote} (Codex) or "
536
- f"{quote}{others}{arguments}{quote} (Antigravity/Zed)"
546
+ f"{quote}{others}{arguments}{quote} (Antigravity/Zed/Muse)"
537
547
  )
538
548
 
539
549
  return re.sub(
@@ -542,7 +552,7 @@ def _shared_invocations(text: str) -> str:
542
552
  r"(?: \(Codex\) (?:and|or) (?P<paired_quote>`?)/"
543
553
  r"(?P<paired_skill>gsd-path(?:-[a-z0-9]+)*|path)"
544
554
  r"(?P<paired_arguments> status)?(?P=paired_quote)"
545
- r" \((?:other hosts|Antigravity/Zed)\))?",
555
+ r" \((?:other hosts|Antigravity/Zed/Muse)\))?",
546
556
  replace,
547
557
  text,
548
558
  )
@@ -620,7 +630,7 @@ def default_root(target: str, environ: Optional[Mapping[str, str]] = None) -> Pa
620
630
  return absolute_path(Path("~/.gemini/antigravity-cli/skills"))
621
631
  if target == "cursor":
622
632
  return absolute_path(Path("~/.cursor/skills"))
623
- if target == "zed":
633
+ if target in ("zed", "muse"):
624
634
  return absolute_path(Path("~/.agents/skills"))
625
635
  if target == "kiro":
626
636
  return absolute_path(Path(env.get("KIRO_HOME") or "~/.kiro") / "skills")
@@ -656,7 +666,15 @@ def _is_owned_router_alias(skill_dir: Path) -> bool:
656
666
  version = version_file.read_text(encoding="utf-8").strip()
657
667
  except (OSError, UnicodeError):
658
668
  return False
659
- return re.fullmatch(r"[0-9]+(?:\.[0-9]+)+", version) is not None
669
+ return (
670
+ re.fullmatch(
671
+ r"[0-9]+(?:\.[0-9]+)+"
672
+ r"(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?"
673
+ r"(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?",
674
+ version,
675
+ )
676
+ is not None
677
+ )
660
678
 
661
679
 
662
680
  def _is_managed_install_entry(root: Path, name: str) -> bool:
@@ -1199,6 +1217,35 @@ def _rollback_target(transaction: TargetTransaction) -> None:
1199
1217
  _remove_empty_directories(transaction.created_directories)
1200
1218
 
1201
1219
 
1220
+ def _chained_hook_path(hook: Path) -> Path:
1221
+ return hook.with_name(f"{hook.name}{CHAINED_HOOK_SUFFIX}")
1222
+
1223
+
1224
+ def _foreign_git_hook(hook: Path) -> bool:
1225
+ """A regular hook file that no GSD Path installer wrote."""
1226
+ if hook.is_symlink() or not hook.is_file():
1227
+ return False
1228
+ text = hook.read_text(encoding="utf-8", errors="replace")
1229
+ return MEMBER_HOOK_MARKER not in text and not _is_managed_git_hook_content(text)
1230
+
1231
+
1232
+ def _require_chainable_git_hook(project: Path, hook: Path) -> None:
1233
+ """A foreign hook is kept as `<hook>.gsd-path-chained` and runs after the guard."""
1234
+ chained = _chained_hook_path(hook)
1235
+ if _lexists(chained):
1236
+ raise InstallerError(f"cannot chain {hook}: {chained} already exists")
1237
+ # ponytail: only the repository's own .git/hooks. A core.hooksPath directory
1238
+ # can be tracked (Husky) or shared by other repositories, so a rename there
1239
+ # reaches other people; chain it when a design for tracked hooks exists.
1240
+ if not _same_path(hook.parent, project / ".git" / "hooks"):
1241
+ raise InstallerError(
1242
+ f"cannot chain {hook}: its hooks directory is not this repository's "
1243
+ ".git/hooks (core.hooksPath or a linked worktree). Rename it to "
1244
+ f"{chained.name} yourself, then rerun: the guard runs it after its own "
1245
+ "check. See HOOKS.md."
1246
+ )
1247
+
1248
+
1202
1249
  def _project_destinations(
1203
1250
  project: Path,
1204
1251
  selected: Sequence[str],
@@ -1260,9 +1307,9 @@ def _project_destinations(
1260
1307
  )
1261
1308
  if hooks_dir is not None:
1262
1309
  for hook_name, generator in GIT_HOOKS:
1263
- destinations.append(
1264
- (hooks_dir / hook_name, None, generator(interpreter), True)
1265
- )
1310
+ hook = hooks_dir / hook_name
1311
+ chained = _lexists(_chained_hook_path(hook)) or _foreign_git_hook(hook)
1312
+ destinations.append((hook, None, generator(interpreter, chained), True))
1266
1313
  return destinations
1267
1314
 
1268
1315
 
@@ -1664,6 +1711,13 @@ def _validate_project(
1664
1711
  managed = (
1665
1712
  _update_replacement(project, destination, hooks_dir) if update else None
1666
1713
  )
1714
+ if (
1715
+ hooks_dir is not None
1716
+ and _same_path(destination.parent, hooks_dir)
1717
+ and _foreign_git_hook(destination)
1718
+ ):
1719
+ _require_chainable_git_hook(project, destination)
1720
+ continue
1667
1721
  if destination.is_symlink() or (merge is None and not update):
1668
1722
  raise _existing_contract_error(destination)
1669
1723
  if merge is not None:
@@ -1710,6 +1764,21 @@ def _apply_project(
1710
1764
  _apply_agents(source_root, destination, transaction)
1711
1765
  continue
1712
1766
  merge = mergers.get(destination)
1767
+ if (
1768
+ hooks_dir is not None
1769
+ and _same_path(destination.parent, hooks_dir)
1770
+ and _foreign_git_hook(destination)
1771
+ ):
1772
+ original = destination.read_bytes()
1773
+ mode = destination.stat().st_mode & 0o777
1774
+ chained = _chained_hook_path(destination)
1775
+ with chained.open("xb") as output:
1776
+ transaction.copied.append(chained)
1777
+ output.write(original)
1778
+ chained.chmod(mode)
1779
+ _atomic_write(destination, (content or "").encode("utf-8"), 0o755)
1780
+ transaction.replaced.append((destination, original, mode))
1781
+ continue
1713
1782
  if _lexists(destination) and not destination.is_symlink():
1714
1783
  replaceable = (
1715
1784
  update
@@ -2151,7 +2220,9 @@ def _validate_hooks_refresh(
2151
2220
  raise InstallerError(
2152
2221
  f"refusing to refresh a symlink: {hook_path}"
2153
2222
  )
2154
- if _lexists(hook_path) and not _is_managed_git_hook(hook_path):
2223
+ if _foreign_git_hook(hook_path):
2224
+ _require_chainable_git_hook(project, hook_path)
2225
+ elif _lexists(hook_path) and not _is_managed_git_hook(hook_path):
2155
2226
  raise InstallerError(
2156
2227
  f"not a managed GSD Path git hook: {hook_path}"
2157
2228
  )
@@ -2259,7 +2330,7 @@ def _deployment_plans(plans: Sequence[TargetPlan]) -> List[DeploymentPlan]:
2259
2330
  if not target_set <= SHARED_AGENT_TARGETS:
2260
2331
  labels = ", ".join(targets)
2261
2332
  raise InstallerError(
2262
- "only Codex, Antigravity, and Zed may share a skills root: "
2333
+ "only Codex, Antigravity, Zed, and Muse may share a skills root: "
2263
2334
  f"{labels}"
2264
2335
  )
2265
2336
  profile = SHARED_AGENT_PROFILE
@@ -2836,6 +2907,8 @@ def doctor(
2836
2907
  else:
2837
2908
  for name in PROJECT_RUNTIME_SCRIPTS:
2838
2909
  destination = runtime / name
2910
+ if pinned and not _lexists(destination):
2911
+ continue # a valid older selected runtime lacks helpers added later
2839
2912
  if destination.is_symlink():
2840
2913
  push("fail", f"project: runtime {name} is a symlink")
2841
2914
  runtime_current = False
@@ -2995,7 +3068,9 @@ def doctor(
2995
3068
  if not _is_managed_git_hook_content(hook_text):
2996
3069
  push("warn", f"hooks: {label} is not a managed GSD Path git hook")
2997
3070
  elif not any(
2998
- hook_text == generator(candidate)
3071
+ hook_text == generator(
3072
+ candidate, _lexists(_chained_hook_path(hook_path))
3073
+ )
2999
3074
  for candidate in INTERPRETER_CANDIDATES
3000
3075
  ):
3001
3076
  push("warn", f"hooks: {label} is stale — run --hooks-refresh-full")
@@ -3275,6 +3350,87 @@ def install(
3275
3350
  return results
3276
3351
 
3277
3352
 
3353
+ def _is_installed_skill(skill_dir: Path) -> bool:
3354
+ """The desktop app's rule: a VERSION stamp or a SKILL.md that names gsd-path."""
3355
+ if (skill_dir / "VERSION").is_file():
3356
+ return True
3357
+ try:
3358
+ return "gsd-path" in (skill_dir / "SKILL.md").read_text(encoding="utf-8", errors="replace")
3359
+ except OSError:
3360
+ return False
3361
+
3362
+
3363
+ def uninstall(plans: Sequence[TargetPlan], dry_run: bool = False) -> List[str]:
3364
+ """Remove installed skills only. Project contracts and hooks stay."""
3365
+ found = []
3366
+ for plan in _deployment_plans(plans):
3367
+ owned, kept = [], []
3368
+ names = sorted(entry.name for entry in plan.root.iterdir()) if plan.root.is_dir() else []
3369
+ for name in names:
3370
+ if not _is_managed_name(name):
3371
+ continue
3372
+ entry = plan.root / name
3373
+ if _is_managed_install_entry(plan.root, name) and _is_installed_skill(entry):
3374
+ owned.append(entry)
3375
+ else:
3376
+ kept.append(entry)
3377
+ agent = plan.root.parent / "agents" / CURSOR_AGENT_FILENAME
3378
+ if plan.profile == "cursor" and agent.is_file():
3379
+ owned.append(agent)
3380
+ found.append(("+".join(plan.targets), plan.root, owned, kept))
3381
+ results = []
3382
+ locks, created = _acquire_install_locks(
3383
+ [] if dry_run else [root for _, root, owned, _ in found if owned]
3384
+ )
3385
+ try:
3386
+ for label, root, owned, kept in found:
3387
+ results.extend(f"{label}: kept {entry} (not owned by GSD Path)" for entry in kept)
3388
+ for entry in owned:
3389
+ if not dry_run:
3390
+ _remove_path(entry)
3391
+ results.append(f"{label}: {'would remove' if dry_run else 'removed'} {entry}")
3392
+ if not owned:
3393
+ results.append(f"{label}: nothing to remove ({root})")
3394
+ except OSError as error:
3395
+ raise InstallerError(
3396
+ f"uninstall stopped: {error}; fix the cause and run it again"
3397
+ ) from error
3398
+ finally:
3399
+ _release_install_locks(locks, created)
3400
+ return results
3401
+
3402
+
3403
+ def _runtime_provenance(arguments, source_root: Path):
3404
+ """Owner-recorded provenance from --runtime-provenance-* upgrade flags.
3405
+
3406
+ When the supplied source root is a git checkout and no patch reference
3407
+ was given, its HEAD sha is recorded with one best-effort rev-parse.
3408
+ Provenance is display/audit metadata on the runtime declaration only; it
3409
+ never joins the pinned digest or runtime validation.
3410
+ """
3411
+ supplied = (arguments.runtime_provenance_source, arguments.runtime_provenance_patch,
3412
+ arguments.runtime_provenance_note)
3413
+ recorded = {key: value for key, value in zip(runtime_store.PROVENANCE_KEYS, supplied) if value}
3414
+ if not recorded:
3415
+ return None
3416
+ if "patch_ref" not in recorded:
3417
+ try:
3418
+ head = subprocess.run(["git", "rev-parse", "--show-toplevel", "HEAD"], cwd=source_root,
3419
+ capture_output=True, encoding="utf-8", check=True)
3420
+ toplevel, _, sha = head.stdout.strip().partition("\n")
3421
+ if sha and Path(toplevel).resolve() == Path(source_root).resolve():
3422
+ recorded["patch_ref"] = sha
3423
+ except (OSError, subprocess.CalledProcessError):
3424
+ pass
3425
+ return recorded
3426
+
3427
+
3428
+ UNINSTALL_CONFLICTS = (
3429
+ "update", "hooks", "hooks-init", "hooks-refresh", "hooks-refresh-full",
3430
+ "runtime-restore", "runtime-upgrade", "runtime-migrate", "doctor", "member-of",
3431
+ )
3432
+
3433
+
3278
3434
  def parser() -> argparse.ArgumentParser:
3279
3435
  argument_parser = argparse.ArgumentParser(description=__doc__)
3280
3436
  for target in TARGETS:
@@ -3283,6 +3439,12 @@ def parser() -> argparse.ArgumentParser:
3283
3439
  argument_parser.add_argument("--adapter-request", action="store_true", help=argparse.SUPPRESS)
3284
3440
  argument_parser.add_argument("--all", action="store_true", dest="all_targets")
3285
3441
  argument_parser.add_argument("--update", action="store_true")
3442
+ argument_parser.add_argument(
3443
+ "--uninstall",
3444
+ action="store_true",
3445
+ help="remove installed GSD Path skills from the selected targets; "
3446
+ "keeps other skills, host settings, project contracts, and hooks",
3447
+ )
3286
3448
  argument_parser.add_argument("--local", action="store_true")
3287
3449
  argument_parser.add_argument("--dry-run", action="store_true")
3288
3450
  argument_parser.add_argument("--project", type=Path)
@@ -3291,6 +3453,9 @@ def parser() -> argparse.ArgumentParser:
3291
3453
  runtime_actions = argument_parser.add_mutually_exclusive_group()
3292
3454
  for action in ("restore", "upgrade", "migrate"):
3293
3455
  runtime_actions.add_argument(f"--runtime-{action}", action="store_true")
3456
+ argument_parser.add_argument("--runtime-provenance-source")
3457
+ argument_parser.add_argument("--runtime-provenance-patch")
3458
+ argument_parser.add_argument("--runtime-provenance-note")
3294
3459
  argument_parser.add_argument("--hooks", action="store_true")
3295
3460
  argument_parser.add_argument("--hooks-init", action="store_true")
3296
3461
  argument_parser.add_argument("--hooks-refresh", action="store_true")
@@ -3334,8 +3499,27 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
3334
3499
  project = (
3335
3500
  absolute_path(arguments.project) if arguments.project is not None else None
3336
3501
  )
3502
+ if arguments.uninstall:
3503
+ conflicts = [
3504
+ f"--{name}" for name in UNINSTALL_CONFLICTS
3505
+ if getattr(arguments, name.replace("-", "_"))
3506
+ ]
3507
+ if conflicts:
3508
+ print(f"error: --uninstall cannot be combined with {', '.join(conflicts)}", file=sys.stderr)
3509
+ return 2
3510
+ if project is not None:
3511
+ print(
3512
+ "error: --uninstall removes installed skills only; project contracts and hooks "
3513
+ "are not removed (.project/, .gsd-path/, the AGENTS.md block, guard hooks). "
3514
+ "Run it without --project.",
3515
+ file=sys.stderr,
3516
+ )
3517
+ return 2
3337
3518
  runtime_action = next((action for action in ("restore", "upgrade", "migrate")
3338
3519
  if getattr(arguments, "runtime_" + action)), None)
3520
+ provenance = _runtime_provenance(arguments, source_root)
3521
+ if provenance is not None and runtime_action != "upgrade":
3522
+ argument_parser.error("--runtime-provenance-* requires --runtime-upgrade")
3339
3523
  if runtime_action:
3340
3524
  if project is None:
3341
3525
  argument_parser.error(f"--runtime-{runtime_action} requires --project")
@@ -3343,7 +3527,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
3343
3527
  _validate_project_git_root(project)
3344
3528
  locks, created = ([], []) if arguments.dry_run else _acquire_install_locks([project / HOOKS_DIRECTORY])
3345
3529
  try:
3346
- pin = runtime_store.operate(source_root, project, runtime_action, dry_run=arguments.dry_run)
3530
+ pin = runtime_store.operate(source_root, project, runtime_action,
3531
+ dry_run=arguments.dry_run, provenance=provenance)
3347
3532
  finally:
3348
3533
  _release_install_locks(locks, created)
3349
3534
  print(f"runtime: {runtime_action} {pin['version']} ({pin['digest']})"
@@ -3477,7 +3662,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
3477
3662
  )
3478
3663
  return 1
3479
3664
  try:
3480
- for result in install(
3665
+ for result in uninstall(plans, arguments.dry_run) if arguments.uninstall else install(
3481
3666
  source_root,
3482
3667
  plans,
3483
3668
  project,