@garygentry/feature-forge 0.2.14 → 0.3.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 (227) hide show
  1. package/README.md +6 -3
  2. package/adapters/GENERATION-REPORT.md +20 -0
  3. package/adapters/claude/.feature-forge-bundle.json +1 -1
  4. package/adapters/claude/references/forge-config-schema.json +2 -2
  5. package/adapters/claude/scripts/forge-root.sh +47 -3
  6. package/adapters/claude/scripts/forge-session.py +30 -8
  7. package/adapters/claude/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
  8. package/adapters/claude/skills/forge-5-loop/references/forge-config-schema.json +2 -2
  9. package/adapters/claude/skills/forge-guide/references/forge-config-schema.json +2 -2
  10. package/adapters/codex/.feature-forge-bundle.json +1 -1
  11. package/adapters/codex/references/forge-config-schema.json +2 -2
  12. package/adapters/codex/scripts/forge-root.sh +47 -3
  13. package/adapters/codex/scripts/forge-session.py +30 -8
  14. package/adapters/codex/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
  15. package/adapters/codex/skills/forge-5-loop/references/forge-config-schema.json +2 -2
  16. package/adapters/codex/skills/forge-guide/references/forge-config-schema.json +2 -2
  17. package/adapters/copilot/.feature-forge-bundle.json +1 -1
  18. package/adapters/copilot/references/forge-config-schema.json +2 -2
  19. package/adapters/copilot/scripts/forge-root.sh +47 -3
  20. package/adapters/copilot/scripts/forge-session.py +30 -8
  21. package/adapters/copilot/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
  22. package/adapters/copilot/skills/forge-5-loop/references/forge-config-schema.json +2 -2
  23. package/adapters/copilot/skills/forge-guide/references/forge-config-schema.json +2 -2
  24. package/adapters/cursor/.feature-forge-bundle.json +1 -1
  25. package/adapters/cursor/references/forge-config-schema.json +2 -2
  26. package/adapters/cursor/scripts/forge-root.sh +47 -3
  27. package/adapters/cursor/scripts/forge-session.py +30 -8
  28. package/adapters/cursor/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
  29. package/adapters/cursor/skills/forge-5-loop/references/forge-config-schema.json +2 -2
  30. package/adapters/cursor/skills/forge-guide/references/forge-config-schema.json +2 -2
  31. package/adapters/gemini/.feature-forge-bundle.json +1 -1
  32. package/adapters/gemini/gemini-extension.json +1 -1
  33. package/adapters/gemini/references/forge-config-schema.json +2 -2
  34. package/adapters/gemini/scripts/forge-root.sh +47 -3
  35. package/adapters/gemini/scripts/forge-session.py +30 -8
  36. package/adapters/gemini/skills/forge-4-backlog/references/forge-config-schema.json +2 -2
  37. package/adapters/gemini/skills/forge-5-loop/references/forge-config-schema.json +2 -2
  38. package/adapters/gemini/skills/forge-guide/references/forge-config-schema.json +2 -2
  39. package/adapters/pi/.feature-forge-bundle.json +6 -0
  40. package/adapters/pi/agents/forge-researcher.md +139 -0
  41. package/adapters/pi/agents/forge-spec-writer.md +116 -0
  42. package/adapters/pi/agents/forge-verifier.md +126 -0
  43. package/adapters/pi/extensions/ask-user-question/LICENSE +21 -0
  44. package/adapters/pi/extensions/ask-user-question/README.md +91 -0
  45. package/adapters/pi/extensions/ask-user-question/ask-user-question.ts +298 -0
  46. package/adapters/pi/extensions/ask-user-question/config.ts +78 -0
  47. package/adapters/pi/extensions/ask-user-question/events.ts +57 -0
  48. package/adapters/pi/extensions/ask-user-question/index.ts +61 -0
  49. package/adapters/pi/extensions/ask-user-question/locales/de.json +27 -0
  50. package/adapters/pi/extensions/ask-user-question/locales/en.json +27 -0
  51. package/adapters/pi/extensions/ask-user-question/locales/es.json +27 -0
  52. package/adapters/pi/extensions/ask-user-question/locales/fr.json +27 -0
  53. package/adapters/pi/extensions/ask-user-question/locales/pt-BR.json +27 -0
  54. package/adapters/pi/extensions/ask-user-question/locales/pt.json +27 -0
  55. package/adapters/pi/extensions/ask-user-question/locales/ru.json +27 -0
  56. package/adapters/pi/extensions/ask-user-question/locales/uk.json +27 -0
  57. package/adapters/pi/extensions/ask-user-question/locales/zh.json +29 -0
  58. package/adapters/pi/extensions/ask-user-question/reconcile.ts +49 -0
  59. package/adapters/pi/extensions/ask-user-question/rpc-fallback.ts +168 -0
  60. package/adapters/pi/extensions/ask-user-question/state/build-questionnaire.ts +302 -0
  61. package/adapters/pi/extensions/ask-user-question/state/i18n-bridge.ts +53 -0
  62. package/adapters/pi/extensions/ask-user-question/state/key-router.ts +277 -0
  63. package/adapters/pi/extensions/ask-user-question/state/questionnaire-session.ts +234 -0
  64. package/adapters/pi/extensions/ask-user-question/state/row-intent.ts +145 -0
  65. package/adapters/pi/extensions/ask-user-question/state/selectors/contract.ts +26 -0
  66. package/adapters/pi/extensions/ask-user-question/state/selectors/derivations.ts +42 -0
  67. package/adapters/pi/extensions/ask-user-question/state/selectors/focus.ts +19 -0
  68. package/adapters/pi/extensions/ask-user-question/state/selectors/projections.ts +101 -0
  69. package/adapters/pi/extensions/ask-user-question/state/state-reducer.ts +292 -0
  70. package/adapters/pi/extensions/ask-user-question/state/state.ts +55 -0
  71. package/adapters/pi/extensions/ask-user-question/tool/format-answer.ts +31 -0
  72. package/adapters/pi/extensions/ask-user-question/tool/response-envelope.ts +49 -0
  73. package/adapters/pi/extensions/ask-user-question/tool/types.ts +147 -0
  74. package/adapters/pi/extensions/ask-user-question/tool/validate-questionnaire.ts +58 -0
  75. package/adapters/pi/extensions/ask-user-question/vendor-config-shim.ts +65 -0
  76. package/adapters/pi/extensions/ask-user-question/view/component-binding.ts +47 -0
  77. package/adapters/pi/extensions/ask-user-question/view/components/inline-input.ts +98 -0
  78. package/adapters/pi/extensions/ask-user-question/view/components/multi-select-view.ts +193 -0
  79. package/adapters/pi/extensions/ask-user-question/view/components/option-list-view.ts +70 -0
  80. package/adapters/pi/extensions/ask-user-question/view/components/preview/markdown-content-cache.ts +79 -0
  81. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-block-renderer.ts +111 -0
  82. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-box-renderer.ts +88 -0
  83. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-layout-decider.ts +202 -0
  84. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-pane.ts +228 -0
  85. package/adapters/pi/extensions/ask-user-question/view/components/submit-picker.ts +67 -0
  86. package/adapters/pi/extensions/ask-user-question/view/components/tab-bar.ts +59 -0
  87. package/adapters/pi/extensions/ask-user-question/view/components/wrapping-select.ts +293 -0
  88. package/adapters/pi/extensions/ask-user-question/view/dialog-builder.ts +224 -0
  89. package/adapters/pi/extensions/ask-user-question/view/props-adapter.ts +125 -0
  90. package/adapters/pi/extensions/ask-user-question/view/stateful-view.ts +26 -0
  91. package/adapters/pi/extensions/ask-user-question/view/tab-components.ts +18 -0
  92. package/adapters/pi/extensions/ask-user-question/view/tab-content-strategy.ts +252 -0
  93. package/adapters/pi/package.json +26 -0
  94. package/adapters/pi/references/epic-manifest-schema.json +125 -0
  95. package/adapters/pi/references/forge-config-schema.json +236 -0
  96. package/adapters/pi/references/pipeline-state-schema.json +191 -0
  97. package/adapters/pi/references/portable-root.md +71 -0
  98. package/adapters/pi/references/process-overview.md +143 -0
  99. package/adapters/pi/references/ralph-loop-contract.md +221 -0
  100. package/adapters/pi/references/shared-conventions.md +295 -0
  101. package/adapters/pi/references/skill-frontmatter.schema.json +17 -0
  102. package/adapters/pi/references/stack-resolution.md +54 -0
  103. package/adapters/pi/references/stacks/_generic.md +111 -0
  104. package/adapters/pi/references/stacks/go.md +157 -0
  105. package/adapters/pi/references/stacks/python.md +184 -0
  106. package/adapters/pi/references/stacks/rust.md +170 -0
  107. package/adapters/pi/references/stacks/typescript.md +134 -0
  108. package/adapters/pi/references/stage-exit-protocol.md +258 -0
  109. package/adapters/pi/references/templates/specs-hygiene/AGENTS.md +32 -0
  110. package/adapters/pi/references/templates/specs-hygiene/CLAUDE.md +31 -0
  111. package/adapters/pi/references/vendor-construct-inventory.md +50 -0
  112. package/adapters/pi/scripts/epic-manifest.py +1694 -0
  113. package/adapters/pi/scripts/forge-bootstrap.py +1070 -0
  114. package/adapters/pi/scripts/forge-init.sh +58 -0
  115. package/adapters/pi/scripts/forge-root.sh +179 -0
  116. package/adapters/pi/scripts/forge-session.py +1888 -0
  117. package/adapters/pi/scripts/validate-traceability.py +150 -0
  118. package/adapters/pi/skills/forge/SKILL.md +243 -0
  119. package/adapters/pi/skills/forge/references/pipeline-state-schema.json +191 -0
  120. package/adapters/pi/skills/forge/references/process-overview.md +143 -0
  121. package/adapters/pi/skills/forge/references/shared-conventions.md +295 -0
  122. package/adapters/pi/skills/forge/references/stage-exit-protocol.md +258 -0
  123. package/adapters/pi/skills/forge-0-epic/SKILL.md +308 -0
  124. package/adapters/pi/skills/forge-0-epic/references/edit-mode.md +266 -0
  125. package/adapters/pi/skills/forge-0-epic/references/epic-manifest-subcommands.md +75 -0
  126. package/adapters/pi/skills/forge-0-epic/references/pipeline-state-schema.json +191 -0
  127. package/adapters/pi/skills/forge-0-epic/references/portable-root.md +71 -0
  128. package/adapters/pi/skills/forge-0-epic/references/shared-conventions.md +295 -0
  129. package/adapters/pi/skills/forge-0-epic/references/stage-exit-protocol.md +258 -0
  130. package/adapters/pi/skills/forge-1-prd/SKILL.md +164 -0
  131. package/adapters/pi/skills/forge-1-prd/references/pipeline-state-schema.json +191 -0
  132. package/adapters/pi/skills/forge-1-prd/references/prd-template.md +106 -0
  133. package/adapters/pi/skills/forge-1-prd/references/shared-conventions.md +295 -0
  134. package/adapters/pi/skills/forge-1-prd/references/stage-exit-protocol.md +258 -0
  135. package/adapters/pi/skills/forge-2-tech/SKILL.md +225 -0
  136. package/adapters/pi/skills/forge-2-tech/references/pipeline-state-schema.json +191 -0
  137. package/adapters/pi/skills/forge-2-tech/references/shared-conventions.md +295 -0
  138. package/adapters/pi/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
  139. package/adapters/pi/skills/forge-2-tech/references/stack-resolution.md +54 -0
  140. package/adapters/pi/skills/forge-2-tech/references/stacks/_generic.md +111 -0
  141. package/adapters/pi/skills/forge-2-tech/references/stacks/go.md +157 -0
  142. package/adapters/pi/skills/forge-2-tech/references/stacks/python.md +184 -0
  143. package/adapters/pi/skills/forge-2-tech/references/stacks/rust.md +170 -0
  144. package/adapters/pi/skills/forge-2-tech/references/stacks/typescript.md +134 -0
  145. package/adapters/pi/skills/forge-2-tech/references/stage-exit-protocol.md +258 -0
  146. package/adapters/pi/skills/forge-3-specs/SKILL.md +178 -0
  147. package/adapters/pi/skills/forge-3-specs/references/pipeline-state-schema.json +191 -0
  148. package/adapters/pi/skills/forge-3-specs/references/shared-conventions.md +295 -0
  149. package/adapters/pi/skills/forge-3-specs/references/spec-archetypes.md +106 -0
  150. package/adapters/pi/skills/forge-3-specs/references/spec-examples.md +71 -0
  151. package/adapters/pi/skills/forge-3-specs/references/stacks/_generic.md +111 -0
  152. package/adapters/pi/skills/forge-3-specs/references/stacks/go.md +157 -0
  153. package/adapters/pi/skills/forge-3-specs/references/stacks/python.md +184 -0
  154. package/adapters/pi/skills/forge-3-specs/references/stacks/rust.md +170 -0
  155. package/adapters/pi/skills/forge-3-specs/references/stacks/typescript.md +134 -0
  156. package/adapters/pi/skills/forge-3-specs/references/stage-exit-protocol.md +258 -0
  157. package/adapters/pi/skills/forge-4-backlog/SKILL.md +175 -0
  158. package/adapters/pi/skills/forge-4-backlog/references/forge-config-schema.json +236 -0
  159. package/adapters/pi/skills/forge-4-backlog/references/pipeline-state-schema.json +191 -0
  160. package/adapters/pi/skills/forge-4-backlog/references/shared-conventions.md +295 -0
  161. package/adapters/pi/skills/forge-4-backlog/references/stage-exit-protocol.md +258 -0
  162. package/adapters/pi/skills/forge-5-loop/SKILL.md +314 -0
  163. package/adapters/pi/skills/forge-5-loop/references/forge-config-schema.json +236 -0
  164. package/adapters/pi/skills/forge-5-loop/references/ralph-loop-contract.md +221 -0
  165. package/adapters/pi/skills/forge-5-loop/references/result-reporting.md +85 -0
  166. package/adapters/pi/skills/forge-5-loop/references/runner-contract.md +341 -0
  167. package/adapters/pi/skills/forge-5-loop/references/shared-conventions.md +295 -0
  168. package/adapters/pi/skills/forge-5-loop/references/stage-exit-protocol.md +258 -0
  169. package/adapters/pi/skills/forge-6-docs/SKILL.md +202 -0
  170. package/adapters/pi/skills/forge-6-docs/references/doc-conventions.md +126 -0
  171. package/adapters/pi/skills/forge-6-docs/references/pipeline-state-schema.json +191 -0
  172. package/adapters/pi/skills/forge-6-docs/references/shared-conventions.md +295 -0
  173. package/adapters/pi/skills/forge-bootstrap/SKILL.md +250 -0
  174. package/adapters/pi/skills/forge-bootstrap/references/templates/ci/github-actions.yml +12 -0
  175. package/adapters/pi/skills/forge-bootstrap/references/templates/generic/run.sh +3 -0
  176. package/adapters/pi/skills/forge-bootstrap/references/templates/generic/test.sh +13 -0
  177. package/adapters/pi/skills/forge-bootstrap/references/templates/go/go.mod +3 -0
  178. package/adapters/pi/skills/forge-bootstrap/references/templates/go/main.go +12 -0
  179. package/adapters/pi/skills/forge-bootstrap/references/templates/go/main_test.go +11 -0
  180. package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +35 -0
  181. package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +36 -0
  182. package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/README.md +11 -0
  183. package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/Apache-2.0/LICENSE +198 -0
  184. package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/MIT/LICENSE +21 -0
  185. package/adapters/pi/skills/forge-bootstrap/references/templates/python/pyproject.toml +24 -0
  186. package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/__init__.py +5 -0
  187. package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/main.py +13 -0
  188. package/adapters/pi/skills/forge-bootstrap/references/templates/python/tests/test_smoke.py +8 -0
  189. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/Cargo.toml +15 -0
  190. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/lib.rs +7 -0
  191. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/main.rs +5 -0
  192. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/tests/smoke.rs +6 -0
  193. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/package.json +15 -0
  194. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/src/index.ts +4 -0
  195. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/test/smoke.test.ts +6 -0
  196. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/tsconfig.json +14 -0
  197. package/adapters/pi/skills/forge-fix/SKILL.md +98 -0
  198. package/adapters/pi/skills/forge-fix/references/shared-conventions.md +295 -0
  199. package/adapters/pi/skills/forge-fix/references/stage-exit-protocol.md +258 -0
  200. package/adapters/pi/skills/forge-guide/SKILL.md +192 -0
  201. package/adapters/pi/skills/forge-guide/references/forge-config-schema.json +236 -0
  202. package/adapters/pi/skills/forge-guide/references/process-overview.md +143 -0
  203. package/adapters/pi/skills/forge-guide/references/ralph-loop-contract.md +221 -0
  204. package/adapters/pi/skills/forge-guide/references/shared-conventions.md +295 -0
  205. package/adapters/pi/skills/forge-guide/references/stack-resolution.md +54 -0
  206. package/adapters/pi/skills/forge-guide/references/stacks/_generic.md +111 -0
  207. package/adapters/pi/skills/forge-guide/references/stacks/go.md +157 -0
  208. package/adapters/pi/skills/forge-guide/references/stacks/python.md +184 -0
  209. package/adapters/pi/skills/forge-guide/references/stacks/rust.md +170 -0
  210. package/adapters/pi/skills/forge-guide/references/stacks/typescript.md +134 -0
  211. package/adapters/pi/skills/forge-init/SKILL.md +72 -0
  212. package/adapters/pi/skills/forge-verify/SKILL.md +273 -0
  213. package/adapters/pi/skills/forge-verify/references/pipeline-state-schema.json +191 -0
  214. package/adapters/pi/skills/forge-verify/references/shared-conventions.md +295 -0
  215. package/adapters/pi/skills/forge-verify/references/verification-checklists.md +477 -0
  216. package/dist/agent-targets.d.ts +1 -1
  217. package/dist/agent-targets.js +23 -3
  218. package/dist/detect.d.ts +1 -1
  219. package/dist/detect.js +2 -1
  220. package/dist/manifest.d.ts +1 -1
  221. package/dist/manifest.js +2 -2
  222. package/dist/placements.js +5 -1
  223. package/dist/rauf.d.ts +4 -4
  224. package/dist/rauf.js +3 -3
  225. package/dist/types.d.ts +31 -6
  226. package/dist/types.js +6 -3
  227. package/package.json +14 -3
