multi-forge 0.2.0__tar.gz → 0.3.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 (322) hide show
  1. {multi_forge-0.2.0 → multi_forge-0.3.0}/PKG-INFO +18 -12
  2. {multi_forge-0.2.0 → multi_forge-0.3.0}/README.md +14 -8
  3. {multi_forge-0.2.0 → multi_forge-0.3.0}/pyproject.toml +14 -11
  4. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/__init__.py +1 -1
  5. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/backend.py +22 -10
  6. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/claude.py +9 -8
  7. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/config_cmd.py +4 -4
  8. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/extensions.py +25 -19
  9. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/gc.py +2 -1
  10. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/guards.py +4 -3
  11. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/handoff.py +13 -8
  12. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/commands.py +14 -11
  13. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/direct_commands.py +45 -44
  14. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/policy.py +2 -2
  15. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/logs.py +35 -13
  16. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/main.py +8 -2
  17. multi_forge-0.3.0/src/forge/cli/memory.py +1227 -0
  18. multi_forge-0.3.0/src/forge/cli/output.py +92 -0
  19. multi_forge-0.2.0/src/forge/cli/guard.py → multi_forge-0.3.0/src/forge/cli/policy.py +125 -139
  20. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/proxy.py +120 -61
  21. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/search.py +41 -15
  22. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session.py +16 -24
  23. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_fork.py +123 -25
  24. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_handoff.py +9 -9
  25. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_lifecycle.py +415 -81
  26. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_manage.py +94 -30
  27. multi_forge-0.3.0/src/forge/cli/session_memory.py +36 -0
  28. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/workflow.py +13 -9
  29. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/loader.py +1 -1
  30. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/schema.py +2 -2
  31. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/__init__.py +2 -2
  32. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/capabilities.py +4 -4
  33. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/template_secrets.py +8 -8
  34. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/model_catalog.yaml +2 -0
  35. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/__init__.py +1 -1
  36. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/litellm.py +1 -1
  37. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/openrouter.py +1 -1
  38. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/resolution.py +1 -1
  39. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/session_runner.py +9 -0
  40. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/tagger.py +1 -1
  41. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/throttle.py +1 -1
  42. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/__init__.py +2 -2
  43. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/__init__.py +3 -3
  44. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/base.py +1 -1
  45. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/coding_standards.py +2 -2
  46. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/registry.py +5 -5
  47. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/tdd.py +2 -2
  48. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/engine.py +3 -3
  49. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/protocols.py +1 -1
  50. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/queries.py +2 -2
  51. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/__init__.py +2 -2
  52. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/promotion.py +2 -2
  53. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/supervisor.py +49 -24
  54. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/verdict.py +1 -1
  55. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/store.py +1 -1
  56. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/handlers.py +2 -2
  57. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/branches.py +3 -3
  58. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/divergence.py +1 -1
  59. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/policy.py +4 -4
  60. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/stages.py +2 -2
  61. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxy_orchestrator.py +92 -4
  62. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/server.py +13 -7
  63. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/utils.py +3 -2
  64. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/engine.py +4 -2
  65. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/effective.py +7 -3
  66. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/exceptions.py +13 -0
  67. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/handoff_agent.py +120 -111
  68. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/manager.py +36 -0
  69. multi_forge-0.3.0/src/forge/session/memory_inheritance.py +78 -0
  70. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/models.py +7 -15
  71. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/overrides.py +1 -1
  72. multi_forge-0.3.0/src/forge/session/passport.py +758 -0
  73. multi_forge-0.3.0/src/forge/session/project_memory.py +317 -0
  74. multi_forge-0.3.0/src/forge/session/shadow_curation.py +320 -0
  75. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/store.py +32 -0
  76. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/validation.py +21 -1
  77. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/secrets.py +2 -2
  78. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/SKILL.md +2 -2
  79. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/12-search.md +3 -3
  80. multi_forge-0.2.0/src/skills/qa/resources/checklist/13-guard.md → multi_forge-0.3.0/src/skills/qa/resources/checklist/13-policy.md +31 -31
  81. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/16-handoff.md +35 -47
  82. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/9-direct-commands.md +21 -21
  83. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist.md +10 -10
  84. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/report-template.md +1 -1
  85. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/scripts/walkthrough-state.py +88 -35
  86. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/skills-writing-guide.md +1 -1
  87. multi_forge-0.3.0/src/skills/review/resources/code.md +1 -0
  88. multi_forge-0.3.0/src/skills/review-docs/resources/docs.md +1 -0
  89. multi_forge-0.3.0/src/skills/understand/resources/code.md +163 -0
  90. multi_forge-0.3.0/src/skills/understand/resources/docs.md +177 -0
  91. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/SKILL.md +2 -2
  92. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/resources/checklist.md +25 -22
  93. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/scripts/walkthrough-state.py +88 -35
  94. multi_forge-0.2.0/src/forge/cli/session_memory.py +0 -201
  95. multi_forge-0.2.0/src/skills/review/resources/code-anthropic.md +0 -1
  96. multi_forge-0.2.0/src/skills/review-docs/resources/docs-anthropic.md +0 -1
  97. multi_forge-0.2.0/src/skills/understand/resources/code-anthropic.md +0 -1
  98. multi_forge-0.2.0/src/skills/understand/resources/docs-anthropic.md +0 -1
  99. {multi_forge-0.2.0 → multi_forge-0.3.0}/.gitignore +0 -0
  100. {multi_forge-0.2.0 → multi_forge-0.3.0}/LICENSE +0 -0
  101. {multi_forge-0.2.0 → multi_forge-0.3.0}/NOTICE +0 -0
  102. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/agents/.gitkeep +0 -0
  103. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/commands/.gitkeep +0 -0
  104. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/__init__.py +0 -0
  105. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/adapters/__init__.py +0 -0
  106. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/adapters/litellm.py +0 -0
  107. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/creation.py +0 -0
  108. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/registry.py +0 -0
  109. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/__init__.py +0 -0
  110. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/auth.py +0 -0
  111. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/__init__.py +0 -0
  112. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/_group.py +0 -0
  113. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/_helpers.py +0 -0
  114. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/install.py +0 -0
  115. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
  116. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/verification.py +0 -0
  117. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/proxy_costs.py +0 -0
  118. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_addendum.py +0 -0
  119. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/status_line.py +0 -0
  120. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/__init__.py +0 -0
  121. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/dataclass_utils.py +0 -0
  122. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/__init__.py +0 -0
  123. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/backends/__init__.py +0 -0
  124. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/backends/litellm.yaml +0 -0
  125. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/__init__.py +0 -0
  126. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +0 -0
  127. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +0 -0
  128. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +0 -0
  129. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +0 -0
  130. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +0 -0
  131. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +0 -0
  132. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +0 -0
  133. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +0 -0
  134. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-openai.yaml +0 -0
  135. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-anthropic.yaml +0 -0
  136. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +0 -0
  137. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +0 -0
  138. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +0 -0
  139. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +0 -0
  140. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +0 -0
  141. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +0 -0
  142. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +0 -0
  143. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +0 -0
  144. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +0 -0
  145. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/__init__.py +0 -0
  146. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/credentials_file.py +0 -0
  147. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/protocols.py +0 -0
  148. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/secrets.py +0 -0
  149. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/__init__.py +0 -0
  150. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/pricing.yaml +0 -0
  151. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
  152. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
  153. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
  154. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/__init__.py +0 -0
  155. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/base.py +0 -0
  156. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/openai_compat.py +0 -0
  157. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/credentials.py +0 -0
  158. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/detection.py +0 -0
  159. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/errors.py +0 -0
  160. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/protocols.py +0 -0
  161. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/types.py +0 -0
  162. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/logging.py +0 -0
  163. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/__init__.py +0 -0
  164. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/catalog.py +0 -0
  165. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/pricing.py +0 -0
  166. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/types.py +0 -0
  167. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/naming.py +0 -0
  168. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/__init__.py +0 -0
  169. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/context.py +0 -0
  170. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/gc.py +0 -0
  171. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/proxy.py +0 -0
  172. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/session.py +0 -0
  173. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/session_context.py +0 -0
  174. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/paths.py +0 -0
  175. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/process.py +0 -0
  176. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/__init__.py +0 -0
  177. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/cost_tracking.py +0 -0
  178. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/env.py +0 -0
  179. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/proxy.py +0 -0
  180. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/routing.py +0 -0
  181. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/structured_output.py +0 -0
  182. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/__init__.py +0 -0
  183. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/exceptions.py +0 -0
  184. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/io.py +0 -0
  185. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/lock.py +0 -0
  186. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/timestamps.py +0 -0
  187. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/transcript.py +0 -0
  188. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/typing_helpers.py +0 -0
  189. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/workqueue/__init__.py +0 -0
  190. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/workqueue/queue.py +0 -0
  191. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/workqueue/types.py +0 -0
  192. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/__init__.py +0 -0
  193. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/cli.py +0 -0
  194. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/exceptions.py +0 -0
  195. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/hooks.py +0 -0
  196. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/installer.py +0 -0
  197. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/models.py +0 -0
  198. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/preset.py +0 -0
  199. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/settings_merge.py +0 -0
  200. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/tracking.py +0 -0
  201. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/version.py +0 -0
  202. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/__init__.py +0 -0
  203. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/config.py +0 -0
  204. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/prompts.py +0 -0
  205. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/types.py +0 -0
  206. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/__init__.py +0 -0
  207. {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/config.py +0 -0
  208. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/__init__.py +0 -0
  209. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/base_client.py +0 -0
  210. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/client_adapter.py +0 -0
  211. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/client_factory.py +0 -0
  212. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/converters.py +0 -0
  213. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/cost_logger.py +0 -0
  214. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/cost_tracker.py +0 -0
  215. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/data_models.py +0 -0
  216. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/error_hints.py +0 -0
  217. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/metrics.py +0 -0
  218. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/model_spec.py +0 -0
  219. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxies.py +0 -0
  220. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxy_identity.py +0 -0
  221. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxy_startup.py +0 -0
  222. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/__init__.py +0 -0
  223. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/adversarial.py +0 -0
  224. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/consensus.py +0 -0
  225. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/models.py +0 -0
  226. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/__init__.py +0 -0
  227. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview-performance.md +0 -0
  228. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview-quick.md +0 -0
  229. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview-security.md +0 -0
  230. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview.md +0 -0
  231. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/docreview-quick.md +0 -0
  232. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/docreview.md +0 -0
  233. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/thinkdeep.md +0 -0
  234. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/routing.py +0 -0
  235. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/synthesis.py +0 -0
  236. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/runtime_config.py +0 -0
  237. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/__init__.py +0 -0
  238. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/bm25_store.py +0 -0
  239. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/content_store.py +0 -0
  240. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/engine.py +0 -0
  241. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/exceptions.py +0 -0
  242. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/extractor.py +0 -0
  243. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/index_state.py +0 -0
  244. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/store.py +0 -0
  245. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/tokenizer.py +0 -0
  246. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/__init__.py +0 -0
  247. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/active.py +0 -0
  248. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/artifacts.py +0 -0
  249. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/__init__.py +0 -0
  250. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/cleanup.py +0 -0
  251. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/invoke.py +0 -0
  252. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/paths.py +0 -0
  253. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/cleanup.py +0 -0
  254. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/config.py +0 -0
  255. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/direct_model.py +0 -0
  256. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/handoff.py +0 -0
  257. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/hooks/__init__.py +0 -0
  258. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/hooks/models.py +0 -0
  259. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/hooks/session_start.py +0 -0
  260. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/identity.py +0 -0
  261. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/index.py +0 -0
  262. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/plan_resolution.py +0 -0
  263. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/prev_sessions.py +0 -0
  264. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/__init__.py +0 -0
  265. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/cleanup.py +0 -0
  266. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/config_copy.py +0 -0
  267. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/create.py +0 -0
  268. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/__init__.py +0 -0
  269. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/container.py +0 -0
  270. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/docker.py +0 -0
  271. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/analyze/SKILL.md +0 -0
  272. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/challenge/SKILL.md +0 -0
  273. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/SKILL.md +0 -0
  274. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/resources/code_consensus_evaluation.md +0 -0
  275. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/resources/consensus_evaluation.md +0 -0
  276. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/resources/synthesis.md +0 -0
  277. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/debate/SKILL.md +0 -0
  278. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/debate/resources/code_debate_evaluation.md +0 -0
  279. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/debate/resources/debate_evaluation.md +0 -0
  280. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/panel/SKILL.md +0 -0
  281. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/panel/resources/synthesis.md +0 -0
  282. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/0-enable.md +0 -0
  283. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
  284. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/10-resume.md +0 -0
  285. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/11-config.md +0 -0
  286. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
  287. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/15-skills.md +0 -0
  288. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/17-info.md +0 -0
  289. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/18-disable.md +0 -0
  290. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/19-uninstall.md +0 -0
  291. /multi_forge-0.2.0/src/skills/qa/resources/checklist/2-extensions.md → /multi_forge-0.3.0/src/skills/qa/resources/checklist/2-extension.md +0 -0
  292. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/20-cleanup.md +0 -0
  293. /multi_forge-0.2.0/src/skills/qa/resources/checklist/3-auth.md → /multi_forge-0.3.0/src/skills/qa/resources/checklist/3-authentication.md +0 -0
  294. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/4-proxy.md +0 -0
  295. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/5-session.md +0 -0
  296. /multi_forge-0.2.0/src/skills/qa/resources/checklist/6-hooks.md → /multi_forge-0.3.0/src/skills/qa/resources/checklist/6-hook.md +0 -0
  297. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/7-costs.md +0 -0
  298. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/8-status-line.md +0 -0
  299. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/scripts/start-container.sh +0 -0
  300. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/SKILL.md +0 -0
  301. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/claude-4.6.md +0 -0
  302. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/claude-4.7.md +0 -0
  303. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/gemini-3.1.md +0 -0
  304. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/gpt-5.5.md +0 -0
  305. /multi_forge-0.2.0/src/skills/review/resources/code.md → /multi_forge-0.3.0/src/skills/review/resources/code-anthropic.md +0 -0
  306. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/resources/code-gemini.md +0 -0
  307. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/resources/code-openai.md +0 -0
  308. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review-docs/SKILL.md +0 -0
  309. /multi_forge-0.2.0/src/skills/review-docs/resources/docs.md → /multi_forge-0.3.0/src/skills/review-docs/resources/docs-anthropic.md +0 -0
  310. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review-docs/resources/docs-gemini.md +0 -0
  311. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review-docs/resources/docs-openai.md +0 -0
  312. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/smoke-test/SKILL.md +0 -0
  313. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/smoke-test/scripts/smoke-test.sh +0 -0
  314. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/SKILL.md +0 -0
  315. /multi_forge-0.2.0/src/skills/understand/resources/code.md → /multi_forge-0.3.0/src/skills/understand/resources/code-anthropic.md +0 -0
  316. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/code-gemini.md +0 -0
  317. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/code-openai.md +0 -0
  318. /multi_forge-0.2.0/src/skills/understand/resources/docs.md → /multi_forge-0.3.0/src/skills/understand/resources/docs-anthropic.md +0 -0
  319. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/docs-gemini.md +0 -0
  320. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/docs-openai.md +0 -0
  321. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
  322. {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/scripts/setup-test-repo.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multi-forge
3
- Version: 0.2.0
3
+ Version: 0.3.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
@@ -24,15 +24,15 @@ Requires-Python: <3.14,>=3.11
24
24
  Requires-Dist: click>=8.3.1
25
25
  Requires-Dist: coolname<6,>=5.0.0
26
26
  Requires-Dist: dacite>=1.8.0
27
- Requires-Dist: fastapi>=0.115.11
27
+ Requires-Dist: fastapi>=0.115.14
28
28
  Requires-Dist: httpx>=0.25.0
29
- Requires-Dist: litellm[proxy]>=1.84.0
29
+ Requires-Dist: litellm[proxy]>=1.85.0
30
30
  Requires-Dist: openai>=1.0.0
31
31
  Requires-Dist: packaging>=21.0
32
32
  Requires-Dist: pydantic>=2.0.0
33
33
  Requires-Dist: python-dotenv>=1.2.2
34
34
  Requires-Dist: pyyaml>=6.0.0
35
- Requires-Dist: rich>=13.0.0
35
+ Requires-Dist: rich>=13.9.0
36
36
  Requires-Dist: ruamel-yaml>=0.18.0
37
37
  Requires-Dist: tenacity>=8.0.0
38
38
  Requires-Dist: uvicorn>=0.31.1
@@ -41,8 +41,13 @@ Description-Content-Type: text/markdown
41
41
 
42
42
  # Multi-Forge
43
43
 
44
- [![License](https://img.shields.io/github/license/hapa1i/multi-forge)](LICENSE)
45
- [![Python](https://img.shields.io/badge/python-3.11--3.13-blue)](https://github.com/hapa1i/multi-forge)
44
+ <p align="left">
45
+ <img src="assets/logo.jpg" alt="Dusk" width=320">
46
+ </p>
47
+
48
+ [![PyPI](https://img.shields.io/pypi/v/multi-forge)](https://pypi.org/project/multi-forge/)
49
+ [![Python](https://img.shields.io/pypi/pyversions/multi-forge)](https://pypi.org/project/multi-forge/)
50
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
46
51
 
47
52
  > [!WARNING]
48
53
  > **Research Preview** -- Forge is under active development. APIs, commands, and file formats may change without notice
@@ -206,7 +211,7 @@ inside Claude Code for an interactive walkthrough.
206
211
  | `forge session` | Named sessions, worktrees, resume, fork |
207
212
  | `forge proxy` | Model routing, templates, tier mappings |
208
213
  | `forge authentication` | Credential management (`credentials.yaml`) |
209
- | `forge guard` | Policy enforcement, plan supervision |
214
+ | `forge policy` | Policy enforcement, plan supervision |
210
215
  | `forge workflow` | Workflow runners (panel, analyze, debate) |
211
216
  | `forge search` | Transcript search across sessions |
212
217
  | `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
@@ -217,11 +222,12 @@ Run `forge <command> --help` for details on any command.
217
222
 
218
223
  ## Documentation
219
224
 
220
- | Audience | Location | Contents |
221
- | ---------------- | ---------------------------------- | ------------------------------------------------- |
222
- | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
223
- | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
224
- | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
225
+ | Audience | Location | Contents |
226
+ | ---------------- | ---------------------------------- | ---------------------------------------------------- |
227
+ | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
228
+ | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
229
+ | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
230
+ | **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
225
231
 
226
232
  ## Contributing
227
233
 
@@ -1,7 +1,12 @@
1
1
  # Multi-Forge
2
2
 
3
- [![License](https://img.shields.io/github/license/hapa1i/multi-forge)](LICENSE)
4
- [![Python](https://img.shields.io/badge/python-3.11--3.13-blue)](https://github.com/hapa1i/multi-forge)
3
+ <p align="left">
4
+ <img src="assets/logo.jpg" alt="Dusk" width=320">
5
+ </p>
6
+
7
+ [![PyPI](https://img.shields.io/pypi/v/multi-forge)](https://pypi.org/project/multi-forge/)
8
+ [![Python](https://img.shields.io/pypi/pyversions/multi-forge)](https://pypi.org/project/multi-forge/)
9
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
5
10
 
6
11
  > [!WARNING]
7
12
  > **Research Preview** -- Forge is under active development. APIs, commands, and file formats may change without notice
@@ -165,7 +170,7 @@ inside Claude Code for an interactive walkthrough.
165
170
  | `forge session` | Named sessions, worktrees, resume, fork |
166
171
  | `forge proxy` | Model routing, templates, tier mappings |
167
172
  | `forge authentication` | Credential management (`credentials.yaml`) |
168
- | `forge guard` | Policy enforcement, plan supervision |
173
+ | `forge policy` | Policy enforcement, plan supervision |
169
174
  | `forge workflow` | Workflow runners (panel, analyze, debate) |
170
175
  | `forge search` | Transcript search across sessions |
171
176
  | `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
@@ -176,11 +181,12 @@ Run `forge <command> --help` for details on any command.
176
181
 
177
182
  ## Documentation
178
183
 
179
- | Audience | Location | Contents |
180
- | ---------------- | ---------------------------------- | ------------------------------------------------- |
181
- | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
182
- | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
183
- | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
184
+ | Audience | Location | Contents |
185
+ | ---------------- | ---------------------------------- | ---------------------------------------------------- |
186
+ | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
187
+ | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
188
+ | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
189
+ | **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
184
190
 
185
191
  ## Contributing
186
192
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "multi-forge"
3
- version = "0.2.0"
3
+ version = "0.3.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"
@@ -28,7 +28,7 @@ dependencies = [
28
28
  "dacite>=1.8.0",
29
29
  "click>=8.3.1",
30
30
  "coolname>=5.0.0,<6",
31
- "rich>=13.0.0",
31
+ "rich>=13.9.0",
32
32
  "pydantic>=2.0.0",
33
33
  "openai>=1.0.0",
34
34
  "httpx>=0.25.0",
@@ -41,10 +41,10 @@ dependencies = [
41
41
  # Plain `fastapi` (no `[standard]` extras): Forge uses none of websockets/
42
42
  # uvloop/httptools/multipart/jinja2. `watchfiles` is declared explicitly
43
43
  # because Forge owns `--reload` (`forge proxy server --reload`).
44
- "fastapi>=0.115.11",
44
+ "fastapi>=0.115.14",
45
45
  "uvicorn>=0.31.1",
46
46
  "watchfiles>=0.20",
47
- "litellm[proxy]>=1.84.0",
47
+ "litellm[proxy]>=1.85.0",
48
48
  ]
49
49
 
50
50
  [project.scripts]
@@ -104,9 +104,11 @@ markers = [
104
104
  asyncio_mode = "auto"
105
105
 
106
106
  [tool.mypy]
107
- # Exclude extension scripts with optional dependencies
107
+ # Same-named standalone scripts in separate skill directories collide in mypy's
108
+ # module map during broad scans. Keep this exclusion local to the duplicate
109
+ # script name; it is not a source-of-truth relationship between the skills.
108
110
  exclude = [
109
- "src/skills/",
111
+ 'src/skills/qa/scripts/walkthrough-state\.py$',
110
112
  ]
111
113
  ignore_missing_imports = true
112
114
 
@@ -137,18 +139,19 @@ dev = [
137
139
  "pytest-cov>=4.1.0",
138
140
  "pytest-asyncio>=0.23.0",
139
141
  "pytest-mock>=3.15.1",
140
- "ruff>=0.8.0",
142
+ "ruff>=0.15.0",
143
+ "black>=26.5.0",
141
144
  "mypy>=1.13.0",
142
145
  "pyright>=1.1.0",
143
146
  "pytest-rerunfailures>=14.0",
144
- "pre-commit>=4.0.0",
147
+ "pre-commit>=4.5.0",
145
148
  "types-PyYAML>=6.0.0",
146
149
  "types-requests>=2.31.0",
147
150
  "python-dotenv>=1.2.1",
148
151
  ]
149
152
  provider-check = [
150
- "anthropic>=0.52.0",
151
- "google-genai>=2.3.0",
152
- "openai>=1.0.0",
153
+ "anthropic>=0.100.0",
154
+ "google-genai>=2.5.0",
155
+ "openai>=2.0.0",
153
156
  "tiktoken>=0.12.0",
154
157
  ]
@@ -1,3 +1,3 @@
1
1
  """Multi-Forge - Multi-runtime agent toolkit."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.3.0"
@@ -21,6 +21,7 @@ from forge.backend import BackendManager
21
21
  from forge.backend.adapters import get_adapter
22
22
  from forge.backend.creation import create_backend_config, get_backend_config_path
23
23
  from forge.backend.registry import BackendRegistryStore, is_pid_alive
24
+ from forge.cli.output import print_error_with_tip, print_tip
24
25
  from forge.core.paths import display_path, get_forge_home
25
26
 
26
27
 
@@ -64,7 +65,7 @@ def list_cmd(as_json: bool) -> None:
64
65
 
65
66
  if not backends:
66
67
  console.print("No backends found.")
67
- console.print("\n[dim]Tip: Run 'forge backend create litellm'.[/dim]")
68
+ print_tip("Run 'forge backend create litellm'.", console=console)
68
69
  return
69
70
 
70
71
  table = Table(title="Forge Backends")
@@ -146,7 +147,7 @@ def show_cmd(backend_id: str, raw: bool) -> None:
146
147
  console.print(syntax)
147
148
  else:
148
149
  console.print(f"\n[dim]No config found for adapter '{adapter_type}'.[/dim]")
149
- console.print(f"[dim]Tip: Run 'forge backend create {adapter_type}'.[/dim]")
150
+ print_tip(f"Run 'forge backend create {adapter_type}'.", blank_before=False, console=console)
150
151
 
151
152
 
152
153
  @backend.command("create")
@@ -166,10 +167,13 @@ def create_cmd(adapter: str, config: Path | None) -> None:
166
167
 
167
168
  config_path = get_backend_config_path(adapter)
168
169
  if config_path.exists():
169
- console.print(f"[yellow]Backend config already exists:[/yellow] {display_path(config_path)}")
170
- console.print("\n[dim]Start an instance with:[/dim]")
171
- console.print(f" forge backend start {adapter} --port 4000")
172
- return
170
+ print_error_with_tip(
171
+ f"Backend config already exists: {display_path(config_path)}",
172
+ "Start an instance with:",
173
+ commands=[f"forge backend start {adapter} --port 4000"],
174
+ console=console,
175
+ )
176
+ sys.exit(1)
173
177
 
174
178
  try:
175
179
  config_path = create_backend_config(
@@ -194,9 +198,12 @@ def start_cmd(adapter: str, port: int) -> None:
194
198
 
195
199
  config_path = get_backend_config_path(adapter)
196
200
  if not config_path.exists():
197
- console.print(f"[red]Error:[/red] Backend config not found for '{adapter}'")
198
- console.print("\n[dim]Create it first:[/dim]")
199
- console.print(f" forge backend create {adapter}")
201
+ print_error_with_tip(
202
+ f"Backend config not found for '{adapter}'",
203
+ "Create it first:",
204
+ commands=[f"forge backend create {adapter}"],
205
+ console=console,
206
+ )
200
207
  sys.exit(1)
201
208
 
202
209
  backend_id = f"{adapter}-{port}"
@@ -271,7 +278,12 @@ def delete_cmd(adapter: str, port: int | None, yes: bool, force: bool) -> None:
271
278
  else:
272
279
  backend_dir = get_forge_home() / "backends" / adapter
273
280
  if not backend_dir.exists():
274
- console.print(f"[red]Error:[/red] Backend config not found for '{adapter}'")
281
+ print_error_with_tip(
282
+ f"Backend config not found for '{adapter}'",
283
+ "Create it first:",
284
+ commands=[f"forge backend create {adapter}"],
285
+ console=console,
286
+ )
275
287
  sys.exit(1)
276
288
 
277
289
  if not yes and not click.confirm(f"Delete backend config for '{adapter}' (stops all instances)?"):
@@ -20,10 +20,9 @@ from rich.console import Console
20
20
 
21
21
  from forge.core.paths import display_path
22
22
  from forge.proxy.proxies import (
23
+ ProxyNotFoundError,
23
24
  ProxyRegistryCorruptedError,
24
- ProxyRegistryStore,
25
25
  ProxyResolutionError,
26
- resolve_proxy,
27
26
  )
28
27
  from forge.session.direct_model import apply_direct_model_env
29
28
 
@@ -208,20 +207,22 @@ def start_cmd(
208
207
  proxy_display: str | None = None
209
208
 
210
209
  if proxy_id:
211
- proxy_store = ProxyRegistryStore()
210
+ from forge.proxy.proxy_orchestrator import ProxyStartError, ensure_proxy
212
211
 
213
212
  try:
214
- registry = proxy_store.read()
213
+ entry, started = ensure_proxy(proxy_id)
215
214
  except ProxyRegistryCorruptedError as e:
216
215
  click.echo(f"Error: {e}")
217
216
  sys.exit(1)
218
-
219
- try:
220
- entry = resolve_proxy(registry, proxy_id)
221
- except ProxyResolutionError as e:
217
+ except (ProxyResolutionError, ProxyStartError) as e:
222
218
  click.echo(f"Error: {e}")
219
+ if isinstance(e, ProxyNotFoundError):
220
+ click.echo("Tip: Run 'forge proxy template list' to see available templates.")
223
221
  sys.exit(1)
224
222
 
223
+ if started:
224
+ console.print(f"[dim]Started proxy '{entry.proxy_id}' from template '{proxy_id}'.[/dim]")
225
+
225
226
  try:
226
227
  _healthcheck_proxy(
227
228
  base_url=entry.base_url,
@@ -35,23 +35,23 @@ from forge.runtime_config import (
35
35
  )
36
36
 
37
37
 
38
- @click.group(invoke_without_command=True)
38
+ @click.group(invoke_without_command=True, subcommand_metavar="[COMMAND] [ARGS]...")
39
39
  @click.pass_context
40
40
  def config(ctx: click.Context) -> None:
41
41
  """Manage Forge global configuration.
42
42
 
43
43
  \b
44
44
  Configuration file: ~/.forge/config.yaml
45
- Auto-created with documented defaults on first access.
45
+ Auto-created with documented defaults by `forge config show`.
46
46
 
47
47
  \b
48
48
  Examples:
49
- forge config # Show effective config
49
+ forge config show # Show effective config
50
50
  forge config set proxy_mode=sidecar
51
51
  forge config edit # Open in $EDITOR
52
52
  """
53
53
  if ctx.invoked_subcommand is None:
54
- ctx.invoke(show_cmd)
54
+ click.echo(ctx.get_help())
55
55
 
56
56
 
57
57
  @config.command("show")
@@ -17,6 +17,7 @@ import click
17
17
  from rich.console import Console
18
18
  from rich.table import Table
19
19
 
20
+ from forge.cli.output import print_tip
20
21
  from forge.core.paths import display_path
21
22
  from forge.install.exceptions import (
22
23
  ForgeInstallError,
@@ -179,11 +180,17 @@ def _print_completion_message(
179
180
  parts.append(f"{settings_actions} setting{'s' if settings_actions != 1 else ''}")
180
181
  console.print(f"\n[green]Extensions enabled.[/green] ({', '.join(parts)} updated)")
181
182
 
182
- console.print("[dim]Tip: Customize permissions and env vars with 'forge claude preset edit'.[/dim]")
183
+ print_tip(
184
+ "Run 'forge claude preset edit' to customize permissions and env vars.",
185
+ blank_before=False,
186
+ console=console,
187
+ )
183
188
 
184
189
  if InstallModule.SKILLS.value in plan.modules:
185
- console.print(
186
- "[dim]Tip: Multi-model skills require proxy credentials. " "Run 'forge auth status' to check.[/dim]"
190
+ print_tip(
191
+ "Multi-model skills require proxy credentials. Run 'forge auth status' to check.",
192
+ blank_before=False,
193
+ console=console,
187
194
  )
188
195
 
189
196
  profile = InstallProfile(plan.profile)
@@ -191,7 +198,7 @@ def _print_completion_message(
191
198
  if gated:
192
199
  skill_list = ", ".join(f"/forge:{name}" for name, _ in gated)
193
200
  required = gated[0][1].value
194
- console.print(f"\n[dim]Tip: Additional skills available with --profile {required}: {skill_list}[/dim]")
201
+ print_tip(f"Additional skills available with --profile {required}: {skill_list}", console=console)
195
202
 
196
203
 
197
204
  def _validate_anchor(anchor: Path) -> None:
@@ -321,7 +328,7 @@ def _print_plan(plan: InstallPlan, dry_run: bool = False) -> None:
321
328
  console.print(f"\n{prefix}[bold red]Conflicts detected:[/bold red]")
322
329
  for c in plan.conflicts:
323
330
  console.print(f" [red]- {c}[/red]")
324
- console.print("\n[dim]Tip: Use --force to override, or resolve conflicts manually.[/dim]")
331
+ print_tip("Use --force to override, or resolve conflicts manually.", console=console)
325
332
 
326
333
 
327
334
  def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
@@ -507,7 +514,7 @@ def enable_cmd(
507
514
  version_check = check_minimum_version()
508
515
  if not version_check.ok:
509
516
  console.print(f"[red]Error:[/red] {version_check.reason}")
510
- console.print("\n[dim]Tip: Run 'claude update' to upgrade.[/dim]")
517
+ print_tip("Run 'claude update' to upgrade.", console=console)
511
518
  sys.exit(1)
512
519
 
513
520
  anchor = Path(path) if path else None
@@ -597,14 +604,13 @@ def enable_cmd(
597
604
  raise
598
605
  except NoClaudeDirectoryError as e:
599
606
  console.print(f"[red]Error:[/red] {e}")
600
- console.print(
601
- "\n[dim]Tip: Use '--scope user' to enable globally, "
602
- "or '--root <dir>' to target a specific directory.[/dim]"
607
+ print_tip(
608
+ "Use --scope user to enable globally, or --root <dir> to target a specific directory.", console=console
603
609
  )
604
610
  sys.exit(1)
605
611
  except SettingsConflictError as e:
606
612
  console.print(f"[red]Settings conflict:[/red] {e}")
607
- console.print("\n[dim]Tip: Use --force to override.[/dim]")
613
+ print_tip("Use --force to override.", console=console)
608
614
  sys.exit(1)
609
615
  except ForgeInstallError as e:
610
616
  console.print(f"[red]Error:[/red] {e}")
@@ -647,7 +653,7 @@ def sync_cmd(scope: str | None, force: bool) -> None:
647
653
  version_check = check_minimum_version()
648
654
  if not version_check.ok:
649
655
  console.print(f"[red]Error:[/red] {version_check.reason}")
650
- console.print("\n[dim]Tip: Run 'claude update' to upgrade.[/dim]")
656
+ print_tip("Run 'claude update' to upgrade.", console=console)
651
657
  sys.exit(1)
652
658
 
653
659
  if scope is None:
@@ -683,7 +689,7 @@ def sync_cmd(scope: str | None, force: bool) -> None:
683
689
  sys.exit(1)
684
690
  except NotInstalledError as e:
685
691
  console.print(f"[red]Error:[/red] {e}")
686
- console.print("\n[dim]Tip: Run 'forge extension enable' first.[/dim]")
692
+ print_tip("Run 'forge extension enable' first.", console=console)
687
693
  sys.exit(1)
688
694
  except ForgeInstallError as e:
689
695
  console.print(f"[red]Error:[/red] {e}")
@@ -809,12 +815,12 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool, force: bool)
809
815
  except NoForgeInstallationError as e:
810
816
  console.print(f"[red]Error:[/red] {e}")
811
817
  sys.exit(1)
812
- except ForgeInstallError as e:
813
- console.print(f"[red]Error:[/red] {e}")
814
- sys.exit(1)
815
818
  except TrackingCorruptedError as e:
816
819
  console.print(f"[bold red]Error:[/bold red] {e}")
817
820
  sys.exit(1)
821
+ except ForgeInstallError as e:
822
+ console.print(f"[red]Error:[/red] {e}")
823
+ sys.exit(1)
818
824
 
819
825
 
820
826
  @extensions.command("status")
@@ -993,9 +999,9 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
993
999
  if not local_installed:
994
1000
  all_installations = tracking.list_installations()
995
1001
  if all_installations:
996
- console.print(
997
- f"\n[dim]Tip: {len(all_installations)} installation(s) exist elsewhere. "
998
- "Use 'forge info' to see all.[/dim]"
1002
+ print_tip(
1003
+ f"{len(all_installations)} installation(s) exist elsewhere. Run 'forge info' to see all.",
1004
+ console=console,
999
1005
  )
1000
1006
  else:
1001
- console.print("\n[dim]Tip: Run 'forge extension enable' to set up Forge.[/dim]")
1007
+ print_tip("Run 'forge extension enable' to set up Forge.", console=console)
@@ -8,6 +8,7 @@ import sys
8
8
  import click
9
9
  from rich.console import Console
10
10
 
11
+ from forge.cli.output import print_tip
11
12
  from forge.core.ops.context import ExecutionContext
12
13
  from forge.core.ops.gc import CleanError, CleanReport, collect_clean_report, run_clean
13
14
 
@@ -78,7 +79,7 @@ def _print_report(report: CleanReport, verbose: bool, console: Console) -> None:
78
79
  console.print("[green]Nothing to clean.[/green]")
79
80
  else:
80
81
  console.print(f"Total: [cyan]{report.total_count}[/cyan] objects to clean\n")
81
- console.print("[dim]Tip: Run with --yes to clean, or --verbose for details.[/dim]")
82
+ print_tip("Use --yes to clean, or --verbose for details.", blank_before=False, console=console)
82
83
 
83
84
 
84
85
  def _run_and_report(ctx: ExecutionContext, scope: str, report: CleanReport, console: Console) -> None:
@@ -12,6 +12,7 @@ from pathlib import Path
12
12
 
13
13
  from rich.console import Console
14
14
 
15
+ from forge.cli.output import print_tip
15
16
  from forge.core.paths import display_path
16
17
 
17
18
  console = Console()
@@ -47,7 +48,7 @@ def require_repo_root() -> Path:
47
48
  console.print(
48
49
  f"[red]Error:[/red] Must run from the repository root ({display_path(repo_root)}), " f"not a subdirectory"
49
50
  )
50
- console.print(f"\n[dim]Tip: cd {display_path(hint)}[/dim]")
51
+ print_tip("Run from:", commands=[f"cd {display_path(hint)}"], console=console)
51
52
  sys.exit(1)
52
53
 
53
54
  return cwd
@@ -87,7 +88,7 @@ def require_main_repo_root() -> Path:
87
88
  "[red]Error:[/red] Cannot create worktrees from inside a child worktree. "
88
89
  f"Run from the main repository root ({display_path(main_root)})"
89
90
  )
90
- console.print(f"\n[dim]Tip: cd {display_path(main_root)}[/dim]")
91
+ print_tip("Run from:", commands=[f"cd {display_path(main_root)}"], console=console)
91
92
  sys.exit(1)
92
93
 
93
94
  # Accept CWD at a Forge project root (nested or top-level)
@@ -100,7 +101,7 @@ def require_main_repo_root() -> Path:
100
101
  console.print(
101
102
  f"[red]Error:[/red] Must run from the repository root ({display_path(repo_root)}), " f"not a subdirectory"
102
103
  )
103
- console.print(f"\n[dim]Tip: cd {display_path(repo_root)}[/dim]")
104
+ print_tip("Run from:", commands=[f"cd {display_path(repo_root)}"], console=console)
104
105
  sys.exit(1)
105
106
 
106
107
  return cwd
@@ -71,16 +71,21 @@ def run_cmd(
71
71
  logger.warning("Failed to read session manifest for %s: %s", session_name, e)
72
72
  raise SystemExit(1)
73
73
 
74
- if not effective.memory or not effective.memory.auto_update:
75
- logger.info("Handoff not configured for session %s", session_name)
76
- return
74
+ import dataclasses
77
75
 
78
- config = effective.memory.auto_update
79
- if not config.enabled:
80
- logger.info("Handoff disabled for session %s", session_name)
76
+ from forge.session.handoff_agent import resolve_handoff_base_url, run_handoff_agent
77
+ from forge.session.project_memory import (
78
+ DEFAULT_SCAN_ROOTS,
79
+ is_memory_enabled,
80
+ scan_passported_docs,
81
+ )
82
+
83
+ if not is_memory_enabled(manifest, effective):
84
+ logger.info("Handoff not activated for session %s", session_name)
81
85
  return
82
86
 
83
- from forge.session.handoff_agent import resolve_handoff_base_url, run_handoff_agent
87
+ assert effective.memory is not None and effective.memory.auto_update is not None
88
+ config = dataclasses.replace(effective.memory.auto_update, enabled=True)
84
89
 
85
90
  confirmed_proxy_url = None
86
91
  if manifest.confirmed.started_with_proxy:
@@ -94,7 +99,7 @@ def run_cmd(
94
99
  subprocess_proxy=subprocess_proxy or effective.subprocess_proxy,
95
100
  )
96
101
 
97
- designated_docs = effective.memory.designated_docs if effective.memory else []
102
+ designated_docs = scan_passported_docs(effective_root, DEFAULT_SCAN_ROOTS, session_name)
98
103
 
99
104
  success = run_handoff_agent(
100
105
  session_name=session_name,
@@ -52,9 +52,9 @@ from .direct_commands import (
52
52
  _handle_cmd_cancel_verification,
53
53
  _handle_cmd_clean,
54
54
  _handle_cmd_config,
55
- _handle_cmd_guard,
56
55
  _handle_cmd_help,
57
56
  _handle_cmd_plan,
57
+ _handle_cmd_policy,
58
58
  _handle_cmd_proxy,
59
59
  _handle_cmd_session,
60
60
  _parse_direct_command,
@@ -513,11 +513,14 @@ def stop() -> None:
513
513
  is not None
514
514
  )
515
515
 
516
- # Enqueue handoff marker if auto_update is enabled (best-effort)
516
+ # Enqueue handoff marker if memory is enabled for this session (best-effort).
517
517
  queued_handoff = False
518
518
  try:
519
519
  effective = compute_effective_intent(manifest)
520
- if effective.memory and effective.memory.auto_update and effective.memory.auto_update.enabled:
520
+
521
+ from forge.session.project_memory import is_memory_enabled
522
+
523
+ if is_memory_enabled(manifest, effective):
521
524
  queued_handoff = (
522
525
  enqueue_handoff_marker(
523
526
  session_id=session_id,
@@ -530,7 +533,7 @@ def stop() -> None:
530
533
  is not None
531
534
  )
532
535
  except Exception:
533
- pass # Best-effort: don't break stop hook on handoff enqueue failure
536
+ logger.debug("Memory handoff enqueue failed for session %s", manifest.name, exc_info=True)
534
537
 
535
538
  if not manifest_updated:
536
539
  # Manifest failed but we still tried to enqueue
@@ -1117,8 +1120,8 @@ def policy_check() -> None:
1117
1120
  print("[forge] Policy check: cannot build action context", file=sys.stderr)
1118
1121
  sys.exit(0)
1119
1122
 
1120
- from forge.guard.engine import build_engine
1121
- from forge.guard.types import FailMode
1123
+ from forge.policy.engine import build_engine
1124
+ from forge.policy.types import FailMode
1122
1125
 
1123
1126
  fail_mode: FailMode = effective.policy.fail_mode or "open"
1124
1127
  bundles = effective.policy.bundles or []
@@ -1140,7 +1143,7 @@ def policy_check() -> None:
1140
1143
 
1141
1144
  # Register semantic supervisor before restore_state so cached state is restored with it.
1142
1145
  if has_supervisor:
1143
- from forge.guard.semantic.supervisor import SemanticSupervisorPolicy
1146
+ from forge.policy.semantic.supervisor import SemanticSupervisorPolicy
1144
1147
 
1145
1148
  supervisor_policy = SemanticSupervisorPolicy(config=effective.policy.supervisor)
1146
1149
  engine.register(supervisor_policy)
@@ -1321,8 +1324,8 @@ def user_prompt_submit() -> None:
1321
1324
  _handle_cmd_plan(args)
1322
1325
  return
1323
1326
 
1324
- if cmd == "guard":
1325
- _handle_cmd_guard(data, args)
1327
+ if cmd == "policy":
1328
+ _handle_cmd_policy(data, args)
1326
1329
  return
1327
1330
 
1328
1331
  if cmd == "config":
@@ -1541,7 +1544,7 @@ def teammate_idle() -> None:
1541
1544
  if not config or not config.enabled:
1542
1545
  sys.exit(0)
1543
1546
 
1544
- from forge.guard.team.handlers import handle_teammate_idle
1547
+ from forge.policy.team.handlers import handle_teammate_idle
1545
1548
 
1546
1549
  cache_key = _safe_cache_key(data.get("session_id"))
1547
1550
  exit_code, feedback = _run_team_handler(cache_key, lambda cache: handle_teammate_idle(data, config, cache))
@@ -1576,7 +1579,7 @@ def task_completed() -> None:
1576
1579
  if not config or not config.enabled:
1577
1580
  sys.exit(0)
1578
1581
 
1579
- from forge.guard.team.handlers import handle_task_completed
1582
+ from forge.policy.team.handlers import handle_task_completed
1580
1583
 
1581
1584
  cache_key = _safe_cache_key(data.get("session_id"))
1582
1585
  exit_code, feedback = _run_team_handler(cache_key, lambda cache: handle_task_completed(data, config, cache))