multi-forge 0.4.0__tar.gz → 0.5.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 (352) hide show
  1. {multi_forge-0.4.0 → multi_forge-0.5.0}/PKG-INFO +1 -1
  2. {multi_forge-0.4.0 → multi_forge-0.5.0}/pyproject.toml +1 -1
  3. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/__init__.py +1 -1
  4. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/activity.py +14 -3
  5. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/gc.py +4 -4
  6. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/direct_commands.py +3 -3
  7. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/memory.py +6 -6
  8. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/policy.py +1 -1
  9. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/runtime.py +77 -2
  10. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/session_manage.py +5 -5
  11. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/status_line.py +5 -1
  12. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/transfer.py +12 -4
  13. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/anthropic-passthrough.yaml +3 -2
  14. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +5 -1
  15. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +6 -3
  16. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-anthropic.yaml +5 -3
  17. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/auth/capabilities.py +17 -2
  18. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/data/model_catalog.yaml +41 -3
  19. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/invoker/__init__.py +3 -0
  20. multi_forge-0.4.0/src/forge/core/invoker/claude.py → multi_forge-0.5.0/src/forge/core/invoker/_lifecycle.py +150 -174
  21. multi_forge-0.5.0/src/forge/core/invoker/claude.py +154 -0
  22. multi_forge-0.5.0/src/forge/core/invoker/codex.py +218 -0
  23. multi_forge-0.5.0/src/forge/core/invoker/codex_stream.py +141 -0
  24. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/invoker/types.py +6 -0
  25. multi_forge-0.5.0/src/forge/core/ops/codex_bridge.py +244 -0
  26. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/gc.py +9 -9
  27. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/resolution.py +7 -7
  28. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/session.py +7 -7
  29. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/transfer.py +18 -4
  30. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/usage_summary.py +135 -33
  31. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/env.py +92 -17
  32. multi_forge-0.5.0/src/forge/core/run_id.py +44 -0
  33. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/runtime/__init__.py +18 -0
  34. multi_forge-0.5.0/src/forge/core/runtime/codex_preflight.py +509 -0
  35. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/runtime/registry.py +45 -25
  36. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/usage/__init__.py +2 -0
  37. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/usage/emit.py +65 -0
  38. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/usage/ledger.py +5 -1
  39. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/queries.py +2 -2
  40. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/cost_logger.py +83 -1
  41. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/data_models.py +4 -2
  42. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/server.py +45 -0
  43. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/models.py +7 -0
  44. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/direct_model.py +4 -0
  45. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/manager.py +11 -6
  46. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/transfer.py +152 -20
  47. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/panel/SKILL.md +3 -3
  48. {multi_forge-0.4.0 → multi_forge-0.5.0}/.gitignore +0 -0
  49. {multi_forge-0.4.0 → multi_forge-0.5.0}/LICENSE +0 -0
  50. {multi_forge-0.4.0 → multi_forge-0.5.0}/NOTICE +0 -0
  51. {multi_forge-0.4.0 → multi_forge-0.5.0}/README.md +0 -0
  52. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/agents/.gitkeep +0 -0
  53. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/commands/.gitkeep +0 -0
  54. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/backend/__init__.py +0 -0
  55. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/backend/adapters/__init__.py +0 -0
  56. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/backend/adapters/litellm.py +0 -0
  57. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/backend/creation.py +0 -0
  58. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/backend/registry.py +0 -0
  59. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/__init__.py +0 -0
  60. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/auth.py +0 -0
  61. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/backend.py +0 -0
  62. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/claude.py +0 -0
  63. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/config_cmd.py +0 -0
  64. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/editor.py +0 -0
  65. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/extensions.py +0 -0
  66. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/guards.py +0 -0
  67. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/__init__.py +0 -0
  68. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/_group.py +0 -0
  69. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/_helpers.py +0 -0
  70. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/commands.py +0 -0
  71. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/install.py +0 -0
  72. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/policy.py +0 -0
  73. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/protocols.py +0 -0
  74. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
  75. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/hooks/verification.py +0 -0
  76. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/launch_confirmation.py +0 -0
  77. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/logs.py +0 -0
  78. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/main.py +0 -0
  79. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/memory_report.py +0 -0
  80. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/memory_writer.py +0 -0
  81. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/output.py +0 -0
  82. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/proxy.py +0 -0
  83. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/proxy_audit.py +0 -0
  84. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/proxy_costs.py +0 -0
  85. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/search.py +0 -0
  86. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/session.py +0 -0
  87. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/session_addendum.py +0 -0
  88. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/session_fork.py +0 -0
  89. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/session_lifecycle.py +0 -0
  90. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/statusline/__init__.py +0 -0
  91. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/statusline/context.py +0 -0
  92. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/statusline/names.py +0 -0
  93. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/statusline/palette.py +0 -0
  94. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/statusline/registry.py +0 -0
  95. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/statusline/throttle.py +0 -0
  96. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/cli/workflow.py +0 -0
  97. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/__init__.py +0 -0
  98. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/dataclass_utils.py +0 -0
  99. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/__init__.py +0 -0
  100. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/backends/__init__.py +0 -0
  101. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/backends/litellm.yaml +0 -0
  102. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/__init__.py +0 -0
  103. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +0 -0
  104. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +0 -0
  105. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +0 -0
  106. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +0 -0
  107. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +0 -0
  108. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +0 -0
  109. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/litellm-openai.yaml +0 -0
  110. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +0 -0
  111. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +0 -0
  112. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +0 -0
  113. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +0 -0
  114. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +0 -0
  115. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +0 -0
  116. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +0 -0
  117. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +0 -0
  118. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +0 -0
  119. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/loader.py +0 -0
  120. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/config/schema.py +0 -0
  121. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/__init__.py +0 -0
  122. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/auth/__init__.py +0 -0
  123. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/auth/credentials_file.py +0 -0
  124. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/auth/protocols.py +0 -0
  125. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/auth/secrets.py +0 -0
  126. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/auth/template_secrets.py +0 -0
  127. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/data/__init__.py +0 -0
  128. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
  129. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
  130. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
  131. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/__init__.py +0 -0
  132. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/clients/__init__.py +0 -0
  133. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/clients/base.py +0 -0
  134. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/clients/litellm.py +0 -0
  135. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/clients/openai_compat.py +0 -0
  136. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/clients/openrouter.py +0 -0
  137. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/credentials.py +0 -0
  138. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/detection.py +0 -0
  139. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/errors.py +0 -0
  140. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/protocols.py +0 -0
  141. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/llm/types.py +0 -0
  142. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/logging.py +0 -0
  143. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/models/__init__.py +0 -0
  144. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/models/catalog.py +0 -0
  145. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/models/types.py +0 -0
  146. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/naming.py +0 -0
  147. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/__init__.py +0 -0
  148. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/context.py +0 -0
  149. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/proxy.py +0 -0
  150. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/ops/session_context.py +0 -0
  151. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/paths.py +0 -0
  152. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/process.py +0 -0
  153. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/__init__.py +0 -0
  154. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/cost_tracking.py +0 -0
  155. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/headless_json.py +0 -0
  156. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/proxy.py +0 -0
  157. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/routing.py +0 -0
  158. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/session_runner.py +0 -0
  159. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/structured_output.py +0 -0
  160. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/tagger.py +0 -0
  161. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/reactive/throttle.py +0 -0
  162. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/state/__init__.py +0 -0
  163. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/state/exceptions.py +0 -0
  164. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/state/io.py +0 -0
  165. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/state/lock.py +0 -0
  166. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/state/timestamps.py +0 -0
  167. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/transcript.py +0 -0
  168. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/typing_helpers.py +0 -0
  169. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/usage/billing.py +0 -0
  170. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/usage/correlation.py +0 -0
  171. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/usage/vocabulary.py +0 -0
  172. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/workqueue/__init__.py +0 -0
  173. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/workqueue/queue.py +0 -0
  174. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/core/workqueue/types.py +0 -0
  175. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/__init__.py +0 -0
  176. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/cli.py +0 -0
  177. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/exceptions.py +0 -0
  178. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/hooks.py +0 -0
  179. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/installer.py +0 -0
  180. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/models.py +0 -0
  181. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/preset.py +0 -0
  182. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/settings_merge.py +0 -0
  183. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/tracking.py +0 -0
  184. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/install/version.py +0 -0
  185. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/__init__.py +0 -0
  186. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/deterministic/__init__.py +0 -0
  187. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/deterministic/base.py +0 -0
  188. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/deterministic/coding_standards.py +0 -0
  189. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/deterministic/registry.py +0 -0
  190. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/deterministic/tdd.py +0 -0
  191. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/engine.py +0 -0
  192. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/protocols.py +0 -0
  193. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/semantic/__init__.py +0 -0
  194. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/semantic/promotion.py +0 -0
  195. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/semantic/supervisor.py +0 -0
  196. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/semantic/verdict.py +0 -0
  197. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/store.py +0 -0
  198. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/team/__init__.py +0 -0
  199. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/team/config.py +0 -0
  200. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/team/handlers.py +0 -0
  201. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/team/prompts.py +0 -0
  202. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/types.py +0 -0
  203. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/workflow/__init__.py +0 -0
  204. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/workflow/branches.py +0 -0
  205. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/workflow/config.py +0 -0
  206. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/workflow/divergence.py +0 -0
  207. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/workflow/policy.py +0 -0
  208. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/policy/workflow/stages.py +0 -0
  209. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/__init__.py +0 -0
  210. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/audit_logger.py +0 -0
  211. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/base_client.py +0 -0
  212. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/client_adapter.py +0 -0
  213. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/client_factory.py +0 -0
  214. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/converters.py +0 -0
  215. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/cost_tracker.py +0 -0
  216. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/error_hints.py +0 -0
  217. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/intercept.py +0 -0
  218. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/metrics.py +0 -0
  219. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/model_spec.py +0 -0
  220. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/passthrough.py +0 -0
  221. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/proxies.py +0 -0
  222. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/proxy_identity.py +0 -0
  223. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/proxy_orchestrator.py +0 -0
  224. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/proxy_startup.py +0 -0
  225. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/proxy/utils.py +0 -0
  226. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/__init__.py +0 -0
  227. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/adversarial.py +0 -0
  228. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/consensus.py +0 -0
  229. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/engine.py +0 -0
  230. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/__init__.py +0 -0
  231. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/codereview-performance.md +0 -0
  232. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/codereview-quick.md +0 -0
  233. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/codereview-security.md +0 -0
  234. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/codereview.md +0 -0
  235. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/docreview-quick.md +0 -0
  236. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/docreview.md +0 -0
  237. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/resources/thinkdeep.md +0 -0
  238. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/routing.py +0 -0
  239. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/review/synthesis.py +0 -0
  240. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/runtime_config.py +0 -0
  241. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/__init__.py +0 -0
  242. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/bm25_store.py +0 -0
  243. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/content_store.py +0 -0
  244. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/engine.py +0 -0
  245. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/exceptions.py +0 -0
  246. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/extractor.py +0 -0
  247. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/index_state.py +0 -0
  248. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/store.py +0 -0
  249. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/search/tokenizer.py +0 -0
  250. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/__init__.py +0 -0
  251. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/active.py +0 -0
  252. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/artifacts.py +0 -0
  253. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/claude/__init__.py +0 -0
  254. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/claude/cleanup.py +0 -0
  255. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/claude/invoke.py +0 -0
  256. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/claude/paths.py +0 -0
  257. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/claude/relocate.py +0 -0
  258. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/cleanup.py +0 -0
  259. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/config.py +0 -0
  260. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/effective.py +0 -0
  261. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/exceptions.py +0 -0
  262. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/hooks/__init__.py +0 -0
  263. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/hooks/models.py +0 -0
  264. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/hooks/session_start.py +0 -0
  265. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/identity.py +0 -0
  266. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/index.py +0 -0
  267. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/memory_inheritance.py +0 -0
  268. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/memory_writer.py +0 -0
  269. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/models.py +0 -0
  270. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/overrides.py +0 -0
  271. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/passport.py +0 -0
  272. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/plan_resolution.py +0 -0
  273. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/prev_sessions.py +0 -0
  274. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/project_memory.py +0 -0
  275. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/shadow_curation.py +0 -0
  276. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/store.py +0 -0
  277. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/validation.py +0 -0
  278. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/worktree/__init__.py +0 -0
  279. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/worktree/cleanup.py +0 -0
  280. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/worktree/config_copy.py +0 -0
  281. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/session/worktree/create.py +0 -0
  282. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/sidecar/__init__.py +0 -0
  283. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/sidecar/container.py +0 -0
  284. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/sidecar/docker.py +0 -0
  285. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/forge/sidecar/secrets.py +0 -0
  286. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/analyze/SKILL.md +0 -0
  287. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/challenge/SKILL.md +0 -0
  288. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/consensus/SKILL.md +0 -0
  289. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/consensus/resources/code_consensus_evaluation.md +0 -0
  290. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/consensus/resources/consensus_evaluation.md +0 -0
  291. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/consensus/resources/synthesis.md +0 -0
  292. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/debate/SKILL.md +0 -0
  293. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/debate/resources/code_debate_evaluation.md +0 -0
  294. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/debate/resources/debate_evaluation.md +0 -0
  295. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/panel/resources/synthesis.md +0 -0
  296. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/SKILL.md +0 -0
  297. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/0-enable.md +0 -0
  298. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
  299. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/10-resume.md +0 -0
  300. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/11-config.md +0 -0
  301. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/12-search.md +0 -0
  302. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/13-policy.md +0 -0
  303. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
  304. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/15-skills.md +0 -0
  305. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/16-memory.md +0 -0
  306. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/17-info.md +0 -0
  307. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/18-disable.md +0 -0
  308. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/19-uninstall.md +0 -0
  309. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/2-extension.md +0 -0
  310. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/20-cleanup.md +0 -0
  311. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/3-authentication.md +0 -0
  312. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/4-proxy.md +0 -0
  313. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/5-session.md +0 -0
  314. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/6-hook.md +0 -0
  315. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/7-costs.md +0 -0
  316. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/8-status-line.md +0 -0
  317. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist/9-direct-commands.md +0 -0
  318. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/checklist.md +0 -0
  319. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/resources/report-template.md +0 -0
  320. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/scripts/start-container.sh +0 -0
  321. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/qa/scripts/walkthrough-state.py +0 -0
  322. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/SKILL.md +0 -0
  323. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/references/claude-4.6.md +0 -0
  324. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/references/claude-4.8.md +0 -0
  325. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/references/gemini-3.1.md +0 -0
  326. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/references/gpt-5.5.md +0 -0
  327. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/references/skills-writing-guide.md +0 -0
  328. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/resources/code-anthropic.md +0 -0
  329. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/resources/code-gemini.md +0 -0
  330. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/resources/code-openai.md +0 -0
  331. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review/resources/code.md +0 -0
  332. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review-docs/SKILL.md +0 -0
  333. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review-docs/resources/docs-anthropic.md +0 -0
  334. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review-docs/resources/docs-gemini.md +0 -0
  335. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review-docs/resources/docs-openai.md +0 -0
  336. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/review-docs/resources/docs.md +0 -0
  337. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/smoke-test/SKILL.md +0 -0
  338. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/smoke-test/scripts/smoke-test.sh +0 -0
  339. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/SKILL.md +0 -0
  340. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/code-anthropic.md +0 -0
  341. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/code-gemini.md +0 -0
  342. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/code-openai.md +0 -0
  343. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/code.md +0 -0
  344. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/docs-anthropic.md +0 -0
  345. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/docs-gemini.md +0 -0
  346. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/docs-openai.md +0 -0
  347. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/understand/resources/docs.md +0 -0
  348. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/walkthrough/SKILL.md +0 -0
  349. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/walkthrough/resources/checklist.md +0 -0
  350. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
  351. {multi_forge-0.4.0 → multi_forge-0.5.0}/src/skills/walkthrough/scripts/setup-test-repo.sh +0 -0
  352. {multi_forge-0.4.0 → multi_forge-0.5.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.4.0
3
+ Version: 0.5.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.4.0"
3
+ version = "0.5.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"
@@ -1,3 +1,3 @@
1
1
  """Multi-Forge - Multi-runtime agent toolkit."""
2
2
 
3
- __version__ = "0.4.0"
3
+ __version__ = "0.5.0"
@@ -100,7 +100,10 @@ def _render(summary: SessionActivitySummary, *, days: int | None) -> None:
100
100
  for c in summary.commands:
101
101
  errors = f"[red]{c.errors}[/red]" if c.errors else "0"
102
102
  tokens = f"{c.input_tokens}/{c.output_tokens}" if (c.input_tokens or c.output_tokens) else "-"
103
- cost = f"~{_fmt_usd(c.cost_micro_usd)}" if c.cost_micro_usd is not None else "-"
103
+ if c.cost_micro_usd is None:
104
+ cost = "-"
105
+ else:
106
+ cost = f"{'~' if c.cost_estimated else ''}{_fmt_usd(c.cost_micro_usd)}"
104
107
  row = [c.command, str(c.calls)]
105
108
  if show_workers:
106
109
  row.append(str(c.workers) if c.workers else "-")
@@ -120,7 +123,10 @@ def _render(summary: SessionActivitySummary, *, days: int | None) -> None:
120
123
  if summary.subagents:
121
124
  console.print(f"\n[bold]Subagents[/bold]: {summary.subagents}")
122
125
 
123
- total_cost = f"~{_fmt_usd(summary.total_cost_micro_usd)}" if summary.total_cost_micro_usd is not None else "n/a"
126
+ if summary.total_cost_micro_usd is None:
127
+ total_cost = "n/a"
128
+ else:
129
+ total_cost = f"{'~' if summary.cost_estimated else ''}{_fmt_usd(summary.total_cost_micro_usd)}"
124
130
  console.print(
125
131
  f"\n[dim]Total:[/dim] {summary.total_events} events · "
126
132
  f"{summary.total_input_tokens}/{summary.total_output_tokens} tok · {total_cost}"
@@ -138,7 +144,12 @@ def _footnotes(summary: SessionActivitySummary) -> list[str]:
138
144
  notes.append("policy decision log is at capacity — older decisions may not be shown")
139
145
  if summary.session_tagging_partial:
140
146
  notes.append("some calls (e.g. the action tagger) are not session-attributed")
141
- notes.append("cost is reported-or-estimated, best-effort; 'forge proxy costs show' is the authoritative spend view")
147
+ # "no snapshot estimates" covers both exact sources: the 4g cost-plane root-join
148
+ # and runtime-reported (runtime_native) self-reports. A cost-less summary keeps
149
+ # the generic caveat -- there is no figure to call exact.
150
+ exact = summary.total_cost_micro_usd is not None and not summary.cost_estimated
151
+ evidence = "reported (no snapshot estimates mixed in)" if exact else "reported-or-estimated"
152
+ notes.append(f"cost is {evidence}, best-effort; 'forge proxy costs show' is the authoritative spend view")
142
153
  return notes
143
154
 
144
155
 
@@ -16,9 +16,9 @@ from forge.core.ops.gc import CleanError, CleanReport, collect_clean_report, run
16
16
  @click.command("clean")
17
17
  @click.option(
18
18
  "--scope",
19
- type=click.Choice(["repo", "project", "all"]),
20
- default="repo",
21
- help="Scope: repo (default), project, or all",
19
+ type=click.Choice(["workspace", "project", "all"]),
20
+ default="workspace",
21
+ help="Scope: workspace (default), project, or all",
22
22
  )
23
23
  @click.option("--yes", "-y", is_flag=True, help="Actually delete (default is dry-run)")
24
24
  @click.option("--verbose", "-v", is_flag=True, help="Show individual items")
@@ -31,7 +31,7 @@ def clean_cmd(scope: str, yes: bool, verbose: bool, as_json: bool) -> None:
31
31
  Examples:
32
32
 
33
33
  \b
34
- forge clean # Dry-run (scope: repo)
34
+ forge clean # Dry-run (scope: workspace)
35
35
  forge clean --yes # Actually clean
36
36
  forge clean --scope all --yes # Clean globally
37
37
  forge clean --scope project # Current Forge project only
@@ -68,7 +68,7 @@ def _handle_cmd_help() -> None:
68
68
  "reason": "Direct commands:\n"
69
69
  "- %session show [name] | list\n"
70
70
  "- %proxy list | show <id> | audit show|diff [id]\n"
71
- "- %clean [--scope repo|project|all]\n"
71
+ "- %clean [--scope workspace|project|all]\n"
72
72
  "- %plan\n"
73
73
  "- %config (show runtime config)\n"
74
74
  "- %policy status | enable | disable | check\n"
@@ -108,8 +108,8 @@ def _handle_cmd_session(data: dict[str, Any], argv: list[str]) -> None:
108
108
  if "--no-incognito" in argv:
109
109
  include_incognito = False
110
110
 
111
- # Parse --scope VALUE or --scope=VALUE (default: repo)
112
- scope = "repo"
111
+ # Parse --scope VALUE or --scope=VALUE (default: workspace)
112
+ scope = "workspace"
113
113
  for i, arg in enumerate(argv):
114
114
  if arg.startswith("--scope="):
115
115
  scope = arg.split("=", 1)[1].lower()
@@ -85,7 +85,7 @@ def memory() -> None:
85
85
  forge memory track docs/changelog.md --strategy changelog # author a passport (sessionless)
86
86
  forge memory enable --session planner # enable memory for a session
87
87
  forge memory list # show passported docs
88
- forge memory status --scope repo # show activation across sessions
88
+ forge memory status --scope workspace # show activation across sessions
89
89
  """
90
90
 
91
91
 
@@ -590,7 +590,7 @@ def list_cmd(as_json: bool) -> None:
590
590
  @memory.command("status")
591
591
  @click.option(
592
592
  "--scope",
593
- type=click.Choice(["project", "repo", "all"]),
593
+ type=click.Choice(["project", "workspace", "all"]),
594
594
  default="project",
595
595
  show_default=True,
596
596
  help="Scope for discovery.",
@@ -689,7 +689,7 @@ def _collect_shadow_entries(
689
689
  @shadows_group.command("list")
690
690
  @click.option(
691
691
  "--scope",
692
- type=click.Choice(["project", "repo", "all"]),
692
+ type=click.Choice(["project", "workspace", "all"]),
693
693
  default="project",
694
694
  show_default=True,
695
695
  help="Scope for discovery.",
@@ -754,7 +754,7 @@ def shadows_list_cmd(scope: str, as_json: bool) -> None:
754
754
  @click.option("--for", "for_doc", required=True, help="Official doc to show shadow content for.")
755
755
  @click.option(
756
756
  "--scope",
757
- type=click.Choice(["project", "repo", "all"]),
757
+ type=click.Choice(["project", "workspace", "all"]),
758
758
  default="project",
759
759
  show_default=True,
760
760
  help="Scope for discovery.",
@@ -820,7 +820,7 @@ def shadows_show_cmd(for_doc: str, scope: str) -> None:
820
820
  @click.option("--session", "-s", "session_name", default=None, help="Session name.")
821
821
  @click.option(
822
822
  "--scope",
823
- type=click.Choice(["project", "repo", "all"]),
823
+ type=click.Choice(["project", "workspace", "all"]),
824
824
  default="project",
825
825
  show_default=True,
826
826
  help="Scope for shadow discovery.",
@@ -923,7 +923,7 @@ def _review_curate(
923
923
  )
924
924
 
925
925
  if scope == "all":
926
- raise click.ClickException("Cross-project curation deferred; use --scope project or --scope repo.")
926
+ raise click.ClickException("Cross-project curation deferred; use --scope project or --scope workspace.")
927
927
 
928
928
  ctx = ExecutionContext.from_cwd()
929
929
  try:
@@ -59,7 +59,7 @@ def _resolve_session_for_display(
59
59
  name: str,
60
60
  cwd: Path,
61
61
  ) -> tuple[SessionStore, SessionState]:
62
- """Resolve a named session, repo-scoped with current-project preference.
62
+ """Resolve a named session, workspace-scoped with current-project preference.
63
63
 
64
64
  Delegates to the shared two-tier resolver in core.ops.resolution.
65
65
  """
@@ -7,12 +7,19 @@ headless, hooks, usage source, native resume, install scopes).
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
+ import sys
11
+
10
12
  import click
11
13
  from rich.console import Console
12
14
  from rich.markup import escape
13
15
  from rich.table import Table
14
16
 
15
- from forge.core.runtime import RuntimeSpec, list_runtimes
17
+ from forge.core.runtime import (
18
+ CodexPreflight,
19
+ RuntimeSpec,
20
+ list_runtimes,
21
+ preflight_codex,
22
+ )
16
23
 
17
24
 
18
25
  @click.group(context_settings={"help_option_names": ["-h", "--help"]})
@@ -99,7 +106,75 @@ def list_cmd(as_json: bool) -> None:
99
106
 
100
107
  console.print(table)
101
108
  # Escape note text: a free-text note may contain bracketed tokens (e.g.
102
- # `[features] codex_hooks = true`) that Rich would otherwise eat as markup.
109
+ # `[features] hooks`) that Rich would otherwise eat as markup.
103
110
  for s in specs:
104
111
  if s.note:
105
112
  console.print(f"[dim]{s.id}: {escape(s.note)}[/dim]")
113
+
114
+
115
+ def _render_preflight(console: Console, result: CodexPreflight) -> None:
116
+ """Render a CodexPreflight as a labeled report (escapes free-text; carries no secret)."""
117
+ version = result.version or "-"
118
+ floor_met = "yes" if result.version_ok else "no"
119
+ ready = "[green]YES[/green]" if result.ready else "[red]NO[/red]"
120
+
121
+ console.print("[bold]Codex preflight[/bold]")
122
+ console.print(f" Installed: {'yes' if result.installed else 'no'}")
123
+ console.print(f" Version: {escape(version)} (hook floor met: {floor_met})")
124
+ console.print(
125
+ f" Auth: {escape(result.auth_method)} "
126
+ f"(source: {escape(result.auth_source)}, billing: {escape(result.billing_mode)})"
127
+ )
128
+ console.print(f" Hook seam: {escape(result.hook_seam)}")
129
+ console.print(f" Responses: {escape(result.proxy_responses)}")
130
+ if result.doctor_status:
131
+ console.print(f" Doctor: {escape(result.doctor_status)} [dim](informational)[/dim]")
132
+ console.print(f" Ready: {ready}")
133
+ if not result.ready and result.blocking_reason:
134
+ console.print()
135
+ console.print(escape(result.blocking_reason))
136
+
137
+
138
+ @runtime.command("preflight")
139
+ @click.argument("runtime_name", metavar="RUNTIME")
140
+ @click.option(
141
+ "--proxy",
142
+ "proxy_id",
143
+ default=None,
144
+ metavar="PROXY_ID",
145
+ help="Check Responses support against an existing proxy id (reads proxy.yaml; starts nothing).",
146
+ )
147
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
148
+ def preflight_cmd(runtime_name: str, proxy_id: str | None, as_json: bool) -> None:
149
+ """Preflight a runtime for headless runs: auth, hooks, and Responses readiness.
150
+
151
+ Runs the dynamic, per-machine checks the static `forge runtime list` matrix cannot:
152
+ resolves a non-interactive credential, reads `codex doctor`, checks hook state, and
153
+ -- with --proxy -- whether that proxy can serve Codex its Responses API. Exits
154
+ non-zero when the runtime is not ready.
155
+
156
+ \b
157
+ Examples:
158
+ forge runtime preflight codex
159
+ forge runtime preflight codex --json
160
+ forge runtime preflight codex --proxy my-openai-proxy
161
+ """
162
+ if runtime_name != "codex":
163
+ # Codex is the only runtime with a preflight today; this is the dispatch seam.
164
+ raise click.BadParameter(
165
+ f"No preflight available for '{runtime_name}' (supported: codex).",
166
+ param_hint="RUNTIME",
167
+ )
168
+
169
+ result = preflight_codex(proxy_id=proxy_id)
170
+
171
+ if as_json:
172
+ import json
173
+ from dataclasses import asdict
174
+
175
+ click.echo(json.dumps(asdict(result), indent=2))
176
+ else:
177
+ _render_preflight(Console(), result)
178
+
179
+ if not result.ready:
180
+ sys.exit(1)
@@ -415,9 +415,9 @@ def _delete_single_session(
415
415
  )
416
416
  @click.option(
417
417
  "--scope",
418
- type=click.Choice(["repo", "project", "all"], case_sensitive=False),
419
- default="repo",
420
- help="Scope: repo (default, same logical repo), project (same forge_root), all (global)",
418
+ type=click.Choice(["workspace", "project", "all"], case_sensitive=False),
419
+ default="workspace",
420
+ help="Scope: workspace (default, all worktrees of the same repo), project (same forge_root), all (global)",
421
421
  )
422
422
  @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
423
423
  def list_sessions(include_incognito: bool, older_than: int | None, scope: str, as_json: bool) -> None:
@@ -788,7 +788,7 @@ def show(session_id: str | None, as_json: bool, field_path: str | None) -> None:
788
788
 
789
789
  # Resolve the forge_root once -- either from get_session_context's prior
790
790
  # UUID/name lookup (preserves exact scope for UUIDs) or via the two-tier
791
- # repo-wide resolver as fallback.
791
+ # workspace-wide resolver as fallback.
792
792
  from forge.core.ops.resolution import resolve_session_repo_wide
793
793
  from forge.core.ops.session_context import resolve_session_identifier
794
794
 
@@ -815,7 +815,7 @@ def show(session_id: str | None, as_json: bool, field_path: str | None) -> None:
815
815
  return st, ent, is_cross
816
816
  except ForgeSessionError:
817
817
  pass
818
- # Fallback: two-tier repo-wide resolution
818
+ # Fallback: two-tier workspace-wide resolution
819
819
  try:
820
820
  res = resolve_session_repo_wide(ctx.session_name, _fr, manager=manager)
821
821
  return res.state, res.entry, res.is_cross_project
@@ -338,7 +338,8 @@ def get_tier_display(runtime: ProxyRuntimeTruth | None) -> str | None:
338
338
  def get_tier_from_display_name(display_name: str) -> str:
339
339
  """Map Claude Code's display name to tier."""
340
340
  display_lower = display_name.lower()
341
- if "opus" in display_lower:
341
+ # Fable carries no tier word of its own; it rides the opus tier.
342
+ if "opus" in display_lower or "fable" in display_lower:
342
343
  return "opus"
343
344
  elif "sonnet" in display_lower:
344
345
  return "sonnet"
@@ -360,6 +361,9 @@ def explicit_tier_from_model(model_id: str) -> str | None:
360
361
  for tier in ("haiku", "sonnet", "opus"):
361
362
  if tier in name:
362
363
  return tier
364
+ # Fable carries no tier word of its own; it rides the opus tier.
365
+ if "fable" in name:
366
+ return "opus"
363
367
  return None
364
368
 
365
369
 
@@ -31,7 +31,7 @@ from forge.core.ops.transfer import (
31
31
  show_transfer,
32
32
  )
33
33
  from forge.core.paths import display_path
34
- from forge.session.transfer import ResumeStrategy
34
+ from forge.session.transfer import TRANSFER_TARGET_RUNTIMES, ResumeStrategy
35
35
 
36
36
  _STRATEGY_CHOICES = [s.value for s in ResumeStrategy]
37
37
 
@@ -112,11 +112,19 @@ def show_cmd(parent: str, child: str | None, as_json: bool) -> None:
112
112
  help="Override strategy (default: the cache's current strategy).",
113
113
  )