@@ -1434,6 +1434,17 @@ def _resolve_feature_dir(specs_dir: Path, feature: str, epic: str | None) -> Pat
1434
1434
  return flat
1435
1435
 
1436
1436
 
1437
+ def _host_command(command: str, host: str) -> str:
1438
+ """Rewrite a `/feature-forge:` slash command to the host's surface.
1439
+
1440
+ Pi's slash-command surface is `/skill:` (matching the adapter body's
1441
+ `/feature-forge:` -> `/skill:` translation). The scripted stage-exit output bypasses
1442
+ that body translation, so it rewrites the commands it emits here. No-op for
1443
+ claude/generic, which keep the canonical `/feature-forge:` form.
1444
+ """
1445
+ return command.replace("/feature-forge:", "/skill:") if host == "pi" else command
1446
+
1447
+
1437
1448
  def _next_steps_block(
1438
1449
  next_command: str, host: str, reconcile: dict | None = None
1439
1450
  ) -> str:
@@ -1463,6 +1474,18 @@ def _next_steps_block(
1463
1474
  "2. Then start a fresh session and run the next stage below — or "
1464
1475
  "re-run `/feature-forge:forge` to let the navigator resume from disk."
1465
1476
  )
1477
+ elif host == "pi":
1478
+ # Pi's fresh-session command is `/new` (not `/clear`); its slash-command
1479
+ # surface is `/skill:` (the fenced command below is rewritten to match).
1480
+ clear_line = (
1481
+ "1. `/new` — recommended unconditionally at this stage boundary; every "
1482
+ "artifact is on disk, so the work survives starting a fresh session. "
1483
+ "I can't run `/new` for you — you have to run it yourself."
1484
+ )
1485
+ next_line = (
1486
+ "2. Then, in the new session, run the next stage below — or re-run "
1487
+ "`/skill:forge` to let the navigator resume from disk."
1488
+ )
1466
1489
  else:
