multi-forge 0.8.0__tar.gz → 0.9.0__tar.gz

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 (433) hide show
  1. {multi_forge-0.8.0 → multi_forge-0.9.0}/PKG-INFO +1 -1
  2. {multi_forge-0.8.0 → multi_forge-0.9.0}/pyproject.toml +1 -1
  3. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/extensions.py +289 -64
  4. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/commands.py +1 -1
  5. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/direct_commands.py +2 -2
  6. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/policy.py +2 -2
  7. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/memory.py +189 -91
  8. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/memory_report.py +3 -3
  9. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/policy.py +2 -3
  10. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/runtime.py +3 -0
  11. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_lane.py +4 -2
  12. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_lifecycle.py +4 -4
  13. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_memory.py +3 -3
  14. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/workflow.py +2 -2
  15. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/backends/litellm.yaml +22 -0
  16. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/codex-responses-local.yaml +2 -2
  17. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +1 -1
  18. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +2 -2
  19. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-openai.yaml +3 -3
  20. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +1 -1
  21. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +4 -4
  22. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/schema.py +4 -0
  23. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/data/model_catalog.yaml +82 -2
  24. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/__init__.py +3 -2
  25. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/clients/__init__.py +1 -0
  26. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/runtime/codex_preflight.py +8 -8
  27. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/runtime/registry.py +25 -15
  28. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/state/io.py +28 -3
  29. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/state/lock.py +7 -2
  30. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/__init__.py +6 -0
  31. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/codex_hooks.py +2 -2
  32. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/hook_dispatcher.py +8 -4
  33. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/hook_migration.py +1 -0
  34. multi_forge-0.9.0/src/forge/install/installer.py +2412 -0
  35. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/models.py +57 -1
  36. multi_forge-0.9.0/src/forge/install/skill_cache.py +174 -0
  37. multi_forge-0.9.0/src/forge/install/skill_compiler.py +1660 -0
  38. multi_forge-0.9.0/src/forge/install/skill_planning.py +424 -0
  39. multi_forge-0.9.0/src/forge/install/skill_validation.py +1140 -0
  40. multi_forge-0.9.0/src/forge/install/tracking.py +394 -0
  41. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/semantic/supervisor.py +11 -12
  42. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/models.py +6 -3
  43. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/claude/cleanup.py +2 -1
  44. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/consumer_lanes.py +11 -8
  45. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/hooks/session_start.py +4 -4
  46. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/launch_confirmation.py +1 -1
  47. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/memory_inheritance.py +1 -1
  48. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/models.py +13 -11
  49. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/overrides.py +3 -2
  50. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/passport.py +234 -18
  51. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/project_memory.py +17 -4
  52. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/store.py +2 -1
  53. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/transfer.py +1 -1
  54. multi_forge-0.8.0/src/skills/challenge/SKILL.md → multi_forge-0.9.0/src/skills/challenge/content.md +10 -20
  55. multi_forge-0.9.0/src/skills/challenge/forge-skill.yaml +9 -0
  56. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/consensus/SKILL.md +3 -3
  57. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/debate/SKILL.md +2 -2
  58. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/panel/SKILL.md +7 -7
  59. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/panel/resources/synthesis.md +4 -4
  60. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/0-enable.md +8 -2
  61. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/15-skills.md +50 -2
  62. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/16-memory.md +81 -2
  63. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/17-info.md +30 -0
  64. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/18-disable.md +31 -5
  65. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/19-uninstall.md +11 -6
  66. multi_forge-0.9.0/src/skills/qa/resources/checklist/2-extension.md +473 -0
  67. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/4-proxy.md +2 -2
  68. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/6-hook.md +10 -1
  69. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist.md +15 -9
  70. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/scripts/start-container.sh +2 -2
  71. multi_forge-0.9.0/src/skills/review/content.md +96 -0
  72. multi_forge-0.9.0/src/skills/review/forge-skill.yaml +21 -0
  73. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/references/skills-writing-guide.md +58 -0
  74. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/resources/code-anthropic.md +7 -15
  75. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/resources/code-gemini.md +7 -15
  76. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/resources/code-openai.md +8 -16
  77. multi_forge-0.9.0/src/skills/review-docs/content.md +93 -0
  78. multi_forge-0.9.0/src/skills/review-docs/forge-skill.yaml +14 -0
  79. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs-anthropic.md +6 -14
  80. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs-gemini.md +6 -14
  81. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs-openai.md +7 -15
  82. multi_forge-0.9.0/src/skills/smoke-test/content.md +18 -0
  83. multi_forge-0.9.0/src/skills/smoke-test/forge-skill.yaml +8 -0
  84. multi_forge-0.9.0/src/skills/smoke-test/scripts/smoke-test.sh +157 -0
  85. multi_forge-0.8.0/src/skills/understand/SKILL.md → multi_forge-0.9.0/src/skills/understand/content.md +27 -51
  86. multi_forge-0.9.0/src/skills/understand/forge-skill.yaml +18 -0
  87. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/code-anthropic.md +11 -24
  88. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/code-gemini.md +12 -25
  89. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/code-openai.md +12 -25
  90. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/code.md +11 -24
  91. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/docs-anthropic.md +13 -28
  92. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/docs-gemini.md +14 -29
  93. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/docs-openai.md +14 -29
  94. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/understand/resources/docs.md +13 -28
  95. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/walkthrough/SKILL.md +13 -10
  96. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/walkthrough/resources/checklist.md +276 -37
  97. multi_forge-0.8.0/src/forge/install/installer.py +0 -1259
  98. multi_forge-0.8.0/src/forge/install/tracking.py +0 -230
  99. multi_forge-0.8.0/src/skills/qa/resources/checklist/2-extension.md +0 -265
  100. multi_forge-0.8.0/src/skills/review/SKILL.md +0 -125
  101. multi_forge-0.8.0/src/skills/review-docs/SKILL.md +0 -121
  102. multi_forge-0.8.0/src/skills/smoke-test/SKILL.md +0 -27
  103. multi_forge-0.8.0/src/skills/smoke-test/scripts/smoke-test.sh +0 -118
  104. {multi_forge-0.8.0 → multi_forge-0.9.0}/.gitignore +0 -0
  105. {multi_forge-0.8.0 → multi_forge-0.9.0}/LICENSE +0 -0
  106. {multi_forge-0.8.0 → multi_forge-0.9.0}/NOTICE +0 -0
  107. {multi_forge-0.8.0 → multi_forge-0.9.0}/README.md +0 -0
  108. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/agents/.gitkeep +0 -0
  109. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/commands/.gitkeep +0 -0
  110. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/__init__.py +0 -0
  111. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/__init__.py +0 -0
  112. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/adapters/__init__.py +0 -0
  113. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/adapters/litellm.py +0 -0
  114. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/creation.py +0 -0
  115. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/registry.py +0 -0
  116. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/remote/__init__.py +0 -0
  117. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/remote/base.py +0 -0
  118. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/remote/openrouter.py +0 -0
  119. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/backend/sources.py +0 -0
  120. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/__init__.py +0 -0
  121. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/activity.py +0 -0
  122. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/auth.py +0 -0
  123. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/backend.py +0 -0
  124. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/claude.py +0 -0
  125. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/codex.py +0 -0
  126. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/config_cmd.py +0 -0
  127. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/consumer_lane_freeze.py +0 -0
  128. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/editor.py +0 -0
  129. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/gc.py +0 -0
  130. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/guards.py +0 -0
  131. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/__init__.py +0 -0
  132. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/_group.py +0 -0
  133. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/_helpers.py +0 -0
  134. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/codex_patch.py +0 -0
  135. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/codex_policy.py +0 -0
  136. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/codex_transfer.py +0 -0
  137. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/protocols.py +0 -0
  138. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
  139. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/hooks/verification.py +0 -0
  140. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/logs.py +0 -0
  141. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/main.py +0 -0
  142. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/memory_writer.py +0 -0
  143. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/model.py +0 -0
  144. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/output.py +0 -0
  145. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/proxy.py +0 -0
  146. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/proxy_audit.py +0 -0
  147. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/proxy_costs.py +0 -0
  148. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/search.py +0 -0
  149. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session.py +0 -0
  150. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_codex.py +0 -0
  151. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_fork.py +0 -0
  152. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_manage.py +0 -0
  153. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_model_pin.py +0 -0
  154. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_resume_modes.py +0 -0
  155. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_rewind.py +0 -0
  156. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_routing.py +0 -0
  157. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/session_supervisor_options.py +0 -0
  158. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/status_line.py +0 -0
  159. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/statusline/__init__.py +0 -0
  160. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/statusline/context.py +0 -0
  161. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/statusline/names.py +0 -0
  162. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/statusline/palette.py +0 -0
  163. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/statusline/registry.py +0 -0
  164. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/statusline/throttle.py +0 -0
  165. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/telemetry.py +0 -0
  166. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/trace.py +0 -0
  167. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/cli/transfer.py +0 -0
  168. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/__init__.py +0 -0
  169. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/dataclass_utils.py +0 -0
  170. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/__init__.py +0 -0
  171. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/backends/__init__.py +0 -0
  172. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/__init__.py +0 -0
  173. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/anthropic-passthrough.yaml +0 -0
  174. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +0 -0
  175. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +0 -0
  176. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +0 -0
  177. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +0 -0
  178. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +0 -0
  179. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +0 -0
  180. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-anthropic.yaml +0 -0
  181. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +0 -0
  182. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +0 -0
  183. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +0 -0
  184. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +0 -0
  185. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +0 -0
  186. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +0 -0
  187. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +0 -0
  188. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/config/loader.py +0 -0
  189. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/__init__.py +0 -0
  190. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/auth/__init__.py +0 -0
  191. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/auth/capabilities.py +0 -0
  192. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/auth/credentials_file.py +0 -0
  193. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/auth/protocols.py +0 -0
  194. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/auth/secrets.py +0 -0
  195. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/auth/template_secrets.py +0 -0
  196. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/backend_dependency.py +0 -0
  197. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/credential_registry.py +0 -0
  198. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/data/__init__.py +0 -0
  199. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
  200. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
  201. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
  202. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/effort.py +0 -0
  203. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/invoker/__init__.py +0 -0
  204. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/invoker/_lifecycle.py +0 -0
  205. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/invoker/claude.py +0 -0
  206. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/invoker/codex.py +0 -0
  207. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/invoker/codex_stream.py +0 -0
  208. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/invoker/types.py +0 -0
  209. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/lanes.py +0 -0
  210. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/clients/base.py +0 -0
  211. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/clients/litellm.py +0 -0
  212. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/clients/openai_compat.py +0 -0
  213. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/clients/openrouter.py +0 -0
  214. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/credentials.py +0 -0
  215. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/detection.py +0 -0
  216. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/errors.py +0 -0
  217. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/protocols.py +0 -0
  218. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/llm/types.py +0 -0
  219. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/logging.py +0 -0
  220. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/models/__init__.py +0 -0
  221. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/models/catalog.py +0 -0
  222. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/models/direct_model.py +0 -0
  223. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/models/types.py +0 -0
  224. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/naming.py +0 -0
  225. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/__init__.py +0 -0
  226. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/backend_reconcile.py +0 -0
  227. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/claude_session.py +0 -0
  228. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/codex_bridge.py +0 -0
  229. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/codex_enrollment.py +0 -0
  230. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/codex_interactive.py +0 -0
  231. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/codex_session.py +0 -0
  232. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/context.py +0 -0
  233. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/gc.py +0 -0
  234. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/policy.py +0 -0
  235. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/provider_trace.py +0 -0
  236. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/proxy.py +0 -0
  237. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/resolution.py +0 -0
  238. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/session.py +0 -0
  239. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/session_context.py +0 -0
  240. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/transfer.py +0 -0
  241. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/ops/usage_summary.py +0 -0
  242. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/paths.py +0 -0
  243. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/process.py +0 -0
  244. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/provider_types.py +0 -0
  245. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/__init__.py +0 -0
  246. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/cost_tracking.py +0 -0
  247. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/env.py +0 -0
  248. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/headless_json.py +0 -0
  249. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/proxy.py +0 -0
  250. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/routing.py +0 -0
  251. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/session_runner.py +0 -0
  252. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/structured_output.py +0 -0
  253. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/tagger.py +0 -0
  254. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/reactive/throttle.py +0 -0
  255. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/run_id.py +0 -0
  256. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/runtime/__init__.py +0 -0
  257. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/runtime/codex_preflight_cache.py +0 -0
  258. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/runtime/codex_rollouts.py +0 -0
  259. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/runtime_vocab.py +0 -0
  260. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/state/__init__.py +0 -0
  261. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/state/exceptions.py +0 -0
  262. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/state/retention.py +0 -0
  263. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/state/timestamps.py +0 -0
  264. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/state/versioned_store.py +0 -0
  265. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/telemetry/__init__.py +0 -0
  266. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/telemetry/caps.py +0 -0
  267. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/telemetry/downstream.py +0 -0
  268. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/telemetry/jsonl_io.py +0 -0
  269. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/telemetry/upstream.py +0 -0
  270. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/telemetry/vocabulary.py +0 -0
  271. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/tiers.py +0 -0
  272. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/transcript.py +0 -0
  273. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/typing_helpers.py +0 -0
  274. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/usage/__init__.py +0 -0
  275. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/usage/billing.py +0 -0
  276. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/usage/correlation.py +0 -0
  277. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/usage/emit.py +0 -0
  278. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/usage/ledger.py +0 -0
  279. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/usage/measurement.py +0 -0
  280. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/usage/vocabulary.py +0 -0
  281. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/workqueue/__init__.py +0 -0
  282. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/workqueue/queue.py +0 -0
  283. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/core/workqueue/types.py +0 -0
  284. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/cli.py +0 -0
  285. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/doctor.py +0 -0
  286. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/exceptions.py +0 -0
  287. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/hooks.py +0 -0
  288. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/preset.py +0 -0
  289. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/project_compat.py +0 -0
  290. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/project_registry.py +0 -0
  291. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/settings_merge.py +0 -0
  292. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/install/version.py +0 -0
  293. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/__init__.py +0 -0
  294. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/deterministic/__init__.py +0 -0
  295. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/deterministic/base.py +0 -0
  296. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/deterministic/coding_standards.py +0 -0
  297. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/deterministic/registry.py +0 -0
  298. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/deterministic/tdd.py +0 -0
  299. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/engine.py +0 -0
  300. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/protocols.py +0 -0
  301. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/queries.py +0 -0
  302. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/semantic/__init__.py +0 -0
  303. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/semantic/plan_check.py +0 -0
  304. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/semantic/shadow.py +0 -0
  305. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/semantic/shadow_runner.py +0 -0
  306. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/semantic/verdict.py +0 -0
  307. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/store.py +0 -0
  308. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/supervisor_lane_degrade.py +0 -0
  309. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/team/__init__.py +0 -0
  310. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/team/config.py +0 -0
  311. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/team/handlers.py +0 -0
  312. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/team/prompts.py +0 -0
  313. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/types.py +0 -0
  314. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/workflow/__init__.py +0 -0
  315. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/workflow/branches.py +0 -0
  316. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/workflow/config.py +0 -0
  317. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/workflow/divergence.py +0 -0
  318. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/workflow/policy.py +0 -0
  319. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/policy/workflow/stages.py +0 -0
  320. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/__init__.py +0 -0
  321. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/audit_logger.py +0 -0
  322. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/base_client.py +0 -0
  323. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/client_adapter.py +0 -0
  324. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/client_factory.py +0 -0
  325. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/converters.py +0 -0
  326. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/cost_logger.py +0 -0
  327. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/cost_tracker.py +0 -0
  328. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/data_models.py +0 -0
  329. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/error_hints.py +0 -0
  330. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/intercept.py +0 -0
  331. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/metrics.py +0 -0
  332. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/model_spec.py +0 -0
  333. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/passthrough.py +0 -0
  334. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/ports.py +0 -0
  335. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/provider_trace_logger.py +0 -0
  336. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/proxies.py +0 -0
  337. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/proxy_identity.py +0 -0
  338. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/proxy_orchestrator.py +0 -0
  339. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/proxy_startup.py +0 -0
  340. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/responses_ingress.py +0 -0
  341. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/responses_passthrough.py +0 -0
  342. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/server.py +0 -0
  343. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/stream_relay.py +0 -0
  344. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/proxy/utils.py +0 -0
  345. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/__init__.py +0 -0
  346. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/adversarial.py +0 -0
  347. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/consensus.py +0 -0
  348. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/engine.py +0 -0
  349. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/__init__.py +0 -0
  350. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/code_consensus_evaluation.md +0 -0
  351. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/code_debate_evaluation.md +0 -0
  352. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/codereview-performance.md +0 -0
  353. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/codereview-quick.md +0 -0
  354. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/codereview-security.md +0 -0
  355. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/codereview.md +0 -0
  356. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/consensus_evaluation.md +0 -0
  357. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/debate_evaluation.md +0 -0
  358. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/docreview-quick.md +0 -0
  359. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/docreview.md +0 -0
  360. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/resources/thinkdeep.md +0 -0
  361. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/routing.py +0 -0
  362. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/review/synthesis.py +0 -0
  363. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/runtime_config.py +0 -0
  364. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/__init__.py +0 -0
  365. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/bm25_store.py +0 -0
  366. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/content_store.py +0 -0
  367. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/engine.py +0 -0
  368. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/exceptions.py +0 -0
  369. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/extractor.py +0 -0
  370. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/index_state.py +0 -0
  371. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/store.py +0 -0
  372. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/search/tokenizer.py +0 -0
  373. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/__init__.py +0 -0
  374. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/active.py +0 -0
  375. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/addendum.py +0 -0
  376. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/artifacts.py +0 -0
  377. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/claude/__init__.py +0 -0
  378. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/claude/invoke.py +0 -0
  379. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/claude/paths.py +0 -0
  380. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/claude/relocate.py +0 -0
  381. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/cleanup.py +0 -0
  382. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/codex_handoff.py +0 -0
  383. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/codex_invoke.py +0 -0
  384. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/config.py +0 -0
  385. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/context_limit.py +0 -0
  386. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/effective.py +0 -0
  387. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/exceptions.py +0 -0
  388. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/hooks/__init__.py +0 -0
  389. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/hooks/models.py +0 -0
  390. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/identity.py +0 -0
  391. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/index.py +0 -0
  392. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/launch.py +0 -0
  393. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/manager.py +0 -0
  394. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/memory_writer.py +0 -0
  395. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/model_pin.py +0 -0
  396. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/plan_resolution.py +0 -0
  397. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/prev_sessions.py +0 -0
  398. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/rewind.py +0 -0
  399. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/shadow_curation.py +0 -0
  400. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/validation.py +0 -0
  401. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/worktree/__init__.py +0 -0
  402. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/worktree/cleanup.py +0 -0
  403. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/worktree/config_copy.py +0 -0
  404. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/session/worktree/create.py +0 -0
  405. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/sidecar/__init__.py +0 -0
  406. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/sidecar/container.py +0 -0
  407. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/forge/sidecar/docker.py +0 -0
  408. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/analyze/SKILL.md +0 -0
  409. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/consensus/resources/synthesis.md +0 -0
  410. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/SKILL.md +0 -0
  411. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
  412. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/10-resume.md +0 -0
  413. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/11-config.md +0 -0
  414. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/12-search.md +0 -0
  415. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/13-policy.md +0 -0
  416. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
  417. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/20-cleanup.md +0 -0
  418. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/3-authentication.md +0 -0
  419. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/5-session.md +0 -0
  420. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/7-costs.md +0 -0
  421. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/8-status-line.md +0 -0
  422. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/9-direct-commands.md +0 -0
  423. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/resources/report-template.md +0 -0
  424. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/qa/scripts/walkthrough-state.py +0 -0
  425. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/references/claude-4.6.md +0 -0
  426. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/references/claude-4.8.md +0 -0
  427. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/references/gemini-3.1.md +0 -0
  428. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/references/gpt-5.5.md +0 -0
  429. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review/resources/code.md +0 -0
  430. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs.md +0 -0
  431. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
  432. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/walkthrough/scripts/setup-test-repo.sh +0 -0
  433. {multi_forge-0.8.0 → multi_forge-0.9.0}/src/skills/walkthrough/scripts/walkthrough-state.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multi-forge
3
- Version: 0.8.0
3
+ Version: 0.9.0
4
4
  Summary: Multi-runtime agent toolkit: proxy routing, cost control, session management, policy enforcement, and workflow orchestration
5
5
  Project-URL: Homepage, https://github.com/hapa1i/multi-forge
6
6
  Project-URL: Repository, https://github.com/hapa1i/multi-forge
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "multi-forge"
3
- version = "0.8.0"
3
+ version = "0.9.0"
4
4
  description = "Multi-runtime agent toolkit: proxy routing, cost control, session management, policy enforcement, and workflow orchestration"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -39,7 +39,12 @@ from forge.install.hook_migration import (
39
39
  plan_project_hook_migration,
40
40
  )
41
41
  from forge.install.hooks import diagnose_forge_hook_runtime
42
- from forge.install.installer import Installer, find_claude_root, find_forge_installation
42
+ from forge.install.installer import (
43
+ Installer,
44
+ find_claude_root,
45
+ find_forge_installation,
46
+ inspect_skill_package_status,
47
+ )
43
48
  from forge.install.models import (
44
49
  FILE_MODULES,
45
50
  PROFILE_RANK,
@@ -61,6 +66,13 @@ from forge.install.tracking import TrackingStore
61
66
  console = Console()
62
67
  _log = logging.getLogger(__name__)
63
68
  _INSTALL_SCOPE_HELP = "Installation scope: local (gitignored), project (committed), user (global)"
69
+ _SKILL_RUNTIME_IDS = {"claude": "claude_code", "codex": "codex"}
70
+ _NON_FORCEABLE_SKILL_CONFLICT_REASONS = {
71
+ "duplicate_scan_chain",
72
+ "forge_managed_scope_duplicate",
73
+ "runtime_unavailable",
74
+ "scope_unsupported",
75
+ }
64
76
 
65
77
 
66
78
  def _detect_git_project_root(start: Path | None = None) -> Path | None:
@@ -103,6 +115,51 @@ def _parse_modules(modules_str: str | None) -> set[InstallModule] | None:
103
115
  return {InstallModule(m.strip()) for m in modules_str.split(",")}
104
116
 
105
117
 
118
+ def _parse_skill_runtimes(values: tuple[str, ...]) -> tuple[str, ...] | None:
119
+ """Map repeatable CLI runtime names to stable runtime registry ids."""
120
+
121
+ if not values:
122
+ return None
123
+ selected: set[str] = set()
124
+ for value in values:
125
+ if value == "all":
126
+ selected.update(_SKILL_RUNTIME_IDS.values())
127
+ else:
128
+ selected.add(_SKILL_RUNTIME_IDS[value])
129
+ return tuple(runtime for runtime in _SKILL_RUNTIME_IDS.values() if runtime in selected)
130
+
131
+
132
+ def _enforce_claude_version_if_required(plan: InstallPlan, project_root: Path | None = None) -> None:
133
+ """Apply the Claude CLI gate only when the plan mutates Claude surfaces."""
134
+
135
+ if not plan.requires_claude_version:
136
+ return
137
+ from forge.install.version import check_minimum_version
138
+
139
+ version_check = check_minimum_version()
140
+ if not version_check.ok:
141
+ print_error(f"{version_check.reason}")
142
+ codex_packages_selected = any(
143
+ package.runtime == _SKILL_RUNTIME_IDS["codex"] and package.action in {"install", "update"}
144
+ for package in plan.skill_packages
145
+ )
146
+ if version_check.version is None and codex_packages_selected:
147
+ root_option = f" --root {shlex.quote(str(project_root))}" if project_root is not None else ""
148
+ command = (
149
+ f"forge extension enable --scope {plan.scope}{root_option} --profile minimal "
150
+ "--with skills --without commands --runtime codex"
151
+ )
152
+ print_tip(
153
+ f"Install Claude Code, or install only Codex skills with '{command}'.",
154
+ console=console,
155
+ )
156
+ elif version_check.version is None:
157
+ print_tip("Install Claude Code, then retry.", console=console)
158
+ else:
159
+ print_tip("Run 'claude update' to upgrade.", console=console)
160
+ raise click.exceptions.Exit(1)
161
+
162
+
106
163
  def _count_actions(plan: InstallPlan) -> tuple[int, int, int]:
107
164
  """Count non-skip actions in a plan.
108
165
 
@@ -218,11 +275,12 @@ def _print_completion_message(
218
275
  parts.append("Codex hooks")
219
276
  console.print(f"\n[green]Extensions enabled.[/green] ({', '.join(parts)} updated)")
220
277
 
221
- print_tip(
222
- "Run 'forge claude preset edit' to customize permissions and env vars.",
223
- blank_before=False,
224
- console=console,
225
- )
278
+ if InstallModule.PERMISSIONS.value in plan.modules:
279
+ print_tip(
280
+ "Run 'forge claude preset edit' to customize permissions and env vars.",
281
+ blank_before=False,
282
+ console=console,
283
+ )
226
284
 
227
285
  if InstallModule.SKILLS.value in plan.modules:
228
286
  print_tip(
@@ -355,7 +413,10 @@ def _print_hook_migration_plan(plan: ProjectHookMigrationPlan) -> None:
355
413
  for settings_plan in (plan.user.settings, plan.user.legacy_settings):
356
414
  if settings_plan.changed:
357
415
  console.print(f" - {display_path(settings_plan.path)}: update user runtime hooks; backup first")
358
- if plan.user.codex is not None and plan.user.codex.action in {"install", "update"}:
416
+ if plan.user.codex is not None and plan.user.codex.action in {
417
+ "install",
418
+ "update",
419
+ }:
359
420
  console.print(f" - {display_path(plan.user.codex.config_path)}: install/update user Codex hooks")
360
421
  if plan.user.settings.added_path is not None:
361
422
  console.print(
@@ -472,6 +533,35 @@ def _print_plan(plan: InstallPlan, dry_run: bool = False) -> None:
472
533
  console.print(f" Profile: {plan.profile}")
473
534
  console.print(f" Modules: {', '.join(plan.modules)}")
474
535
 
536
+ if plan.skill_packages:
537
+ console.print(f"\n{prefix}[bold]Skill packages:[/bold]")
538
+ table = Table(show_header=True, header_style="bold", box=None)
539
+ table.add_column("ACTION", style="dim")
540
+ table.add_column("RUNTIME")
541
+ table.add_column("SKILL")
542
+ table.add_column("TARGET")
543
+ table.add_column("REASON", style="dim")
544
+ for package in plan.skill_packages:
545
+ style = {
546
+ "install": "green",
547
+ "update": "yellow",
548
+ "skip": "dim",
549
+ "conflict": "red",
550
+ }.get(package.action, "")
551
+ reason = package.reason or ""
552
+ if package.duplicate_dirs:
553
+ duplicates = ", ".join(display_path(path) for path in package.duplicate_dirs)
554
+ reason = f"{reason}; duplicates: {duplicates}" if reason else f"duplicates: {duplicates}"
555
+ table.add_row(
556
+ package.action,
557
+ package.runtime,
558
+ package.skill,
559
+ display_path(package.target_dir) if package.target_dir else "",
560
+ reason,
561
+ style=style,
562
+ )
563
+ console.print(table)
564
+
475
565
  if plan.files:
476
566
  console.print(f"\n{prefix}[bold]Files:[/bold]")
477
567
  table = Table(show_header=True, header_style="bold", box=None)
@@ -527,7 +617,26 @@ def _print_plan(plan: InstallPlan, dry_run: bool = False) -> None:
527
617
  console.print(f"\n{prefix}[bold red]Conflicts detected:[/bold red]")
528
618
  for c in plan.conflicts:
529
619
  console.print(f" [red]- {c}[/red]")
530
- print_tip("Use --force to override, or resolve conflicts manually.", console=console)
620
+ has_policy_conflicts = any(
621
+ package.action == "conflict" and package.reason in _NON_FORCEABLE_SKILL_CONFLICT_REASONS
622
+ for package in plan.skill_packages
623
+ )
624
+ has_forceable_conflicts = any(file.action == "conflict" for file in plan.files) or any(
625
+ setting.action == "conflict" for setting in plan.settings
626
+ )
627
+ if has_policy_conflicts and has_forceable_conflicts:
628
+ print_tip(
629
+ "Use --force only for file or settings conflicts; resolve runtime, scope, "
630
+ "and duplicate-scan conflicts manually.",
631
+ console=console,
632
+ )
633
+ elif has_policy_conflicts:
634
+ print_tip(
635
+ "Resolve runtime, scope, or duplicate-scan conflicts manually; --force does not override them.",
636
+ console=console,
637
+ )
638
+ else:
639
+ print_tip("Use --force to override, or resolve conflicts manually.", console=console)
531
640
 
532
641
 
533
642
  def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
@@ -550,6 +659,7 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
550
659
  table.add_column("PROJECT PATH")
551
660
  table.add_column("PROFILE")
552
661
  table.add_column("FILES")
662
+ table.add_column("SKILL PACKAGES")
553
663
 
554
664
  for scope, project_path, installation in installations:
555
665
  scope_display = scope
@@ -561,6 +671,7 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
561
671
  path_display,
562
672
  installation.profile,
563
673
  str(len(installation.files)),
674
+ str(len(installation.skill_packages)),
564
675
  )
565
676
 
566
677
  console.print(table)
@@ -589,7 +700,10 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
589
700
  installer.uninstall()
590
701
  console.print(" [green]✓ Done[/green]")
591
702
 
592
- except ForgeInstallError as e:
703
+ except Exception as e:
704
+ # ``--all`` is a batch boundary: one filesystem, settings, or
705
+ # tracking failure must not prevent later installations from being
706
+ # attempted. KeyboardInterrupt/SystemExit remain uncaught.
593
707
  console.print(f" [red]✗ Failed: {e}[/red]")
594
708
  errors.append((scope, project_path, str(e)))
595
709
 
@@ -598,6 +712,7 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
598
712
  console.print(f"[yellow]Completed with {len(errors)} error(s).[/yellow]")
599
713
  for scope, path, err in errors:
600
714
  console.print(f" [red]- {scope} ({display_path(path) if path else 'global'}): {err}[/red]")
715
+ raise click.exceptions.Exit(1)
601
716
  else:
602
717
  console.print(f"[green]All {len(installations)} installation(s) disabled.[/green]")
603
718
 
@@ -611,6 +726,19 @@ def _can_resolve_project_root(scope: InstallScope, *, anchor: Path | None = None
611
726
  return False
612
727
 
613
728
 
729
+ def _resolve_status_project_root(scope: InstallScope, anchor: Path | None) -> Path | None:
730
+ """Resolve a status lookup root, including tracked installs without ``.claude``."""
731
+
732
+ try:
733
+ return _resolve_project_root(scope, anchor=anchor)
734
+ except NoClaudeDirectoryError:
735
+ try:
736
+ detected_scope, detected_root = find_forge_installation(start=anchor)
737
+ except NoForgeInstallationError:
738
+ return None
739
+ return detected_root if detected_scope == scope else None
740
+
741
+
614
742
  # --- Commands ---
615
743
 
616
744
 
@@ -676,6 +804,13 @@ def extensions() -> None:
676
804
  "without_modules",
677
805
  help="Remove modules (comma-separated)",
678
806
  )
807
+ @click.option(
808
+ "--runtime",
809
+ "runtimes",
810
+ type=click.Choice(["claude", "codex", "all"]),
811
+ multiple=True,
812
+ help="Skill runtime target; repeat for multiple targets (default: Claude plus detected Codex)",
813
+ )
679
814
  @click.option("--force", "-f", is_flag=True, help="Override conflicts")
680
815
  @click.option("--dry-run", "-n", is_flag=True, help="Show plan without executing")
681
816
  def enable_cmd(
@@ -685,6 +820,7 @@ def enable_cmd(
685
820
  mode: str,
686
821
  with_modules: str | None,
687
822
  without_modules: str | None,
823
+ runtimes: tuple[str, ...],
688
824
  force: bool,
689
825
  dry_run: bool,
690
826
  ) -> None:
@@ -706,18 +842,11 @@ def enable_cmd(
706
842
  forge extension enable --root /repo/api # Same (defaults to local)
707
843
  forge extension enable --scope user # Global ~/.claude
708
844
  forge extension enable --profile minimal # Commands only
845
+ forge extension enable --runtime codex # Target skill packages at Codex
846
+ forge extension enable --runtime claude --runtime codex
709
847
  forge extension enable --dry-run # Preview changes
710
848
  """
711
849
  try:
712
- # Check Claude Code minimum version (hard-block: reject over warn)
713
- from forge.install.version import check_minimum_version
714
-
715
- version_check = check_minimum_version()
716
- if not version_check.ok:
717
- print_error(f"{version_check.reason}")
718
- print_tip("Run 'claude update' to upgrade.", console=console)
719
- sys.exit(1)
720
-
721
850
  anchor = Path(path) if path else None
722
851
 
723
852
  # Validate: --scope user + --root is contradictory
@@ -762,13 +891,6 @@ def enable_cmd(
762
891
 
763
892
  _enforce_project_compatibility(project_root)
764
893
 
765
- # Create .claude/ only when not dry-run
766
- if needs_create and project_root is not None:
767
- if dry_run:
768
- console.print(f"[dim]Would create {display_path(project_root / '.claude')}[/dim]")
769
- else:
770
- _create_claude_dir(project_root)
771
-
772
894
  # Rule 1 anchor: .forge/ is required for session start.
773
895
  # Preview in dry-run; actual creation deferred until installer succeeds.
774
896
  needs_forge = project_root is not None and not (project_root / ".forge").is_dir()
@@ -777,29 +899,41 @@ def enable_cmd(
777
899
 
778
900
  install_profile = InstallProfile(profile)
779
901
  install_mode = InstallMode(mode)
902
+ selected_runtimes = _parse_skill_runtimes(runtimes)
780
903
 
781
904
  installer = Installer(scope=install_scope, project_root=project_root)
905
+ plan = installer.plan(
906
+ profile=install_profile,
907
+ mode=install_mode,
908
+ with_modules=_parse_modules(with_modules),
909
+ without_modules=_parse_modules(without_modules),
910
+ force=force,
911
+ skill_runtimes=selected_runtimes,
912
+ )
782
913
 
783
914
  if dry_run:
784
- plan = installer.plan(
785
- profile=install_profile,
786
- mode=install_mode,
787
- with_modules=_parse_modules(with_modules),
788
- without_modules=_parse_modules(without_modules),
789
- force=force,
790
- )
915
+ if needs_create and project_root is not None and plan.requires_claude_version:
916
+ console.print(f"[dim]Would create {display_path(project_root / '.claude')}[/dim]")
791
917
  _print_plan(plan, dry_run=True)
792
918
  if plan.has_conflicts:
793
919
  sys.exit(1)
794
920
  if install_scope == InstallScope.USER:
795
921
  _print_hook_migration_candidates()
796
922
  else:
923
+ if plan.has_conflicts:
924
+ _print_plan(plan)
925
+ console.print("\n[red]Enable failed due to conflicts.[/red]")
926
+ sys.exit(1)
927
+ _enforce_claude_version_if_required(plan, project_root)
928
+ if needs_create and project_root is not None and plan.requires_claude_version:
929
+ _create_claude_dir(project_root)
797
930
  plan = installer.init(
798
931
  profile=install_profile,
799
932
  mode=install_mode,
800
933
  with_modules=_parse_modules(with_modules),
801
934
  without_modules=_parse_modules(without_modules),
802
935
  force=force,
936
+ skill_runtimes=selected_runtimes,
803
937
  )
804
938
  _print_plan(plan)
805
939
  if plan.has_conflicts:
@@ -856,8 +990,9 @@ def sync_cmd(scope: str | None, force: bool) -> None:
856
990
 
857
991
  \b
858
992
  Scope Detection (when no --scope specified):
859
- Walks up from current directory looking for existing Forge extensions
860
- (detected by .settings.*.json.forge.* files in .claude/).
993
+ Walks up from current directory looking for existing Forge extensions,
994
+ using .claude/ ownership sidecars and exact scope/path tracking rows in
995
+ ~/.forge/installed.json.
861
996
  - Checks LOCAL first, then PROJECT, then USER
862
997
  - Fails if no extensions found
863
998
 
@@ -868,26 +1003,28 @@ def sync_cmd(scope: str | None, force: bool) -> None:
868
1003
  forge extension sync --force # Force re-sync
869
1004
  """
870
1005
  try:
871
- # Check Claude Code minimum version (same gate as enable)
872
- from forge.install.version import check_minimum_version
873
-
874
- version_check = check_minimum_version()
875
- if not version_check.ok:
876
- print_error(f"{version_check.reason}")
877
- print_tip("Run 'claude update' to upgrade.", console=console)
878
- sys.exit(1)
879
-
880
1006
  if scope is None:
881
1007
  install_scope, project_root = find_forge_installation()
882
1008
  console.print(f"[dim]Auto-detected scope: {install_scope.value}[/dim]")
883
1009
  else:
884
1010
  install_scope = InstallScope(scope)
885
- # Use canonical project root (finds .claude/ and resolves symlinks)
886
- project_root = _resolve_project_root(install_scope)
1011
+ try:
1012
+ project_root = _resolve_project_root(install_scope)
1013
+ except NoClaudeDirectoryError:
1014
+ detected_scope, detected_root = find_forge_installation()
1015
+ if detected_scope != install_scope:
1016
+ raise NotInstalledError(install_scope.value) from None
1017
+ project_root = detected_root
887
1018
 
888
1019
  _enforce_project_compatibility(project_root)
889
1020
 
890
1021
  installer = Installer(scope=install_scope, project_root=project_root)
1022
+ preview = installer.plan_update(force=force)
1023
+ if preview.has_conflicts:
1024
+ _print_plan(preview)
1025
+ console.print("\n[red]Sync failed due to conflicts.[/red]")
1026
+ sys.exit(1)
1027
+ _enforce_claude_version_if_required(preview, project_root)
891
1028
  plan = installer.update(force=force)
892
1029
 
893
1030
  _print_plan(plan)
@@ -1028,8 +1165,9 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool) -> None:
1028
1165
 
1029
1166
  \b
1030
1167
  Scope Detection (when no --scope/--all specified):
1031
- Walks up from current directory looking for existing Forge extensions
1032
- (detected by .settings.*.json.forge.* files in .claude/).
1168
+ Walks up from current directory looking for existing Forge extensions,
1169
+ using .claude/ ownership sidecars and exact scope/path tracking rows in
1170
+ ~/.forge/installed.json.
1033
1171
  - Checks LOCAL first, then PROJECT, then USER
1034
1172
  - Fails if no extensions found
1035
1173
 
@@ -1058,8 +1196,13 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool) -> None:
1058
1196
  console.print(f"[dim]Auto-detected scope: {install_scope.value}[/dim]")
1059
1197
  else:
1060
1198
  install_scope = InstallScope(scope)
1061
- # Use canonical project root (finds .claude/ and resolves symlinks)
1062
- project_root = _resolve_project_root(install_scope)
1199
+ try:
1200
+ project_root = _resolve_project_root(install_scope)
1201
+ except NoClaudeDirectoryError:
1202
+ detected_scope, detected_root = find_forge_installation()
1203
+ if detected_scope != install_scope:
1204
+ raise NoForgeInstallationError(str(Path.cwd())) from None
1205
+ project_root = detected_root
1063
1206
 
1064
1207
  _enforce_project_compatibility(project_root)
1065
1208
 
@@ -1075,6 +1218,23 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool) -> None:
1075
1218
  console.print(f" Mode: {existing.mode}")
1076
1219
  console.print()
1077
1220
 
1221
+ if existing.skill_packages:
1222
+ table = Table(show_header=True, header_style="bold", box=None, padding=(0, 1))
1223
+ table.add_column("ACTION", style="red")
1224
+ table.add_column("RUNTIME")
1225
+ table.add_column("SKILL")
1226
+ table.add_column("TARGET")
1227
+ for package in existing.skill_packages:
1228
+ table.add_row(
1229
+ "remove",
1230
+ package.runtime,
1231
+ package.skill,
1232
+ display_path(package.target_dir),
1233
+ )
1234
+ console.print("[bold]Skill packages:[/bold]")
1235
+ console.print(table)
1236
+ console.print()
1237
+
1078
1238
  if existing.files:
1079
1239
  table = Table(show_header=True, header_style="bold", box=None, padding=(0, 1))
1080
1240
  table.add_column("ACTION", style="red")
@@ -1159,8 +1319,9 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
1159
1319
 
1160
1320
  \b
1161
1321
  Scope Detection (when no --scope/--all specified):
1162
- Walks up from current directory looking for existing Forge installations
1163
- (detected by .settings.*.json.forge.* files in .claude/).
1322
+ Walks up from current directory looking for existing Forge installations,
1323
+ using .claude/ ownership sidecars and exact scope/path tracking rows in
1324
+ ~/.forge/installed.json.
1164
1325
  - Checks LOCAL first, then PROJECT, then USER
1165
1326
  - If no installation found, shows all scopes for informational purposes
1166
1327
 
@@ -1185,7 +1346,11 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
1185
1346
  # A corrupt installed.json raises TrackingCorruptedError (a StateCorruptedError);
1186
1347
  # it propagates to the top-level handler for the uniform reset tip.
1187
1348
  tracking = TrackingStore()
1188
- tracking.read()
1349
+ tracked_installations = tracking.list_installations()
1350
+ installations_by_target = {
1351
+ (tracked_scope, project_path): installation
1352
+ for tracked_scope, project_path, installation in tracked_installations
1353
+ }
1189
1354
 
1190
1355
  cwd = os.getcwd()
1191
1356
 
@@ -1222,15 +1387,18 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
1222
1387
 
1223
1388
  data = []
1224
1389
  for s in scopes:
1225
- try:
1226
- project_root = _resolve_project_root(s, anchor=effective_anchor)
1227
- project_path_str = str(project_root) if project_root else None
1228
- except NoClaudeDirectoryError:
1229
- project_path_str = None
1390
+ project_root = _resolve_status_project_root(s, effective_anchor)
1391
+ project_path_str = str(project_root) if project_root else None
1230
1392
 
1231
- inst = tracking.get_installation(s.value, project_path_str)
1393
+ inst = installations_by_target.get((s.value, project_path_str))
1232
1394
  if inst is None:
1233
1395
  continue
1396
+ package_statuses = inspect_skill_package_status(
1397
+ inst,
1398
+ s,
1399
+ project_root,
1400
+ tracked_installations=tracked_installations,
1401
+ )
1234
1402
  data.append(
1235
1403
  {
1236
1404
  "scope": s.value,
@@ -1238,6 +1406,20 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
1238
1406
  "mode": inst.mode,
1239
1407
  "modules": list(inst.modules_enabled),
1240
1408
  "files_count": len(inst.files),
1409
+ "skill_packages": [
1410
+ {
1411
+ "runtime": package_status.runtime,
1412
+ "skill": package_status.skill,
1413
+ "target_dir": package_status.target_dir,
1414
+ "file_paths": list(package_status.file_paths),
1415
+ "state": package_status.state,
1416
+ "target_present": package_status.target_present,
1417
+ "missing_file_paths": list(package_status.missing_file_paths),
1418
+ "duplicate_dirs": list(package_status.duplicate_dirs),
1419
+ "recovery": package_status.recovery,
1420
+ }
1421
+ for package_status in package_statuses
1422
+ ],
1241
1423
  "settings_count": len(inst.settings_entries),
1242
1424
  "codex_config_path": inst.codex_config_path,
1243
1425
  "codex_commands": list(inst.codex_commands),
@@ -1256,13 +1438,10 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
1256
1438
  console.print("[dim]Showing all scopes for this location:[/dim]")
1257
1439
 
1258
1440
  for s in scopes:
1259
- try:
1260
- project_root = _resolve_project_root(s, anchor=effective_anchor)
1261
- project_path_str = str(project_root) if project_root else None
1262
- except NoClaudeDirectoryError:
1263
- project_path_str = None
1441
+ project_root = _resolve_status_project_root(s, effective_anchor)
1442
+ project_path_str = str(project_root) if project_root else None
1264
1443
 
1265
- installation = tracking.get_installation(s.value, project_path_str)
1444
+ installation = installations_by_target.get((s.value, project_path_str))
1266
1445
 
1267
1446
  console.print(f"\n[bold]Scope: {s.value}[/bold]")
1268
1447
 
@@ -1280,12 +1459,58 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
1280
1459
  console.print(f" Mode: {installation.mode}")
1281
1460
  console.print(f" Modules: {', '.join(installation.modules_enabled)}")
1282
1461
  console.print(f" Files: {len(installation.files)}")
1462
+ console.print(f" Skills: {len(installation.skill_packages)} runtime package(s)")
1283
1463
  console.print(f" Settings: {len(installation.settings_entries)} entries")
1284
1464
  if installation.codex_config_path:
1285
1465
  console.print(f" Codex: hooks registered in {display_path(installation.codex_config_path)}")
1286
1466
  console.print(f" Installed: {installation.installed_at}")
1287
1467
  console.print(f" Updated: {installation.updated_at}")
1288
1468
 
1469
+ if installation.skill_packages:
1470
+ package_statuses = inspect_skill_package_status(
1471
+ installation,
1472
+ s,
1473
+ project_root,
1474
+ tracked_installations=tracked_installations,
1475
+ )
1476
+ table = Table(show_header=True, header_style="bold", box=None, padding=(0, 1))
1477
+ table.add_column("STATE")
1478
+ table.add_column("RUNTIME")
1479
+ table.add_column("SKILL")
1480
+ table.add_column("TARGET")
1481
+ for package_status in package_statuses:
1482
+ style = {
1483
+ "present": "green",
1484
+ "missing": "yellow",
1485
+ "duplicate": "red",
1486
+ "invalid-target": "red",
1487
+ }.get(package_status.state, "")
1488
+ table.add_row(
1489
+ package_status.state,
1490
+ package_status.runtime,
1491
+ package_status.skill,
1492
+ display_path(package_status.target_dir),
1493
+ style=style,
1494
+ )
1495
+ console.print("\n [dim]Skill packages:[/dim]")
1496
+ console.print(table)
1497
+ for package_status in package_statuses:
1498
+ if package_status.duplicate_dirs:
1499
+ console.print(
1500
+ f" [red]{package_status.runtime}/{package_status.skill} duplicates:[/red] "
1501
+ + ", ".join(display_path(path) for path in package_status.duplicate_dirs)
1502
+ )
1503
+ if package_status.missing_file_paths:
1504
+ console.print(
1505
+ f" [yellow]{package_status.runtime}/{package_status.skill} missing files:[/yellow] "
1506
+ + ", ".join(display_path(path) for path in package_status.missing_file_paths)
1507
+ )
1508
+ if package_status.recovery:
1509
+ console.print(
1510
+ f" [yellow]{package_status.runtime}/{package_status.skill}:[/yellow] "
1511
+ f"{package_status.recovery}"
1512
+ )
1513
+
1289
1514
  try:
1290
1515
  inst_profile = InstallProfile(installation.profile)
1291
1516
  gated = get_gated_skills(inst_profile)
@@ -1016,7 +1016,7 @@ def worktree_create() -> None:
1016
1016
  # Fallback: try without -b (use detached HEAD)
1017
1017
  logger.debug("worktree-create: branched creation failed: %s", result.stderr.strip())
1018
1018
  result = subprocess.run(
1019
- [git, "worktree", "add", str(worktree_path)],
1019
+ [git, "worktree", "add", "--detach", str(worktree_path)],
1020
1020
  cwd=str(repo_root),
1021
1021
  capture_output=True,
1022
1022
  text=True,
@@ -770,8 +770,8 @@ def _handle_policy_supervisor(argv: list[str]) -> None:
770
770
  - ``%policy supervisor``: show current config (including the bound consumer lane)
771
771
 
772
772
  The consumer-lane *runtime* is intentionally not settable here -- it is a resolving-command
773
- flag (``forge policy supervisor set --runtime``) so the binding stays write-once. This path
774
- only shows the bound lane.
773
+ flag (``forge policy supervisor set <target> --runtime``) so the binding stays write-once.
774
+ This path only shows the bound lane.
775
775
  """
776
776
  cwd = Path.cwd().resolve()
777
777
  store = resolve_session_store(cwd)
@@ -172,8 +172,8 @@ def register_supervisor_and_restore(engine: Any, effective: Any, manifest: Any)
172
172
 
173
173
  Returns the supervisor's injected consumer-lane binding (None when no supervisor is
174
174
  configured, or when it resolves to the default lane). The caller threads this same
175
- value into the post-eval freeze so the binding records the lane that actually
176
- dispatched -- not a fresh manifest read that could race a concurrent intent change.
175
+ value into the post-eval freeze so the binding records the lane committed for this
176
+ registered check -- not a fresh manifest read that could race an intent change.
177
177
  """
178
178
  sup = effective.policy.supervisor if effective.policy else None
179
179
  has_supervisor = bool(sup and sup.resume_id and not sup.suspended)