114
114
  @click.option("--depth", type=int, default=None, help="Override lineage depth (default: the cache's current depth).")
115
- def regenerate_cmd(parent: str, strategy: str | None, depth: int | None) -> None:
115
+ @click.option(
116
+ "--target-runtime",
117
+ type=click.Choice(list(TRANSFER_TARGET_RUNTIMES)),
118
+ default=None,
119
+ help="Which runtime will consume this context (default: the cache's current target runtime).",
120
+ )
121
+ def regenerate_cmd(parent: str, strategy: str | None, depth: int | None, target_runtime: str | None) -> None:
116
122
  """Rebuild the parent cache (generated.md). Never touches children or notes."""
117
123
  ctx = ExecutionContext.from_cwd()
118
124
  try:
119
- result = regenerate_transfer(ctx=ctx, parent=parent, strategy=strategy, depth=depth)
125
+ result = regenerate_transfer(
126
+ ctx=ctx, parent=parent, strategy=strategy, depth=depth, target_runtime=target_runtime
127
+ )
120
128
  except ForgeOpError as e:
121
129
  print_error_with_tip(
122
130
  str(e),
@@ -127,7 +135,7 @@ def regenerate_cmd(parent: str, strategy: str | None, depth: int | None) -> None
127
135
 
128
136
  console.print(
129
137
  f"Regenerated [green]{display_path(result.path)}[/green] "
130
- f"[dim](strategy={result.strategy}, depth={result.depth})[/dim]"
138
+ f"[dim](strategy={result.strategy}, depth={result.depth}, runtime={result.target_runtime})[/dim]"
131
139
  )
132
140
  for warning in result.warnings:
133
141
  console.print(f"[yellow]Warning:[/yellow] {warning}")
@@ -8,7 +8,8 @@
8
8
  # `provider: litellm` is only a config slot used for credential and upstream
9
9
  # resolution — `wire_shape: anthropic_passthrough` is the authoritative wire truth
10
10
  # (GET / reports it). Tiers are informational here; the client's model is forwarded
11
- # unchanged. Requires ANTHROPIC_API_KEY in .env (or environment).
11
+ # unchanged (so --model claude-fable-5 reaches the API as-is; no model_alternatives
12
+ # remap applies on this wire shape). Requires ANTHROPIC_API_KEY in .env (or environment).
12
13
 
13
14
  proxy:
14
15
  family: anthropic
@@ -26,5 +27,5 @@ proxy:
26
27
  tiers:
27
28
  haiku: claude-haiku-4-5
28
29
  sonnet: claude-sonnet-4-6
29
- opus: claude-opus-4-6
30
+ opus: claude-fable-5
30
31
  base_url: "https://api.anthropic.com"
@@ -6,6 +6,9 @@
6
6
  #
7
7
  # Backend (LiteLLM on port 4000) starts automatically.
8
8
  #
9
+ # Opus tier defaults to Fable 5. Use --model claude-opus-4-8 or
10
+ # --model claude-opus-4-6 to select an Opus alternative instead.
11
+ #
9
12
  # Note: If you added ANTHROPIC_API_KEY after the backend started,
10
13
  # restart with: forge backend stop litellm-4000
11
14
 
@@ -25,9 +28,10 @@ proxy:
25
28
  tiers:
26
29
  haiku: anthropic/claude-haiku-4-5
27
30
  sonnet: anthropic/claude-sonnet-4-6
28
- opus: anthropic/claude-opus-4-6
31
+ opus: anthropic/claude-fable-5
29
32
  model_alternatives:
30
33
  opus:
31
34
  claude-opus-4-8: anthropic/claude-opus-4-8
35
+ claude-opus-4-6: anthropic/claude-opus-4-6
32
36
  prompt_caching: passthrough
33
37
  error_hints: true
@@ -1,10 +1,12 @@
1
1
  # Template: litellm-anthropic
2
2
  # Anthropic Claude via remote/shared LiteLLM
3
3
  #
4
- # Access to Claude Opus 4.6/4.8, Sonnet 4.6, and Haiku 4.5.
4
+ # Access to Claude Fable 5, Opus 4.8/4.6, Sonnet 4.6, and Haiku 4.5.
5
5
  # Requires LITELLM_API_KEY and LITELLM_BASE_URL in .env (or environment).
6
+ # NOTE: the shared LiteLLM instance must serve anthropic/claude-fable-5.
6
7
  #
7
- # Use --model claude-opus-4-8 to select Opus 4.8 instead of the 4.6 default.
8
+ # Opus tier defaults to Fable 5. Use --model claude-opus-4-8 or
9
+ # --model claude-opus-4-6 to select an Opus alternative instead.
8
10
  # prompt_caching: passthrough respects Anthropic's 4-breakpoint cache_control limit.
9
11
 
10
12
  proxy:
@@ -16,9 +18,10 @@ proxy:
16
18
  tiers:
17
19
  haiku: anthropic/claude-haiku-4-5
18
20
  sonnet: anthropic/claude-sonnet-4-6
19
- opus: anthropic/claude-opus-4-6
21
+ opus: anthropic/claude-fable-5
20
22
  model_alternatives:
21
23
  opus:
22
24
  claude-opus-4-8: anthropic/claude-opus-4-8
25
+ claude-opus-4-6: anthropic/claude-opus-4-6
23
26
  prompt_caching: passthrough
24
27
  error_hints: true
@@ -1,10 +1,11 @@
1
1
  # Template: openrouter-anthropic
2
2
  # Anthropic Claude models via OpenRouter (direct, no LiteLLM)
3
3
  #
4
- # Access to Claude Opus 4.6/4.8, Sonnet 4.6, and Haiku 4.5.
4
+ # Access to Claude Fable 5, Opus 4.8/4.6, Sonnet 4.6, and Haiku 4.5.
5
5
  # Requires OPENROUTER_API_KEY in .env (or environment).
6
6
  #
7
- # Use --model claude-opus-4-8 to select Opus 4.8 instead of the 4.6 default.
7
+ # Opus tier defaults to Fable 5. Use --model claude-opus-4-8 or
8
+ # --model claude-opus-4-6 to select an Opus alternative instead.
8
9
 
9
10
  proxy:
10
11
  family: anthropic
@@ -15,9 +16,10 @@ proxy:
15
16
  tiers:
16
17
  haiku: anthropic/claude-haiku-4.5
17
18
  sonnet: anthropic/claude-sonnet-4.6
18
- opus: anthropic/claude-opus-4.6
19
+ opus: anthropic/claude-fable-5
19
20
  model_alternatives:
20
21
  opus:
21
22
  claude-opus-4-8: anthropic/claude-opus-4.8
23
+ claude-opus-4-6: anthropic/claude-opus-4.6
22
24
  base_url: "https://openrouter.ai/api/v1"
23
25
  error_hints: true
@@ -84,6 +84,21 @@ CREDENTIALS: dict[str, Credential] = {
84
84
  signup_url="https://aistudio.google.com/apikey",
85
85
  note="Gemini API key for local LiteLLM proxy routing",
86
86
  ),
87
+ "codex-api": Credential(
88
+ name="codex-api",
89
+ env_vars=(EnvVar("CODEX_API_KEY"),),
90
+ unlocks_features=("Native Codex headless runs (codex exec)",),
91
+ signup_url="https://platform.openai.com/api-keys",
92
+ note=(
93
+ "Non-interactive Codex override. Codex keeps its OWN credential store; run "
94
+ "'codex doctor' to see resolved auth. Not your ChatGPT login (codex login "
95
+ "--device-auth) and not OPENAI_API_KEY."
96
+ ),
97
+ not_needed_for=(
98
+ "Codex already logged in via 'codex login'",
99
+ "Codex via ChatGPT subscription (codex login --device-auth)",
100
+ ),
101
+ ),
87
102
  "litellm-remote": Credential(
88
103
  name="litellm-remote",
89
104
  env_vars=(
@@ -158,8 +173,8 @@ def format_missing_credential_error(
158
173
  """Build an actionable error message for missing credentials.
159
174
 
160
175
  Includes what failed, which key(s), signup URL, and the exact
161
- ``forge auth login`` command. Renders ``not_needed_for`` only for
162
- anthropic-api (where false urgency is common).
176
+ ``forge auth login`` command. Renders ``not_needed_for`` when the credential
177
+ defines it (anthropic-api, codex-api -- where false urgency is common).
163
178
  """
164
179
  key_word = "key" if len(missing_vars) == 1 else "keys"
165
180
  var_list = ", ".join(missing_vars)
@@ -761,7 +761,7 @@ models:
761
761
  # minimal/low/none/disable -> low, medium/high -> high
762
762
  litellm_reasoning_efforts: [none, disable, minimal, low, medium, high]
763
763
  default_reasoning_effort: high
764
- intelligence_score: 94
764
+ intelligence_score: 99 # Peer of gpt-5.5 / Claude Opus 4.8
765
765
  system_prompt_addendum: system_prompt_addendums/gemini.md
766
766
  tags: []
767
767
 
@@ -785,7 +785,7 @@ models:
785
785
  default_thinking_level: high
786
786
  litellm_reasoning_efforts: [none, disable, minimal, low, medium, high]
787
787
  default_reasoning_effort: high
788
- intelligence_score: 94
788
+ intelligence_score: 99 # Tracks gemini-3.1-pro-preview
789
789
  system_prompt_addendum: system_prompt_addendums/gemini.md
790
790
  tags: [agentic, custom-tools]
791
791
 
@@ -976,9 +976,41 @@ models:
976
976
  litellm_reasoning_efforts: [low, medium, high, xhigh]
977
977
  default_reasoning_effort: high
978
978
  token_estimate_multiplier: 1.35
979
- intelligence_score: 100
979
+ intelligence_score: 99 # Below Fable 5; peer of gpt-5.5 / Gemini 3.1 Pro
980
980
  tags: [bounded-review, opt-in]
981
981
 
982
+ # --- Claude Fable Series ---
983
+ # Fable 5 is the most capable model (a tier above Opus). Same request surface
984
+ # as Opus 4.8 -- adaptive thinking only, sampling overrides removed. Used as
985
+ # the OpenRouter opus-tier default (see templates/openrouter-anthropic.yaml);
986
+ # Opus 4.8/4.6 stay selectable via --model. Not a catalog default: anthropic
987
+ # defaults stay on 4.6 until this profile is proven for resume-heavy flows.
988
+ claude-fable-5:
989
+ friendly_name: Claude Fable 5
990
+ context_window_tokens: 1000000
991
+ max_output_tokens: 128000
992
+ max_thinking_tokens: 128000
993
+ supports_thinking: true
994
+ supports_images: true
995
+ supports_1m_context: true
996
+ temperature_constraint: fixed
997
+ temperature: 1.0
998
+ supports_top_p: false
999
+ supports_sampling_overrides: false
1000
+ default_timeout_seconds: 240
1001
+ prompt_caching:
1002
+ supports: true
1003
+ mechanism: cache_control
1004
+ min_tokens: 1024
1005
+ max_cache_blocks: 4
1006
+ native_thinking_param: output_config.effort
1007
+ thinking_modes: [adaptive]
1008
+ litellm_reasoning_efforts: [low, medium, high, xhigh]
1009
+ default_reasoning_effort: high
1010
+ token_estimate_multiplier: 1.35
1011
+ intelligence_score: 100
1012
+ tags: [opt-in]
1013
+
982
1014
  claude-sonnet-4-6:
983
1015
  friendly_name: Claude Sonnet 4.6
984
1016
  context_window_tokens: 200000
@@ -1547,6 +1579,12 @@ aliases:
1547
1579
  opus-4-8: claude-opus-4-8
1548
1580
  opus-4.8: claude-opus-4-8
1549
1581
 
1582
+ # Fable 5 (most capable; OpenRouter opus-tier default, direct --model fable)
1583
+ anthropic/claude-fable-5: claude-fable-5
1584
+ claude-fable: claude-fable-5
1585
+ fable-5: claude-fable-5
1586
+ fable: claude-fable-5
1587
+
1550
1588
  # Sonnet 4.6
1551
1589
  anthropic/claude-sonnet-4-6: claude-sonnet-4-6
1552
1590
  anthropic/claude-sonnet-4-6-1m: claude-sonnet-4-6-1m
@@ -7,6 +7,7 @@ ordered fan-out, timeouts) and per-job usage emission. Phase 5 adds a
7
7
  """
8
8
 
9
9
  from .claude import ClaudeHeadlessInvoker
10
+ from .codex import CodexHeadlessInvoker, prepare_codex_request
10
11
  from .types import (
11
12
  Attribution,
12
13
  HeadlessInvoker,
@@ -17,7 +18,9 @@ from .types import (
17
18
  __all__ = [
18
19
  "Attribution",
19
20
  "ClaudeHeadlessInvoker",
21
+ "CodexHeadlessInvoker",
20
22
  "HeadlessInvoker",
21
23
  "HeadlessRequest",
22
24
  "HeadlessResult",
25
+ "prepare_codex_request",
23
26
  ]