1467
1490
  clear_line = (
1468
1491
  "1. Clear your session / start a fresh session — recommended "
@@ -1479,7 +1502,7 @@ def _next_steps_block(
1479
1502
  # epic-change request the primary is the reconcile command; otherwise it is the
1480
1503
  # normal next-stage command. The fence sits before the sentinel, so the
1481
1504
  # sentinel remains the absolute last line.
1482
- fenced_command = reconcile["command"] if blocking else next_command
1505
+ fenced_command = _host_command(reconcile["command"] if blocking else next_command, host)
1483
1506
  lines = ["**Next steps**", clear_line]
1484
1507
  if blocking:
1485
1508
  count = reconcile["count"]
@@ -1495,15 +1518,14 @@ def _next_steps_block(
1495
1518
  lines.append("")
1496
1519
  lines.append(f"```\n{fenced_command}\n```")
1497
1520
  if blocking and reconcile.get("deferred"):
1498
- lines.append(
1499
- f"After reconciling, continue the pipeline with: `{reconcile['deferred']}`"
1500
- )
1521
+ deferred_cmd = _host_command(reconcile["deferred"], host)
1522
+ lines.append(f"After reconciling, continue the pipeline with: `{deferred_cmd}`")
1501
1523
  elif reconcile and reconcile.get("reminder"):
1502
1524
  count = reconcile["count"]
1503
1525
  plural = "s" if count != 1 else ""
1504
1526
  lines.append(
1505
1527
  f"You also flagged {count} epic change{plural} to reconcile when "
1506
- f"convenient: `{reconcile['command']}`"
1528
+ f"convenient: `{_host_command(reconcile['command'], host)}`"
1507
1529
  )
1508
1530
  lines.append(NEXT_STEPS_SENTINEL)
1509
1531
  return "\n".join(lines)
@@ -1630,10 +1652,10 @@ def stage_exit(
1630
1652
  "verifyGate": verify_gate,
1631
1653
  "autoFixEligible": auto_fix_eligible,
1632
1654
  "verifyState": verify_label,
1633
- "verifyCommand": f"/feature-forge:forge-verify {feature}",
1655
+ "verifyCommand": _host_command(f"/feature-forge:forge-verify {feature}", host),
1634
1656
  "autoVerifyEffective": effective_auto_verify,
1635
1657
  "nextStage": next_stage_id,
1636
- "nextCommand": next_command,
1658
+ "nextCommand": _host_command(next_command, host) if next_command else next_command,
1637
1659
  "invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
1638
1660
  "gitRepo": git_repo,
1639
1661
  "cleanTree": clean_tree,
@@ -1759,7 +1781,7 @@ def main() -> int:
1759
1781
  p_exit.add_argument("--epic", default=None, help="Epic name for a nested member")
1760
1782
  p_exit.add_argument("--next-feature", default=None, dest="next_feature",
1761
1783
  help="First actionable feature (epic handoff next-command arg)")
1762
- p_exit.add_argument("--host", default="claude", choices=("claude", "generic"),
1784
+ p_exit.add_argument("--host", default="claude", choices=("claude", "generic", "pi"),
1763
1785
  help="Host wording for the NEXT-STEPS block")
1764
1786
  p_exit.add_argument("--json", action="store_true", dest="json_output")
1765
1787
 
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-forge",
3
- "version": "0.12.9",
3
+ "version": "0.13.0",
4
4
  "agent": "cursor",
5
5
  "generatedBy": "python3 scripts/build-adapters.py"
6
6
  }
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -92,9 +92,24 @@ done < <(ls -t "$HOME"/.claude/plugins/cache/*/feature-forge/*/.claude-plugin/pl
92
92
  # Globs that match nothing expand to themselves; the is_root test rejects such literals. Covers
93
93
  # every supported agent's install destination under BOTH global ($HOME) and project ($PWD) scope,
94
94
  # matching the installer's per-agent layout: claude .claude/skills, codex .agents/skills, copilot
95
- # .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions. The cache glob repeats
96
- # step 2a's path for a cache install that carries only the neutral bundle sentinel (no
97
- # plugin.json for ls -t to key on).
95
+ # .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions, pi .pi/skills or
96
+ # $PI_CODING_AGENT_DIR/skills. The cache glob repeats step 2a's path for a cache install that
97
+ # carries only the neutral bundle sentinel (no plugin.json for ls -t to key on).
98
+ if [ -n "${PI_CODING_AGENT_DIR:-}" ]; then
99
+ for candidate in \
100
+ "$PI_CODING_AGENT_DIR/skills/feature-forge" \
101
+ "$PI_CODING_AGENT_DIR"/git/*/feature-forge/adapters/pi \
102
+ "$PI_CODING_AGENT_DIR"/git/*/*/feature-forge/adapters/pi \
103
+ "$PI_CODING_AGENT_DIR"/packages/*/feature-forge/adapters/pi \
104
+ "$PI_CODING_AGENT_DIR"/npm/*/@garygentry/feature-forge/adapters/pi \
105
+ "$PI_CODING_AGENT_DIR"/node_modules/@garygentry/feature-forge/adapters/pi \
106
+ ; do
107
+ if is_root "$candidate"; then
108
+ accept_root "$candidate"
109
+ fi
110
+ done
111
+ fi
112
+
98
113
  for candidate in \
99
114
  "$HOME/.claude/skills/feature-forge" \
100
115
  "$PWD/.claude/skills/feature-forge" \
@@ -108,12 +123,41 @@ for candidate in \
108
123
  "$PWD/.cursor/rules/feature-forge" \
109
124
  "$HOME/.gemini/extensions/feature-forge" \
110
125
  "$PWD/.gemini/extensions/feature-forge" \
126
+ "$HOME/.pi/agent/skills/feature-forge" \
127
+ "$PWD/.pi/skills/feature-forge" \
128
+ "$HOME"/.pi/agent/git/*/feature-forge/adapters/pi \
129
+ "$HOME"/.pi/agent/git/*/*/feature-forge/adapters/pi \
130
+ "$HOME"/.pi/agent/packages/*/feature-forge/adapters/pi \
131
+ "$HOME"/.pi/agent/npm/*/@garygentry/feature-forge/adapters/pi \
132
+ "$HOME"/.pi/agent/node_modules/@garygentry/feature-forge/adapters/pi \
133
+ "$PWD"/.pi/git/*/feature-forge/adapters/pi \
134
+ "$PWD"/.pi/git/*/*/feature-forge/adapters/pi \
135
+ "$PWD"/.pi/packages/*/feature-forge/adapters/pi \
136
+ "$PWD"/.pi/npm/*/@garygentry/feature-forge/adapters/pi \
137
+ "$PWD"/.pi/node_modules/@garygentry/feature-forge/adapters/pi \
111
138
  ; do
112
139
  if is_root "$candidate"; then
113
140
  accept_root "$candidate"
114
141
  fi
115
142
  done
116
143
 
144
+ # Project-scoped Pi installs may be discovered from a subdirectory of the repository. Probe
145
+ # ancestor .pi roots up to the filesystem root; this is bounded by path depth and avoids
146
+ # recursive globs. Scoped to .pi ONLY — every other agent's project layout is probed at $PWD
147
+ # in the fixed list above, and widening those to ancestors here would silently change
148
+ # established discovery behaviour for agents this bundle did not introduce.
149
+ probe_dir="$PWD"
150
+ while :; do
151
+ candidate="$probe_dir/.pi/skills/feature-forge"
152
+ if is_root "$candidate"; then
153
+ accept_root "$candidate"
154
+ fi
155
+ [ "$probe_dir" = "/" ] && break
156
+ next_probe_dir="$(dirname -- "$probe_dir")"
157
+ [ "$next_probe_dir" = "$probe_dir" ] && break
158
+ probe_dir="$next_probe_dir"
159
+ done
160
+
117
161
  # ── Step 3: env fallback — neutral FEATURE_FORGE_ROOT, then the legacy CLAUDE_PLUGIN_ROOT. ─
118
162
  # The neutral override works for every agent; CLAUDE_PLUGIN_ROOT is kept only for backwards
119
163
  # compatibility with existing Claude installs (C-4).
@@ -1434,6 +1434,17 @@ def _resolve_feature_dir(specs_dir: Path, feature: str, epic: str | None) -> Pat
1434
1434
  return flat
1435
1435
 
1436
1436
 
1437
+ def _host_command(command: str, host: str) -> str:
1438
+ """Rewrite a `/feature-forge:` slash command to the host's surface.
1439
+
1440
+ Pi's slash-command surface is `/skill:` (matching the adapter body's
1441
+ `/feature-forge:` -> `/skill:` translation). The scripted stage-exit output bypasses
1442
+ that body translation, so it rewrites the commands it emits here. No-op for
1443
+ claude/generic, which keep the canonical `/feature-forge:` form.
1444
+ """
1445
+ return command.replace("/feature-forge:", "/skill:") if host == "pi" else command
1446
+
1447
+
1437
1448
  def _next_steps_block(
1438
1449
  next_command: str, host: str, reconcile: dict | None = None
1439
1450
  ) -> str:
@@ -1463,6 +1474,18 @@ def _next_steps_block(
1463
1474
  "2. Then start a fresh session and run the next stage below — or "
1464
1475
  "re-run `/feature-forge:forge` to let the navigator resume from disk."
1465
1476
  )
1477
+ elif host == "pi":
1478
+ # Pi's fresh-session command is `/new` (not `/clear`); its slash-command
1479
+ # surface is `/skill:` (the fenced command below is rewritten to match).
1480
+ clear_line = (
1481
+ "1. `/new` — recommended unconditionally at this stage boundary; every "
1482
+ "artifact is on disk, so the work survives starting a fresh session. "
1483
+ "I can't run `/new` for you — you have to run it yourself."
1484
+ )
1485
+ next_line = (
1486
+ "2. Then, in the new session, run the next stage below — or re-run "
1487
+ "`/skill:forge` to let the navigator resume from disk."
1488
+ )
1466
1489
  else:
1467
1490
  clear_line = (
1468
1491
  "1. Clear your session / start a fresh session — recommended "
@@ -1479,7 +1502,7 @@ def _next_steps_block(
1479
1502
  # epic-change request the primary is the reconcile command; otherwise it is the
1480
1503
  # normal next-stage command. The fence sits before the sentinel, so the
1481
1504
  # sentinel remains the absolute last line.
1482
- fenced_command = reconcile["command"] if blocking else next_command
1505
+ fenced_command = _host_command(reconcile["command"] if blocking else next_command, host)
1483
1506
  lines = ["**Next steps**", clear_line]
1484
1507
  if blocking:
1485
1508
  count = reconcile["count"]
@@ -1495,15 +1518,14 @@ def _next_steps_block(
1495
1518
  lines.append("")
1496
1519
  lines.append(f"```\n{fenced_command}\n```")
1497
1520
  if blocking and reconcile.get("deferred"):
1498
- lines.append(
1499
- f"After reconciling, continue the pipeline with: `{reconcile['deferred']}`"
1500
- )
1521
+ deferred_cmd = _host_command(reconcile["deferred"], host)
1522
+ lines.append(f"After reconciling, continue the pipeline with: `{deferred_cmd}`")
1501
1523
  elif reconcile and reconcile.get("reminder"):
1502
1524
  count = reconcile["count"]
1503
1525
  plural = "s" if count != 1 else ""
1504
1526
  lines.append(
1505
1527
  f"You also flagged {count} epic change{plural} to reconcile when "
1506
- f"convenient: `{reconcile['command']}`"
1528
+ f"convenient: `{_host_command(reconcile['command'], host)}`"
1507
1529
  )
1508
1530
  lines.append(NEXT_STEPS_SENTINEL)
1509
1531
  return "\n".join(lines)
@@ -1630,10 +1652,10 @@ def stage_exit(
1630
1652
  "verifyGate": verify_gate,
1631
1653
  "autoFixEligible": auto_fix_eligible,
1632
1654
  "verifyState": verify_label,
1633
- "verifyCommand": f"/feature-forge:forge-verify {feature}",
1655
+ "verifyCommand": _host_command(f"/feature-forge:forge-verify {feature}", host),
1634
1656
  "autoVerifyEffective": effective_auto_verify,
1635
1657
  "nextStage": next_stage_id,
1636
- "nextCommand": next_command,
1658
+ "nextCommand": _host_command(next_command, host) if next_command else next_command,
1637
1659
  "invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
1638
1660
  "gitRepo": git_repo,
1639
1661
  "cleanTree": clean_tree,
@@ -1759,7 +1781,7 @@ def main() -> int:
1759
1781
  p_exit.add_argument("--epic", default=None, help="Epic name for a nested member")
1760
1782
  p_exit.add_argument("--next-feature", default=None, dest="next_feature",
1761
1783
  help="First actionable feature (epic handoff next-command arg)")
1762
- p_exit.add_argument("--host", default="claude", choices=("claude", "generic"),
1784
+ p_exit.add_argument("--host", default="claude", choices=("claude", "generic", "pi"),
1763
1785
  help="Host wording for the NEXT-STEPS block")
1764
1786
  p_exit.add_argument("--json", action="store_true", dest="json_output")
1765
1787
 
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-forge",
3
- "version": "0.12.9",
3
+ "version": "0.13.0",
4
4
  "agent": "gemini",
5
5
  "generatedBy": "python3 scripts/build-adapters.py"
6
6
  }
@@ -4,7 +4,7 @@
4
4
  "regenerate": "python3 scripts/build-adapters.py"
5
5
  },
6
6
  "name": "feature-forge",
7
- "version": "0.12.9",
7
+ "version": "0.13.0",
8
8
  "skills": [
9
9
  {
10
10
  "name": "forge-0-epic",
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -92,9 +92,24 @@ done < <(ls -t "$HOME"/.claude/plugins/cache/*/feature-forge/*/.claude-plugin/pl
92
92
  # Globs that match nothing expand to themselves; the is_root test rejects such literals. Covers
93
93
  # every supported agent's install destination under BOTH global ($HOME) and project ($PWD) scope,
94
94
  # matching the installer's per-agent layout: claude .claude/skills, codex .agents/skills, copilot
95
- # .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions. The cache glob repeats
96
- # step 2a's path for a cache install that carries only the neutral bundle sentinel (no
97
- # plugin.json for ls -t to key on).
95
+ # .github/feature-forge, cursor .cursor/rules, gemini .gemini/extensions, pi .pi/skills or
96
+ # $PI_CODING_AGENT_DIR/skills. The cache glob repeats step 2a's path for a cache install that
97
+ # carries only the neutral bundle sentinel (no plugin.json for ls -t to key on).
98
+ if [ -n "${PI_CODING_AGENT_DIR:-}" ]; then
99
+ for candidate in \
100
+ "$PI_CODING_AGENT_DIR/skills/feature-forge" \
101
+ "$PI_CODING_AGENT_DIR"/git/*/feature-forge/adapters/pi \
102
+ "$PI_CODING_AGENT_DIR"/git/*/*/feature-forge/adapters/pi \
103
+ "$PI_CODING_AGENT_DIR"/packages/*/feature-forge/adapters/pi \
104
+ "$PI_CODING_AGENT_DIR"/npm/*/@garygentry/feature-forge/adapters/pi \
105
+ "$PI_CODING_AGENT_DIR"/node_modules/@garygentry/feature-forge/adapters/pi \
106
+ ; do
107
+ if is_root "$candidate"; then
108
+ accept_root "$candidate"
109
+ fi
110
+ done
111
+ fi
112
+
98
113
  for candidate in \
99
114
  "$HOME/.claude/skills/feature-forge" \
100
115
  "$PWD/.claude/skills/feature-forge" \
@@ -108,12 +123,41 @@ for candidate in \
108
123
  "$PWD/.cursor/rules/feature-forge" \
109
124
  "$HOME/.gemini/extensions/feature-forge" \
110
125
  "$PWD/.gemini/extensions/feature-forge" \
126
+ "$HOME/.pi/agent/skills/feature-forge" \
127
+ "$PWD/.pi/skills/feature-forge" \
128
+ "$HOME"/.pi/agent/git/*/feature-forge/adapters/pi \
129
+ "$HOME"/.pi/agent/git/*/*/feature-forge/adapters/pi \
130
+ "$HOME"/.pi/agent/packages/*/feature-forge/adapters/pi \
131
+ "$HOME"/.pi/agent/npm/*/@garygentry/feature-forge/adapters/pi \
132
+ "$HOME"/.pi/agent/node_modules/@garygentry/feature-forge/adapters/pi \
133
+ "$PWD"/.pi/git/*/feature-forge/adapters/pi \
134
+ "$PWD"/.pi/git/*/*/feature-forge/adapters/pi \
135
+ "$PWD"/.pi/packages/*/feature-forge/adapters/pi \
136
+ "$PWD"/.pi/npm/*/@garygentry/feature-forge/adapters/pi \
137
+ "$PWD"/.pi/node_modules/@garygentry/feature-forge/adapters/pi \
111
138
  ; do
112
139
  if is_root "$candidate"; then
113
140
  accept_root "$candidate"
114
141
  fi
115
142
  done
116
143
 
144
+ # Project-scoped Pi installs may be discovered from a subdirectory of the repository. Probe
145
+ # ancestor .pi roots up to the filesystem root; this is bounded by path depth and avoids
146
+ # recursive globs. Scoped to .pi ONLY — every other agent's project layout is probed at $PWD
147
+ # in the fixed list above, and widening those to ancestors here would silently change
148
+ # established discovery behaviour for agents this bundle did not introduce.
149
+ probe_dir="$PWD"
150
+ while :; do
151
+ candidate="$probe_dir/.pi/skills/feature-forge"
152
+ if is_root "$candidate"; then
153
+ accept_root "$candidate"
154
+ fi
155
+ [ "$probe_dir" = "/" ] && break
156
+ next_probe_dir="$(dirname -- "$probe_dir")"
157
+ [ "$next_probe_dir" = "$probe_dir" ] && break
158
+ probe_dir="$next_probe_dir"
159
+ done
160
+
117
161
  # ── Step 3: env fallback — neutral FEATURE_FORGE_ROOT, then the legacy CLAUDE_PLUGIN_ROOT. ─
118
162
  # The neutral override works for every agent; CLAUDE_PLUGIN_ROOT is kept only for backwards
119
163
  # compatibility with existing Claude installs (C-4).
@@ -1434,6 +1434,17 @@ def _resolve_feature_dir(specs_dir: Path, feature: str, epic: str | None) -> Pat
1434
1434
  return flat
1435
1435
 
1436
1436
 
1437
+ def _host_command(command: str, host: str) -> str:
1438
+ """Rewrite a `/feature-forge:` slash command to the host's surface.
1439
+
1440
+ Pi's slash-command surface is `/skill:` (matching the adapter body's
1441
+ `/feature-forge:` -> `/skill:` translation). The scripted stage-exit output bypasses
1442
+ that body translation, so it rewrites the commands it emits here. No-op for
1443
+ claude/generic, which keep the canonical `/feature-forge:` form.
1444
+ """
1445
+ return command.replace("/feature-forge:", "/skill:") if host == "pi" else command
1446
+
1447
+
1437
1448
  def _next_steps_block(
1438
1449
  next_command: str, host: str, reconcile: dict | None = None
1439
1450
  ) -> str:
@@ -1463,6 +1474,18 @@ def _next_steps_block(
1463
1474
  "2. Then start a fresh session and run the next stage below — or "
1464
1475
  "re-run `/feature-forge:forge` to let the navigator resume from disk."
1465
1476
  )
1477
+ elif host == "pi":
1478
+ # Pi's fresh-session command is `/new` (not `/clear`); its slash-command
1479
+ # surface is `/skill:` (the fenced command below is rewritten to match).
1480
+ clear_line = (
1481
+ "1. `/new` — recommended unconditionally at this stage boundary; every "
1482
+ "artifact is on disk, so the work survives starting a fresh session. "
1483
+ "I can't run `/new` for you — you have to run it yourself."
1484
+ )
1485
+ next_line = (
1486
+ "2. Then, in the new session, run the next stage below — or re-run "
1487
+ "`/skill:forge` to let the navigator resume from disk."
1488
+ )
1466
1489
  else:
1467
1490
  clear_line = (
1468
1491
  "1. Clear your session / start a fresh session — recommended "
@@ -1479,7 +1502,7 @@ def _next_steps_block(
1479
1502
  # epic-change request the primary is the reconcile command; otherwise it is the
1480
1503
  # normal next-stage command. The fence sits before the sentinel, so the
1481
1504
  # sentinel remains the absolute last line.
1482
- fenced_command = reconcile["command"] if blocking else next_command
1505
+ fenced_command = _host_command(reconcile["command"] if blocking else next_command, host)
1483
1506
  lines = ["**Next steps**", clear_line]
1484
1507
  if blocking:
1485
1508
  count = reconcile["count"]
@@ -1495,15 +1518,14 @@ def _next_steps_block(
1495
1518
  lines.append("")
1496
1519
  lines.append(f"```\n{fenced_command}\n```")
1497
1520
  if blocking and reconcile.get("deferred"):
1498
- lines.append(
1499
- f"After reconciling, continue the pipeline with: `{reconcile['deferred']}`"
1500
- )
1521
+ deferred_cmd = _host_command(reconcile["deferred"], host)
1522
+ lines.append(f"After reconciling, continue the pipeline with: `{deferred_cmd}`")
1501
1523
  elif reconcile and reconcile.get("reminder"):
1502
1524
  count = reconcile["count"]
1503
1525
  plural = "s" if count != 1 else ""
1504
1526
  lines.append(
1505
1527
  f"You also flagged {count} epic change{plural} to reconcile when "
1506
- f"convenient: `{reconcile['command']}`"
1528
+ f"convenient: `{_host_command(reconcile['command'], host)}`"
1507
1529
  )
1508
1530
  lines.append(NEXT_STEPS_SENTINEL)
1509
1531
  return "\n".join(lines)
@@ -1630,10 +1652,10 @@ def stage_exit(
1630
1652
  "verifyGate": verify_gate,
1631
1653
  "autoFixEligible": auto_fix_eligible,
1632
1654
  "verifyState": verify_label,
1633
- "verifyCommand": f"/feature-forge:forge-verify {feature}",
1655
+ "verifyCommand": _host_command(f"/feature-forge:forge-verify {feature}", host),
1634
1656
  "autoVerifyEffective": effective_auto_verify,
1635
1657
  "nextStage": next_stage_id,
1636
- "nextCommand": next_command,
1658
+ "nextCommand": _host_command(next_command, host) if next_command else next_command,
1637
1659
  "invalidAutoVerifyKeys": invalid_auto_verify_keys(config),
1638
1660
  "gitRepo": git_repo,
1639
1661
  "cleanTree": clean_tree,
@@ -1759,7 +1781,7 @@ def main() -> int:
1759
1781
  p_exit.add_argument("--epic", default=None, help="Epic name for a nested member")
1760
1782
  p_exit.add_argument("--next-feature", default=None, dest="next_feature",
1761
1783
  help="First actionable feature (epic handoff next-command arg)")
1762
- p_exit.add_argument("--host", default="claude", choices=("claude", "generic"),
1784
+ p_exit.add_argument("--host", default="claude", choices=("claude", "generic", "pi"),
1763
1785
  help="Host wording for the NEXT-STEPS block")
1764
1786
  p_exit.add_argument("--json", action="store_true", dest="json_output")
1765
1787
 
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -217,8 +217,8 @@
217
217
  },
218
218
  "installHint": {
219
219
  "type": "string",
220
- "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.12.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.12.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
- "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.12.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
220
+ "default": "Provision rauf for a multi-agent setup with the cross-agent installer: `npx @garygentry/feature-forge install` (records the pinned @garygentry/rauf@0.13.0 default). Or install/upgrade just the rauf CLI: `npx @garygentry/rauf@0.13.0 --version`, or `curl -fsSL https://raw.githubusercontent.com/garygentry/rauf/main/scripts/install-binary.sh | bash`.",
221
+ "description": "Shown when the runner BINARY is missing or too old (version gate fails, minRunnerVersion floor) — how to obtain/upgrade the CLI itself. Names two distinct binary-provisioning paths: (1) the cross-agent installer (`npx @garygentry/feature-forge install`, the multi-agent provisioning path that pins @garygentry/rauf@0.13.0), and (2) the direct rauf-CLI install/upgrade one-liner. Distinct from setupHint (which installs per-project artifacts); a version-gate failure is ALWAYS this hint, never setupHint."
222
222
  },
223
223
  "schemaVersion": {
224
224
  "type": "string",
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "feature-forge",
3
+ "version": "0.13.0",
4
+ "agent": "pi",
5
+ "generatedBy": "python3 scripts/build-adapters.py"
6
+ }