multi-forge 0.2.1__tar.gz → 0.4.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 (360) hide show
  1. {multi_forge-0.2.1 → multi_forge-0.4.0}/PKG-INFO +15 -9
  2. {multi_forge-0.2.1 → multi_forge-0.4.0}/README.md +14 -8
  3. {multi_forge-0.2.1 → multi_forge-0.4.0}/pyproject.toml +7 -6
  4. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/__init__.py +1 -1
  5. multi_forge-0.4.0/src/forge/cli/activity.py +151 -0
  6. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/auth.py +1 -3
  7. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/backend.py +23 -13
  8. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/claude.py +10 -11
  9. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/config_cmd.py +118 -14
  10. multi_forge-0.4.0/src/forge/cli/editor.py +44 -0
  11. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/extensions.py +24 -21
  12. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/gc.py +4 -3
  13. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/guards.py +4 -3
  14. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/commands.py +30 -55
  15. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/direct_commands.py +116 -47
  16. multi_forge-0.4.0/src/forge/cli/hooks/policy.py +212 -0
  17. multi_forge-0.4.0/src/forge/cli/hooks/protocols.py +53 -0
  18. multi_forge-0.4.0/src/forge/cli/launch_confirmation.py +134 -0
  19. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/logs.py +35 -13
  20. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/main.py +74 -9
  21. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/memory.py +357 -497
  22. multi_forge-0.2.1/src/forge/cli/session_handoff.py → multi_forge-0.4.0/src/forge/cli/memory_report.py +31 -29
  23. multi_forge-0.2.1/src/forge/cli/handoff.py → multi_forge-0.4.0/src/forge/cli/memory_writer.py +23 -18
  24. multi_forge-0.4.0/src/forge/cli/output.py +92 -0
  25. multi_forge-0.2.1/src/forge/cli/guard.py → multi_forge-0.4.0/src/forge/cli/policy.py +127 -139
  26. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/proxy.py +148 -77
  27. multi_forge-0.4.0/src/forge/cli/proxy_audit.py +253 -0
  28. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/proxy_costs.py +203 -55
  29. multi_forge-0.4.0/src/forge/cli/runtime.py +105 -0
  30. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/search.py +22 -20
  31. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/session.py +23 -46
  32. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/session_fork.py +266 -50
  33. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/session_lifecycle.py +293 -175
  34. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/session_manage.py +94 -30
  35. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/status_line.py +490 -161
  36. multi_forge-0.4.0/src/forge/cli/statusline/__init__.py +9 -0
  37. multi_forge-0.4.0/src/forge/cli/statusline/context.py +144 -0
  38. multi_forge-0.4.0/src/forge/cli/statusline/names.py +61 -0
  39. multi_forge-0.4.0/src/forge/cli/statusline/palette.py +149 -0
  40. multi_forge-0.4.0/src/forge/cli/statusline/registry.py +379 -0
  41. multi_forge-0.4.0/src/forge/cli/statusline/throttle.py +172 -0
  42. multi_forge-0.4.0/src/forge/cli/transfer.py +186 -0
  43. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/workflow.py +70 -13
  44. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/backends/litellm.yaml +12 -0
  45. multi_forge-0.4.0/src/forge/config/defaults/templates/anthropic-passthrough.yaml +30 -0
  46. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +1 -1
  47. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +3 -3
  48. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +1 -1
  49. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-anthropic.yaml +3 -3
  50. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +4 -4
  51. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +1 -1
  52. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +6 -4
  53. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/loader.py +6 -0
  54. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/schema.py +245 -11
  55. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/auth/capabilities.py +2 -1
  56. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/auth/template_secrets.py +23 -8
  57. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/data/model_catalog.yaml +95 -3
  58. multi_forge-0.4.0/src/forge/core/invoker/__init__.py +23 -0
  59. multi_forge-0.4.0/src/forge/core/invoker/claude.py +457 -0
  60. multi_forge-0.4.0/src/forge/core/invoker/types.py +111 -0
  61. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/__init__.py +1 -1
  62. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/clients/litellm.py +58 -7
  63. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/clients/openai_compat.py +26 -0
  64. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/clients/openrouter.py +8 -1
  65. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/credentials.py +20 -0
  66. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/types.py +6 -0
  67. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/models/__init__.py +0 -11
  68. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/ops/gc.py +23 -12
  69. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/ops/resolution.py +1 -1
  70. multi_forge-0.4.0/src/forge/core/ops/transfer.py +265 -0
  71. multi_forge-0.4.0/src/forge/core/ops/usage_summary.py +364 -0
  72. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/reactive/__init__.py +17 -1
  73. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/reactive/cost_tracking.py +72 -54
  74. multi_forge-0.4.0/src/forge/core/reactive/env.py +363 -0
  75. multi_forge-0.4.0/src/forge/core/reactive/headless_json.py +133 -0
  76. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/reactive/proxy.py +1 -1
  77. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/reactive/routing.py +2 -2
  78. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/reactive/session_runner.py +122 -25
  79. multi_forge-0.4.0/src/forge/core/reactive/structured_output.py +153 -0
  80. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/reactive/tagger.py +35 -4
  81. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/reactive/throttle.py +1 -1
  82. multi_forge-0.4.0/src/forge/core/runtime/__init__.py +27 -0
  83. multi_forge-0.4.0/src/forge/core/runtime/registry.py +211 -0
  84. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/state/__init__.py +8 -1
  85. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/state/io.py +18 -0
  86. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/transcript.py +1 -1
  87. multi_forge-0.4.0/src/forge/core/usage/__init__.py +56 -0
  88. multi_forge-0.4.0/src/forge/core/usage/billing.py +28 -0
  89. multi_forge-0.4.0/src/forge/core/usage/correlation.py +91 -0
  90. multi_forge-0.4.0/src/forge/core/usage/emit.py +440 -0
  91. multi_forge-0.4.0/src/forge/core/usage/ledger.py +306 -0
  92. multi_forge-0.4.0/src/forge/core/usage/vocabulary.py +70 -0
  93. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/workqueue/queue.py +12 -0
  94. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/__init__.py +3 -2
  95. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/exceptions.py +3 -2
  96. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/installer.py +6 -6
  97. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/preset.py +2 -2
  98. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/tracking.py +2 -2
  99. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/__init__.py +2 -2
  100. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/deterministic/__init__.py +3 -3
  101. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/deterministic/base.py +1 -1
  102. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/deterministic/coding_standards.py +26 -14
  103. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/deterministic/registry.py +5 -5
  104. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/deterministic/tdd.py +2 -2
  105. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/engine.py +3 -3
  106. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/protocols.py +1 -1
  107. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/queries.py +2 -2
  108. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/semantic/__init__.py +2 -2
  109. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/semantic/promotion.py +2 -2
  110. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/semantic/supervisor.py +47 -26
  111. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/semantic/verdict.py +1 -1
  112. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/store.py +1 -1
  113. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/team/handlers.py +22 -6
  114. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/types.py +9 -3
  115. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/workflow/branches.py +3 -3
  116. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/workflow/divergence.py +1 -1
  117. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/workflow/policy.py +4 -4
  118. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/workflow/stages.py +2 -2
  119. multi_forge-0.4.0/src/forge/proxy/audit_logger.py +464 -0
  120. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/client_adapter.py +17 -7
  121. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/converters.py +7 -0
  122. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/cost_logger.py +35 -10
  123. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/cost_tracker.py +31 -28
  124. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/data_models.py +6 -1
  125. multi_forge-0.4.0/src/forge/proxy/intercept.py +314 -0
  126. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/metrics.py +38 -8
  127. multi_forge-0.4.0/src/forge/proxy/passthrough.py +281 -0
  128. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/proxies.py +1 -1
  129. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/proxy_orchestrator.py +146 -8
  130. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/server.py +586 -67
  131. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/utils.py +27 -0
  132. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/adversarial.py +4 -0
  133. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/consensus.py +4 -0
  134. multi_forge-0.4.0/src/forge/review/engine.py +357 -0
  135. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/models.py +14 -9
  136. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/runtime_config.py +141 -15
  137. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/claude/__init__.py +14 -0
  138. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/claude/invoke.py +21 -4
  139. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/claude/paths.py +14 -4
  140. multi_forge-0.4.0/src/forge/session/claude/relocate.py +171 -0
  141. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/effective.py +7 -3
  142. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/manager.py +355 -84
  143. multi_forge-0.4.0/src/forge/session/memory_inheritance.py +78 -0
  144. multi_forge-0.2.1/src/forge/session/handoff_agent.py → multi_forge-0.4.0/src/forge/session/memory_writer.py +80 -71
  145. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/models.py +52 -26
  146. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/passport.py +29 -57
  147. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/plan_resolution.py +1 -1
  148. multi_forge-0.4.0/src/forge/session/prev_sessions.py +236 -0
  149. multi_forge-0.4.0/src/forge/session/project_memory.py +284 -0
  150. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/shadow_curation.py +48 -27
  151. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/store.py +32 -0
  152. multi_forge-0.2.1/src/forge/session/handoff.py → multi_forge-0.4.0/src/forge/session/transfer.py +309 -87
  153. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/sidecar/container.py +84 -0
  154. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/panel/SKILL.md +4 -4
  155. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/SKILL.md +44 -44
  156. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/10-resume.md +66 -5
  157. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/11-config.md +4 -4
  158. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/12-search.md +3 -3
  159. multi_forge-0.2.1/src/skills/qa/resources/checklist/13-guard.md → multi_forge-0.4.0/src/skills/qa/resources/checklist/13-policy.md +37 -31
  160. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/15-skills.md +6 -6
  161. multi_forge-0.2.1/src/skills/qa/resources/checklist/16-handoff.md → multi_forge-0.4.0/src/skills/qa/resources/checklist/16-memory.md +48 -58
  162. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/17-info.md +16 -0
  163. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/18-disable.md +10 -10
  164. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/20-cleanup.md +5 -0
  165. multi_forge-0.2.1/src/skills/qa/resources/checklist/3-auth.md → multi_forge-0.4.0/src/skills/qa/resources/checklist/3-authentication.md +9 -22
  166. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/4-proxy.md +89 -21
  167. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/5-session.md +172 -54
  168. multi_forge-0.2.1/src/skills/qa/resources/checklist/6-hooks.md → multi_forge-0.4.0/src/skills/qa/resources/checklist/6-hook.md +1 -1
  169. multi_forge-0.4.0/src/skills/qa/resources/checklist/7-costs.md +464 -0
  170. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/8-status-line.md +110 -2
  171. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/9-direct-commands.md +40 -21
  172. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist.md +23 -16
  173. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/report-template.md +2 -2
  174. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/scripts/start-container.sh +37 -18
  175. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/scripts/walkthrough-state.py +3 -5
  176. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review/SKILL.md +5 -5
  177. multi_forge-0.2.1/src/skills/review/references/claude-4.7.md → multi_forge-0.4.0/src/skills/review/references/claude-4.8.md +85 -69
  178. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review/references/gemini-3.1.md +2 -2
  179. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review/references/skills-writing-guide.md +1 -1
  180. multi_forge-0.4.0/src/skills/review/resources/code.md +1 -0
  181. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review-docs/SKILL.md +2 -2
  182. multi_forge-0.4.0/src/skills/review-docs/resources/docs.md +1 -0
  183. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/understand/SKILL.md +2 -2
  184. multi_forge-0.4.0/src/skills/understand/resources/code.md +163 -0
  185. multi_forge-0.4.0/src/skills/understand/resources/docs.md +177 -0
  186. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/walkthrough/SKILL.md +2 -2
  187. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/walkthrough/resources/checklist.md +25 -22
  188. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/walkthrough/scripts/walkthrough-state.py +3 -5
  189. multi_forge-0.2.1/src/forge/cli/hooks/policy.py +0 -151
  190. multi_forge-0.2.1/src/forge/cli/session_memory.py +0 -38
  191. multi_forge-0.2.1/src/forge/core/data/pricing.yaml +0 -140
  192. multi_forge-0.2.1/src/forge/core/models/pricing.py +0 -165
  193. multi_forge-0.2.1/src/forge/core/reactive/env.py +0 -180
  194. multi_forge-0.2.1/src/forge/core/reactive/structured_output.py +0 -62
  195. multi_forge-0.2.1/src/forge/review/engine.py +0 -358
  196. multi_forge-0.2.1/src/forge/session/memory_inheritance.py +0 -252
  197. multi_forge-0.2.1/src/forge/session/prev_sessions.py +0 -128
  198. multi_forge-0.2.1/src/skills/qa/resources/checklist/7-costs.md +0 -309
  199. multi_forge-0.2.1/src/skills/review/resources/code-anthropic.md +0 -1
  200. multi_forge-0.2.1/src/skills/review-docs/resources/docs-anthropic.md +0 -1
  201. multi_forge-0.2.1/src/skills/understand/resources/code-anthropic.md +0 -1
  202. multi_forge-0.2.1/src/skills/understand/resources/docs-anthropic.md +0 -1
  203. {multi_forge-0.2.1 → multi_forge-0.4.0}/.gitignore +0 -0
  204. {multi_forge-0.2.1 → multi_forge-0.4.0}/LICENSE +0 -0
  205. {multi_forge-0.2.1 → multi_forge-0.4.0}/NOTICE +0 -0
  206. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/agents/.gitkeep +0 -0
  207. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/commands/.gitkeep +0 -0
  208. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/backend/__init__.py +0 -0
  209. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/backend/adapters/__init__.py +0 -0
  210. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/backend/adapters/litellm.py +0 -0
  211. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/backend/creation.py +0 -0
  212. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/backend/registry.py +0 -0
  213. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/__init__.py +0 -0
  214. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/__init__.py +0 -0
  215. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/_group.py +0 -0
  216. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/_helpers.py +0 -0
  217. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/install.py +0 -0
  218. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
  219. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/hooks/verification.py +0 -0
  220. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/cli/session_addendum.py +0 -0
  221. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/__init__.py +0 -0
  222. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/dataclass_utils.py +0 -0
  223. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/__init__.py +0 -0
  224. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/backends/__init__.py +0 -0
  225. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/__init__.py +0 -0
  226. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +0 -0
  227. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +0 -0
  228. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +0 -0
  229. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +0 -0
  230. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +0 -0
  231. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/litellm-openai.yaml +0 -0
  232. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +0 -0
  233. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +0 -0
  234. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +0 -0
  235. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +0 -0
  236. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +0 -0
  237. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +0 -0
  238. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/__init__.py +0 -0
  239. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/auth/__init__.py +0 -0
  240. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/auth/credentials_file.py +0 -0
  241. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/auth/protocols.py +0 -0
  242. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/auth/secrets.py +0 -0
  243. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/data/__init__.py +0 -0
  244. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
  245. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
  246. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
  247. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/clients/__init__.py +0 -0
  248. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/clients/base.py +0 -0
  249. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/detection.py +0 -0
  250. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/errors.py +0 -0
  251. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/llm/protocols.py +0 -0
  252. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/logging.py +0 -0
  253. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/models/catalog.py +0 -0
  254. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/models/types.py +0 -0
  255. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/naming.py +0 -0
  256. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/ops/__init__.py +0 -0
  257. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/ops/context.py +0 -0
  258. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/ops/proxy.py +0 -0
  259. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/ops/session.py +0 -0
  260. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/ops/session_context.py +0 -0
  261. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/paths.py +0 -0
  262. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/process.py +0 -0
  263. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/state/exceptions.py +0 -0
  264. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/state/lock.py +0 -0
  265. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/state/timestamps.py +0 -0
  266. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/typing_helpers.py +0 -0
  267. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/workqueue/__init__.py +0 -0
  268. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/core/workqueue/types.py +0 -0
  269. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/cli.py +0 -0
  270. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/hooks.py +0 -0
  271. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/models.py +0 -0
  272. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/settings_merge.py +0 -0
  273. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/install/version.py +0 -0
  274. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/team/__init__.py +0 -0
  275. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/team/config.py +0 -0
  276. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/team/prompts.py +0 -0
  277. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/workflow/__init__.py +0 -0
  278. {multi_forge-0.2.1/src/forge/guard → multi_forge-0.4.0/src/forge/policy}/workflow/config.py +0 -0
  279. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/__init__.py +0 -0
  280. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/base_client.py +0 -0
  281. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/client_factory.py +0 -0
  282. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/error_hints.py +0 -0
  283. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/model_spec.py +0 -0
  284. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/proxy_identity.py +0 -0
  285. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/proxy/proxy_startup.py +0 -0
  286. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/__init__.py +0 -0
  287. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/__init__.py +0 -0
  288. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/codereview-performance.md +0 -0
  289. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/codereview-quick.md +0 -0
  290. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/codereview-security.md +0 -0
  291. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/codereview.md +0 -0
  292. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/docreview-quick.md +0 -0
  293. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/docreview.md +0 -0
  294. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/resources/thinkdeep.md +0 -0
  295. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/routing.py +0 -0
  296. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/review/synthesis.py +0 -0
  297. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/__init__.py +0 -0
  298. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/bm25_store.py +0 -0
  299. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/content_store.py +0 -0
  300. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/engine.py +0 -0
  301. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/exceptions.py +0 -0
  302. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/extractor.py +0 -0
  303. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/index_state.py +0 -0
  304. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/store.py +0 -0
  305. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/search/tokenizer.py +0 -0
  306. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/__init__.py +0 -0
  307. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/active.py +0 -0
  308. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/artifacts.py +0 -0
  309. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/claude/cleanup.py +0 -0
  310. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/cleanup.py +0 -0
  311. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/config.py +0 -0
  312. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/direct_model.py +0 -0
  313. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/exceptions.py +0 -0
  314. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/hooks/__init__.py +0 -0
  315. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/hooks/models.py +0 -0
  316. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/hooks/session_start.py +0 -0
  317. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/identity.py +0 -0
  318. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/index.py +0 -0
  319. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/overrides.py +0 -0
  320. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/validation.py +0 -0
  321. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/worktree/__init__.py +0 -0
  322. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/worktree/cleanup.py +0 -0
  323. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/worktree/config_copy.py +0 -0
  324. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/session/worktree/create.py +0 -0
  325. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/sidecar/__init__.py +0 -0
  326. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/sidecar/docker.py +0 -0
  327. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/forge/sidecar/secrets.py +0 -0
  328. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/analyze/SKILL.md +0 -0
  329. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/challenge/SKILL.md +0 -0
  330. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/consensus/SKILL.md +0 -0
  331. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/consensus/resources/code_consensus_evaluation.md +0 -0
  332. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/consensus/resources/consensus_evaluation.md +0 -0
  333. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/consensus/resources/synthesis.md +0 -0
  334. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/debate/SKILL.md +0 -0
  335. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/debate/resources/code_debate_evaluation.md +0 -0
  336. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/debate/resources/debate_evaluation.md +0 -0
  337. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/panel/resources/synthesis.md +0 -0
  338. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/0-enable.md +0 -0
  339. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
  340. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
  341. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/qa/resources/checklist/19-uninstall.md +0 -0
  342. /multi_forge-0.2.1/src/skills/qa/resources/checklist/2-extensions.md → /multi_forge-0.4.0/src/skills/qa/resources/checklist/2-extension.md +0 -0
  343. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review/references/claude-4.6.md +0 -0
  344. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review/references/gpt-5.5.md +0 -0
  345. /multi_forge-0.2.1/src/skills/review/resources/code.md → /multi_forge-0.4.0/src/skills/review/resources/code-anthropic.md +0 -0
  346. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review/resources/code-gemini.md +0 -0
  347. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review/resources/code-openai.md +0 -0
  348. /multi_forge-0.2.1/src/skills/review-docs/resources/docs.md → /multi_forge-0.4.0/src/skills/review-docs/resources/docs-anthropic.md +0 -0
  349. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review-docs/resources/docs-gemini.md +0 -0
  350. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/review-docs/resources/docs-openai.md +0 -0
  351. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/smoke-test/SKILL.md +0 -0
  352. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/smoke-test/scripts/smoke-test.sh +0 -0
  353. /multi_forge-0.2.1/src/skills/understand/resources/code.md → /multi_forge-0.4.0/src/skills/understand/resources/code-anthropic.md +0 -0
  354. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/understand/resources/code-gemini.md +0 -0
  355. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/understand/resources/code-openai.md +0 -0
  356. /multi_forge-0.2.1/src/skills/understand/resources/docs.md → /multi_forge-0.4.0/src/skills/understand/resources/docs-anthropic.md +0 -0
  357. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/understand/resources/docs-gemini.md +0 -0
  358. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/understand/resources/docs-openai.md +0 -0
  359. {multi_forge-0.2.1 → multi_forge-0.4.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
  360. {multi_forge-0.2.1 → multi_forge-0.4.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.1
3
+ Version: 0.4.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
@@ -41,9 +41,13 @@ Description-Content-Type: text/markdown
41
41
 
42
42
  # Multi-Forge
43
43
 
44
+ <p align="left">
45
+ <img src="assets/logo.jpg" alt="Dusk" width=240">
46
+ </p>
47
+
44
48
  [![PyPI](https://img.shields.io/pypi/v/multi-forge)](https://pypi.org/project/multi-forge/)
45
49
  [![Python](https://img.shields.io/pypi/pyversions/multi-forge)](https://pypi.org/project/multi-forge/)
46
- [![License](https://img.shields.io/github/license/hapa1i/multi-forge)](LICENSE)
50
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
47
51
 
48
52
  > [!WARNING]
49
53
  > **Research Preview** -- Forge is under active development. APIs, commands, and file formats may change without notice
@@ -92,7 +96,7 @@ Running `claude` directly bypasses session tracking. When you launch through For
92
96
  | Hook-driven artifacts | No | Yes -- plan snapshots, transcript capture |
93
97
  | Policy enforcement | No | Yes -- TDD, coding standards, supervisor |
94
98
  | Search across sessions | No | Yes -- `forge search` indexes transcripts |
95
- | Handoff agent | No | Yes -- auto-updates project docs on exit |
99
+ | Project memory | No | Yes -- passported docs auto-updated on exit |
96
100
 
97
101
  Even without a proxy, `forge session start` gives you session tracking, hooks, and the status line (direct mode is the
98
102
  default). The proxy adds multi-model routing on top. (`forge claude start` is also available as a bare launcher with
@@ -205,9 +209,10 @@ inside Claude Code for an interactive walkthrough.
205
209
  | ---------------------- | -------------------------------------------- |
206
210
  | `forge claude` | Bare launch, settings preset management |
207
211
  | `forge session` | Named sessions, worktrees, resume, fork |
212
+ | `forge memory` | Project memory passports, shadow proposals |
208
213
  | `forge proxy` | Model routing, templates, tier mappings |
209
214
  | `forge authentication` | Credential management (`credentials.yaml`) |
210
- | `forge guard` | Policy enforcement, plan supervision |
215
+ | `forge policy` | Policy enforcement, plan supervision |
211
216
  | `forge workflow` | Workflow runners (panel, analyze, debate) |
212
217
  | `forge search` | Transcript search across sessions |
213
218
  | `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
@@ -218,11 +223,12 @@ Run `forge <command> --help` for details on any command.
218
223
 
219
224
  ## Documentation
220
225
 
221
- | Audience | Location | Contents |
222
- | ---------------- | ---------------------------------- | ------------------------------------------------- |
223
- | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
224
- | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
225
- | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
226
+ | Audience | Location | Contents |
227
+ | ---------------- | ---------------------------------- | ---------------------------------------------------- |
228
+ | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
229
+ | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
230
+ | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
231
+ | **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
226
232
 
227
233
  ## Contributing
228
234
 
@@ -1,8 +1,12 @@
1
1
  # Multi-Forge
2
2
 
3
+ <p align="left">
4
+ <img src="assets/logo.jpg" alt="Dusk" width=240">
5
+ </p>
6
+
3
7
  [![PyPI](https://img.shields.io/pypi/v/multi-forge)](https://pypi.org/project/multi-forge/)
4
8
  [![Python](https://img.shields.io/pypi/pyversions/multi-forge)](https://pypi.org/project/multi-forge/)
5
- [![License](https://img.shields.io/github/license/hapa1i/multi-forge)](LICENSE)
9
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)
6
10
 
7
11
  > [!WARNING]
8
12
  > **Research Preview** -- Forge is under active development. APIs, commands, and file formats may change without notice
@@ -51,7 +55,7 @@ Running `claude` directly bypasses session tracking. When you launch through For
51
55
  | Hook-driven artifacts | No | Yes -- plan snapshots, transcript capture |
52
56
  | Policy enforcement | No | Yes -- TDD, coding standards, supervisor |
53
57
  | Search across sessions | No | Yes -- `forge search` indexes transcripts |
54
- | Handoff agent | No | Yes -- auto-updates project docs on exit |
58
+ | Project memory | No | Yes -- passported docs auto-updated on exit |
55
59
 
56
60
  Even without a proxy, `forge session start` gives you session tracking, hooks, and the status line (direct mode is the
57
61
  default). The proxy adds multi-model routing on top. (`forge claude start` is also available as a bare launcher with
@@ -164,9 +168,10 @@ inside Claude Code for an interactive walkthrough.
164
168
  | ---------------------- | -------------------------------------------- |
165
169
  | `forge claude` | Bare launch, settings preset management |
166
170
  | `forge session` | Named sessions, worktrees, resume, fork |
171
+ | `forge memory` | Project memory passports, shadow proposals |
167
172
  | `forge proxy` | Model routing, templates, tier mappings |
168
173
  | `forge authentication` | Credential management (`credentials.yaml`) |
169
- | `forge guard` | Policy enforcement, plan supervision |
174
+ | `forge policy` | Policy enforcement, plan supervision |
170
175
  | `forge workflow` | Workflow runners (panel, analyze, debate) |
171
176
  | `forge search` | Transcript search across sessions |
172
177
  | `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
@@ -177,11 +182,12 @@ Run `forge <command> --help` for details on any command.
177
182
 
178
183
  ## Documentation
179
184
 
180
- | Audience | Location | Contents |
181
- | ---------------- | ---------------------------------- | ------------------------------------------------- |
182
- | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
183
- | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
184
- | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
185
+ | Audience | Location | Contents |
186
+ | ---------------- | ---------------------------------- | ---------------------------------------------------- |
187
+ | **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
188
+ | **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
189
+ | **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
190
+ | **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
185
191
 
186
192
  ## Contributing
187
193
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "multi-forge"
3
- version = "0.2.1"
3
+ version = "0.4.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"
@@ -104,10 +104,9 @@ markers = [
104
104
  asyncio_mode = "auto"
105
105
 
106
106
  [tool.mypy]
107
- # qa/ ships a copy of walkthrough-state.py generated from the walkthrough/ copy
108
- # by scripts/sync-walkthrough-state.py (pre-commit) and verified by
109
- # test_walkthrough_state_sync.py. Exclude it to avoid a duplicate-module
110
- # collision; the walkthrough/ copy is the one type-checked.
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.
111
110
  exclude = [
112
111
  'src/skills/qa/scripts/walkthrough-state\.py$',
113
112
  ]
@@ -123,10 +122,11 @@ disallow_untyped_calls = false
123
122
  constraint-dependencies = [
124
123
  "filelock>=3.20.3",
125
124
  "virtualenv>=20.36.1",
126
- "aiohttp>=3.13.4",
125
+ "aiohttp>=3.14.0",
127
126
  "cryptography>=46.0.7",
128
127
  "python-multipart>=0.0.26",
129
128
  "Pygments>=2.20.0",
129
+ "starlette>=1.0.1",
130
130
  ]
131
131
  # litellm pins fastapi-sso<0.17.0 but 0.16.x has a CSRF vulnerability.
132
132
  # Forge doesn't use fastapi-sso directly; override to force the patched version.
@@ -149,6 +149,7 @@ dev = [
149
149
  "types-PyYAML>=6.0.0",
150
150
  "types-requests>=2.31.0",
151
151
  "python-dotenv>=1.2.1",
152
+ "httpx2>=2.3.0",
152
153
  ]
153
154
  provider-check = [
154
155
  "anthropic>=0.100.0",
@@ -1,3 +1,3 @@
1
1
  """Multi-Forge - Multi-runtime agent toolkit."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.4.0"
@@ -0,0 +1,151 @@
1
+ """``forge activity`` — per-session Forge *automation* activity (supervisor, memory
2
+ writer, workflow verbs) + policy decisions. NOT your full interactive Claude usage.
3
+
4
+ Reads the two already-captured planes (usage ledger + ``confirmed.policy.decisions``)
5
+ via :func:`forge.core.ops.usage_summary.build_session_activity_summary` and renders a
6
+ table. Cost is reported-or-estimated (best-effort attribution) — ``forge proxy costs show``
7
+ stays the authoritative spend view.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import sys
14
+ from dataclasses import asdict
15
+ from datetime import datetime, timedelta, timezone
16
+
17
+ import click
18
+ from rich.console import Console
19
+ from rich.table import Table
20
+
21
+ from forge.cli.output import print_error_with_tip
22
+ from forge.core.ops.session_context import (
23
+ SessionContextError,
24
+ resolve_session_identifier,
25
+ )
26
+ from forge.core.ops.usage_summary import (
27
+ SessionActivitySummary,
28
+ build_session_activity_summary,
29
+ )
30
+
31
+ console = Console()
32
+
33
+
34
+ @click.command("activity")
35
+ @click.argument("session", required=False)
36
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
37
+ @click.option("--days", "-d", type=int, default=30, help="Look back this many days (default: 30)")
38
+ @click.option("--all", "all_time", is_flag=True, help="Report all time (ignore --days)")
39
+ def activity_cmd(session: str | None, as_json: bool, days: int, all_time: bool) -> None:
40
+ """Show Forge's automation activity for a session: supervisor checks, cost, tokens.
41
+
42
+ This is what Forge did *on top of* your session — the supervisor, memory writer,
43
+ and workflow verbs (panel/debate/...) — plus policy decisions. It is **not** your
44
+ full interactive Claude usage. Reads the usage ledger and the session's
45
+ policy-decision log. Cost is reported-or-estimated (best-effort attribution);
46
+ 'forge proxy costs show' is the authoritative spend view.
47
+
48
+ \b
49
+ Examples:
50
+ forge activity # current session ($FORGE_SESSION)
51
+ forge activity planner # a named session (or Claude UUID)
52
+ forge activity --all --json # full history, JSON
53
+ """
54
+ try:
55
+ session_name, forge_root = resolve_session_identifier(session)
56
+ except SessionContextError as e:
57
+ if as_json:
58
+ click.echo(json.dumps({"error": str(e)}))
59
+ else:
60
+ print_error_with_tip(
61
+ str(e),
62
+ "Run 'forge session list' to see sessions.",
63
+ console=console,
64
+ )
65
+ sys.exit(1)
66
+
67
+ since = None if all_time else datetime.now(timezone.utc) - timedelta(days=days)
68
+ summary = build_session_activity_summary(session_name, forge_root, since=since)
69
+
70
+ if as_json:
71
+ console.print_json(data=asdict(summary))
72
+ return
73
+ _render(summary, days=None if all_time else days)
74
+
75
+
76
+ def _render(summary: SessionActivitySummary, *, days: int | None) -> None:
77
+ scope = "all time" if days is None else f"last {days}d"
78
+ if summary.is_empty:
79
+ console.print(f"[dim]No Forge activity for session '{summary.session}' ({scope}).[/dim]")
80
+ return
81
+
82
+ console.print(f"\n[bold]Forge activity — {summary.session}[/bold] [dim]({scope})[/dim]")
83
+ console.print(
84
+ "[dim]Forge automation (supervisor, memory writer, workflow verbs) — "
85
+ "not your full interactive session.[/dim]"
86
+ )
87
+
88
+ if summary.commands:
89
+ # The Workers column only earns its width when a fan-out (panel/debate/...) ran;
90
+ # supervisor/memory-writer have no workers, so most sessions skip it.
91
+ show_workers = any(c.workers for c in summary.commands)
92
+ table = Table(show_header=True, header_style="bold", box=None, padding=(0, 2))
93
+ table.add_column("Command", style="cyan")
94
+ table.add_column("Calls", justify="right")
95
+ if show_workers:
96
+ table.add_column("Workers", justify="right", style="dim")
97
+ table.add_column("Errors", justify="right")
98
+ table.add_column("Tokens in/out", justify="right", style="dim")
99
+ table.add_column("Cost", justify="right", style="dim")
100
+ for c in summary.commands:
101
+ errors = f"[red]{c.errors}[/red]" if c.errors else "0"
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 "-"
104
+ row = [c.command, str(c.calls)]
105
+ if show_workers:
106
+ row.append(str(c.workers) if c.workers else "-")
107
+ row += [errors, tokens, cost]
108
+ table.add_row(*row)
109
+ console.print(table)
110
+
111
+ pol = summary.policy
112
+ if pol and pol.has_content:
113
+ console.print(
114
+ f"\n[bold]Supervisor[/bold]: {pol.supervisor_allow} allow · "
115
+ f"{pol.supervisor_warn} warn · {pol.supervisor_deny} block"
116
+ )
117
+ for warning in pol.recent_warnings:
118
+ console.print(f" [yellow]•[/yellow] {warning}")
119
+
120
+ if summary.subagents:
121
+ console.print(f"\n[bold]Subagents[/bold]: {summary.subagents}")
122
+
123
+ total_cost = f"~{_fmt_usd(summary.total_cost_micro_usd)}" if summary.total_cost_micro_usd is not None else "n/a"
124
+ console.print(
125
+ f"\n[dim]Total:[/dim] {summary.total_events} events · "
126
+ f"{summary.total_input_tokens}/{summary.total_output_tokens} tok · {total_cost}"
127
+ )
128
+
129
+ for note in _footnotes(summary):
130
+ console.print(f"[dim]{note}[/dim]")
131
+
132
+
133
+ def _footnotes(summary: SessionActivitySummary) -> list[str]:
134
+ notes: list[str] = []
135
+ if summary.cost_partial:
136
+ notes.append("cost is best-effort and partial (some calls report no cost)")
137
+ if summary.policy is not None and summary.policy.log_capped:
138
+ notes.append("policy decision log is at capacity — older decisions may not be shown")
139
+ if summary.session_tagging_partial:
140
+ 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")
142
+ return notes
143
+
144
+
145
+ def _fmt_usd(micros: int | None) -> str:
146
+ if micros is None:
147
+ return "-"
148
+ dollars = micros / 1_000_000
149
+ if dollars and abs(dollars) < 0.01:
150
+ return f"${dollars:.4f}"
151
+ return f"${dollars:.2f}"
@@ -408,8 +408,7 @@ def status(profile: str | None) -> None:
408
408
  help="Profile to remove credentials from (default: 'default' or FORGE_PROFILE)",
409
409
  )
410
410
  @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
411
- @click.option("--force", "-f", is_flag=True, hidden=True, help="Deprecated alias for --yes")
412
- def logout(profile: str | None, yes: bool, force: bool) -> None:
411
+ def logout(profile: str | None, yes: bool) -> None:
413
412
  """Remove stored credentials for a profile.
414
413
 
415
414
  Deletes the profile from ~/.forge/credentials.yaml.
@@ -421,7 +420,6 @@ def logout(profile: str | None, yes: bool, force: bool) -> None:
421
420
  forge authentication logout --profile work
422
421
  forge authentication logout -y # Skip confirmation
423
422
  """
424
- yes = yes or force
425
423
  profile_name = resolve_profile(profile)
426
424
 
427
425
  if not yes:
@@ -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}"
@@ -244,8 +251,7 @@ def stop_cmd(adapter: str, port: int) -> None:
244
251
  help="Delete specific instance (if not specified, deletes config)",
245
252
  )
246
253
  @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
247
- @click.option("--force", "-f", is_flag=True, hidden=True, help="Deprecated alias for --yes")
248
- def delete_cmd(adapter: str, port: int | None, yes: bool, force: bool) -> None:
254
+ def delete_cmd(adapter: str, port: int | None, yes: bool) -> None:
249
255
  """Delete a backend instance or config.
250
256
 
251
257
  Without --port: Deletes the backend config (stops all instances first).
@@ -253,7 +259,6 @@ def delete_cmd(adapter: str, port: int | None, yes: bool, force: bool) -> None:
253
259
  """
254
260
  import shutil
255
261
 
256
- yes = yes or force
257
262
  console = Console(width=200)
258
263
 
259
264
  if port is not None:
@@ -271,7 +276,12 @@ def delete_cmd(adapter: str, port: int | None, yes: bool, force: bool) -> None:
271
276
  else:
272
277
  backend_dir = get_forge_home() / "backends" / adapter
273
278
  if not backend_dir.exists():
274
- console.print(f"[red]Error:[/red] Backend config not found for '{adapter}'")
279
+ print_error_with_tip(
280
+ f"Backend config not found for '{adapter}'",
281
+ "Create it first:",
282
+ commands=[f"forge backend create {adapter}"],
283
+ console=console,
284
+ )
275
285
  sys.exit(1)
276
286
 
277
287
  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,
@@ -391,13 +392,11 @@ def preset_edit() -> None:
391
392
 
392
393
  @preset.command("reset")
393
394
  @click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
394
- @click.option("--force", "-f", is_flag=True, hidden=True, help="Deprecated alias for --yes")
395
- def preset_reset(yes: bool, force: bool) -> None:
395
+ def preset_reset(yes: bool) -> None:
396
396
  """Reset settings preset to built-in defaults."""
397
397
  from forge.core.state import atomic_write_text
398
398
  from forge.install.preset import get_builtin_preset_json, get_preset_path
399
399
 
400
- yes = yes or force
401
400
  preset_path = get_preset_path()
402
401
 
403
402
  if not yes: