multi-forge 0.5.0__tar.gz → 0.7.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.
- {multi_forge-0.5.0 → multi_forge-0.7.0}/.gitignore +17 -2
- {multi_forge-0.5.0 → multi_forge-0.7.0}/PKG-INFO +40 -29
- {multi_forge-0.5.0 → multi_forge-0.7.0}/README.md +39 -28
- {multi_forge-0.5.0 → multi_forge-0.7.0}/pyproject.toml +11 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/__init__.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/backend/__init__.py +79 -34
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/backend/adapters/litellm.py +13 -13
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/backend/registry.py +46 -18
- multi_forge-0.7.0/src/forge/backend/remote/__init__.py +42 -0
- multi_forge-0.7.0/src/forge/backend/remote/base.py +124 -0
- multi_forge-0.7.0/src/forge/backend/remote/openrouter.py +184 -0
- multi_forge-0.7.0/src/forge/backend/sources.py +643 -0
- multi_forge-0.7.0/src/forge/cli/activity.py +277 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/auth.py +96 -30
- multi_forge-0.7.0/src/forge/cli/backend.py +1211 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/claude.py +52 -62
- multi_forge-0.7.0/src/forge/cli/codex.py +416 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/config_cmd.py +111 -55
- multi_forge-0.7.0/src/forge/cli/consumer_lane_freeze.py +67 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/editor.py +4 -4
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/extensions.py +103 -34
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/gc.py +12 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/guards.py +13 -17
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/_group.py +5 -4
- multi_forge-0.7.0/src/forge/cli/hooks/codex_patch.py +129 -0
- multi_forge-0.7.0/src/forge/cli/hooks/codex_policy.py +197 -0
- multi_forge-0.7.0/src/forge/cli/hooks/codex_transfer.py +113 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/commands.py +284 -23
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/direct_commands.py +194 -20
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/install.py +7 -3
- multi_forge-0.7.0/src/forge/cli/hooks/policy.py +449 -0
- multi_forge-0.7.0/src/forge/cli/hooks/protocols.py +57 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/logs.py +163 -53
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/main.py +85 -10
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/memory.py +120 -218
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/memory_report.py +70 -27
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/memory_writer.py +18 -1
- multi_forge-0.7.0/src/forge/cli/model.py +107 -0
- multi_forge-0.7.0/src/forge/cli/output.py +154 -0
- multi_forge-0.7.0/src/forge/cli/policy.py +1795 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/proxy.py +235 -178
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/proxy_audit.py +5 -5
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/proxy_costs.py +96 -89
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/runtime.py +95 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/search.py +228 -65
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/session.py +32 -299
- multi_forge-0.7.0/src/forge/cli/session_codex.py +487 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/session_fork.py +442 -332
- multi_forge-0.7.0/src/forge/cli/session_lane.py +309 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/session_lifecycle.py +692 -1082
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/session_manage.py +108 -181
- multi_forge-0.7.0/src/forge/cli/session_memory.py +265 -0
- multi_forge-0.7.0/src/forge/cli/session_model_pin.py +108 -0
- multi_forge-0.7.0/src/forge/cli/session_resume_modes.py +197 -0
- multi_forge-0.7.0/src/forge/cli/session_rewind.py +268 -0
- multi_forge-0.7.0/src/forge/cli/session_routing.py +19 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/status_line.py +29 -9
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/statusline/context.py +90 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/statusline/registry.py +5 -2
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/statusline/throttle.py +83 -1
- multi_forge-0.7.0/src/forge/cli/telemetry.py +19 -0
- multi_forge-0.7.0/src/forge/cli/trace.py +203 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/transfer.py +72 -26
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/workflow.py +171 -440
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/dataclass_utils.py +7 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/backends/litellm.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/anthropic-passthrough.yaml +3 -3
- multi_forge-0.7.0/src/forge/config/defaults/templates/codex-responses-local.yaml +27 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +9 -13
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +10 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +2 -8
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +1 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +1 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +1 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +2 -8
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +2 -8
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-openai.yaml +1 -0
- multi_forge-0.7.0/src/forge/config/defaults/templates/openrouter-anthropic.yaml +27 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +5 -5
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/loader.py +176 -90
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/schema.py +220 -24
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/auth/__init__.py +2 -4
- multi_forge-0.7.0/src/forge/core/auth/capabilities.py +123 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/auth/secrets.py +4 -61
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/auth/template_secrets.py +66 -24
- multi_forge-0.7.0/src/forge/core/backend_dependency.py +21 -0
- multi_forge-0.5.0/src/forge/core/auth/capabilities.py → multi_forge-0.7.0/src/forge/core/credential_registry.py +11 -102
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/data/model_catalog.yaml +85 -25
- multi_forge-0.7.0/src/forge/core/effort.py +39 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/invoker/_lifecycle.py +39 -2
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/invoker/claude.py +4 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/invoker/codex.py +51 -23
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/invoker/codex_stream.py +83 -6
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/invoker/types.py +9 -0
- multi_forge-0.7.0/src/forge/core/lanes.py +160 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/__init__.py +2 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/litellm.py +24 -4
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/openai_compat.py +76 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/openrouter.py +43 -5
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/credentials.py +2 -30
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/detection.py +1 -4
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/types.py +39 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/__init__.py +28 -0
- multi_forge-0.7.0/src/forge/core/ops/backend_reconcile.py +279 -0
- multi_forge-0.7.0/src/forge/core/ops/claude_session.py +1485 -0
- multi_forge-0.7.0/src/forge/core/ops/codex_bridge.py +393 -0
- multi_forge-0.7.0/src/forge/core/ops/codex_enrollment.py +307 -0
- multi_forge-0.7.0/src/forge/core/ops/codex_interactive.py +566 -0
- multi_forge-0.7.0/src/forge/core/ops/codex_session.py +589 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/context.py +9 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/gc.py +182 -16
- multi_forge-0.7.0/src/forge/core/ops/provider_trace.py +280 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/proxy.py +8 -6
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/resolution.py +3 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/session.py +20 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/session_context.py +14 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/ops/transfer.py +7 -5
- multi_forge-0.7.0/src/forge/core/ops/usage_summary.py +1226 -0
- multi_forge-0.7.0/src/forge/core/provider_types.py +13 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/cost_tracking.py +4 -106
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/env.py +150 -9
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/session_runner.py +36 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/tagger.py +30 -1
- multi_forge-0.7.0/src/forge/core/run_id.py +130 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/runtime/__init__.py +2 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/runtime/codex_preflight.py +115 -38
- multi_forge-0.7.0/src/forge/core/runtime/codex_preflight_cache.py +172 -0
- multi_forge-0.7.0/src/forge/core/runtime/codex_rollouts.py +187 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/runtime/registry.py +62 -37
- multi_forge-0.7.0/src/forge/core/runtime_vocab.py +28 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/state/__init__.py +2 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/state/exceptions.py +20 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/state/io.py +14 -5
- multi_forge-0.7.0/src/forge/core/telemetry/__init__.py +29 -0
- multi_forge-0.7.0/src/forge/core/telemetry/caps.py +86 -0
- multi_forge-0.7.0/src/forge/core/telemetry/downstream.py +338 -0
- multi_forge-0.7.0/src/forge/core/telemetry/upstream.py +222 -0
- multi_forge-0.7.0/src/forge/core/telemetry/vocabulary.py +52 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/usage/__init__.py +4 -0
- multi_forge-0.7.0/src/forge/core/usage/billing.py +67 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/usage/correlation.py +69 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/usage/emit.py +212 -154
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/usage/ledger.py +5 -6
- multi_forge-0.7.0/src/forge/core/usage/measurement.py +144 -0
- multi_forge-0.7.0/src/forge/core/usage/vocabulary.py +45 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/workqueue/__init__.py +2 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/workqueue/queue.py +51 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/cli.py +1 -1
- multi_forge-0.7.0/src/forge/install/codex_hooks.py +515 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/exceptions.py +20 -2
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/hooks.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/installer.py +126 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/models.py +33 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/preset.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/settings_merge.py +1 -46
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/tracking.py +3 -16
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/base.py +15 -8
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/coding_standards.py +3 -3
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/registry.py +6 -7
- multi_forge-0.7.0/src/forge/policy/engine.py +366 -0
- multi_forge-0.7.0/src/forge/policy/semantic/plan_check.py +638 -0
- multi_forge-0.7.0/src/forge/policy/semantic/shadow.py +295 -0
- multi_forge-0.7.0/src/forge/policy/semantic/shadow_runner.py +229 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/semantic/supervisor.py +541 -67
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/semantic/verdict.py +26 -20
- multi_forge-0.7.0/src/forge/policy/supervisor_lane_degrade.py +81 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/team/config.py +6 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/team/handlers.py +74 -5
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/types.py +17 -5
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/workflow/stages.py +125 -28
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/audit_logger.py +87 -117
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/client_adapter.py +41 -3
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/client_factory.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/converters.py +109 -16
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/cost_logger.py +79 -99
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/cost_tracker.py +117 -16
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/metrics.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/passthrough.py +103 -14
- multi_forge-0.7.0/src/forge/proxy/provider_trace_logger.py +307 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/proxies.py +13 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/proxy_orchestrator.py +281 -15
- multi_forge-0.7.0/src/forge/proxy/responses_ingress.py +266 -0
- multi_forge-0.7.0/src/forge/proxy/responses_passthrough.py +485 -0
- multi_forge-0.7.0/src/forge/proxy/retention.py +79 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/server.py +394 -31
- multi_forge-0.7.0/src/forge/proxy/stream_relay.py +99 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/utils.py +104 -8
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/__init__.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/adversarial.py +2 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/consensus.py +3 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/engine.py +11 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/models.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/runtime_config.py +327 -41
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/__init__.py +1 -3
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/engine.py +2 -52
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/extractor.py +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/index_state.py +10 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/store.py +9 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/active.py +25 -13
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/artifacts.py +8 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/claude/invoke.py +2 -0
- multi_forge-0.7.0/src/forge/session/codex_handoff.py +253 -0
- multi_forge-0.7.0/src/forge/session/codex_invoke.py +199 -0
- multi_forge-0.7.0/src/forge/session/consumer_lanes.py +266 -0
- multi_forge-0.7.0/src/forge/session/context_limit.py +103 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/direct_model.py +21 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/effective.py +2 -9
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/exceptions.py +53 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/hooks/session_start.py +12 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/index.py +3 -1
- multi_forge-0.7.0/src/forge/session/launch.py +204 -0
- {multi_forge-0.5.0/src/forge/cli → multi_forge-0.7.0/src/forge/session}/launch_confirmation.py +66 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/manager.py +53 -13
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/memory_writer.py +253 -25
- multi_forge-0.7.0/src/forge/session/model_pin.py +109 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/models.py +182 -6
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/overrides.py +22 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/passport.py +0 -10
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/prev_sessions.py +2 -25
- multi_forge-0.7.0/src/forge/session/rewind.py +659 -0
- multi_forge-0.7.0/src/forge/session/shadow_curation.py +535 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/store.py +36 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/transfer.py +95 -30
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/sidecar/container.py +47 -9
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/SKILL.md +2 -2
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/10-resume.md +11 -11
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/12-search.md +11 -5
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/13-policy.md +7 -7
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/16-memory.md +4 -4
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/17-info.md +8 -8
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/2-extension.md +44 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/20-cleanup.md +4 -6
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/3-authentication.md +21 -21
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/4-proxy.md +23 -21
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/5-session.md +63 -6
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/7-costs.md +72 -100
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/8-status-line.md +3 -3
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist.md +16 -12
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/report-template.md +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/walkthrough/SKILL.md +1 -1
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/walkthrough/resources/checklist.md +4 -4
- multi_forge-0.5.0/src/forge/cli/activity.py +0 -162
- multi_forge-0.5.0/src/forge/cli/backend.py +0 -308
- multi_forge-0.5.0/src/forge/cli/hooks/policy.py +0 -212
- multi_forge-0.5.0/src/forge/cli/hooks/protocols.py +0 -53
- multi_forge-0.5.0/src/forge/cli/output.py +0 -92
- multi_forge-0.5.0/src/forge/cli/policy.py +0 -1006
- multi_forge-0.5.0/src/forge/config/defaults/templates/openrouter-anthropic.yaml +0 -25
- multi_forge-0.5.0/src/forge/core/ops/codex_bridge.py +0 -244
- multi_forge-0.5.0/src/forge/core/ops/usage_summary.py +0 -466
- multi_forge-0.5.0/src/forge/core/run_id.py +0 -44
- multi_forge-0.5.0/src/forge/core/usage/billing.py +0 -28
- multi_forge-0.5.0/src/forge/core/usage/vocabulary.py +0 -70
- multi_forge-0.5.0/src/forge/policy/engine.py +0 -216
- multi_forge-0.5.0/src/forge/policy/semantic/promotion.py +0 -18
- multi_forge-0.5.0/src/forge/session/shadow_curation.py +0 -331
- {multi_forge-0.5.0 → multi_forge-0.7.0}/LICENSE +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/NOTICE +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/agents/.gitkeep +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/commands/.gitkeep +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/backend/adapters/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/backend/creation.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/_helpers.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/hooks/verification.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/statusline/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/statusline/names.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/cli/statusline/palette.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/backends/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/auth/credentials_file.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/auth/protocols.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/data/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/invoker/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/base.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/errors.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/llm/protocols.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/logging.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/models/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/models/catalog.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/models/types.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/naming.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/paths.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/process.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/headless_json.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/proxy.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/routing.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/structured_output.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/reactive/throttle.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/state/lock.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/state/timestamps.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/transcript.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/typing_helpers.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/core/workqueue/types.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/install/version.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/tdd.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/protocols.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/queries.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/semantic/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/store.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/team/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/team/prompts.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/workflow/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/workflow/branches.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/workflow/config.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/workflow/divergence.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/policy/workflow/policy.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/base_client.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/data_models.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/error_hints.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/intercept.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/model_spec.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/proxy_identity.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/proxy/proxy_startup.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/__init__.py +0 -0
- {multi_forge-0.5.0/src/skills/consensus → multi_forge-0.7.0/src/forge/review}/resources/code_consensus_evaluation.md +0 -0
- {multi_forge-0.5.0/src/skills/debate → multi_forge-0.7.0/src/forge/review}/resources/code_debate_evaluation.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview-performance.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview-quick.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview-security.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview.md +0 -0
- {multi_forge-0.5.0/src/skills/consensus → multi_forge-0.7.0/src/forge/review}/resources/consensus_evaluation.md +0 -0
- {multi_forge-0.5.0/src/skills/debate → multi_forge-0.7.0/src/forge/review}/resources/debate_evaluation.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/docreview-quick.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/docreview.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/resources/thinkdeep.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/routing.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/review/synthesis.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/bm25_store.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/content_store.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/exceptions.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/search/tokenizer.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/__init__.py +0 -0
- /multi_forge-0.5.0/src/forge/cli/session_addendum.py → /multi_forge-0.7.0/src/forge/session/addendum.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/claude/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/claude/cleanup.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/claude/paths.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/claude/relocate.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/cleanup.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/config.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/hooks/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/hooks/models.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/identity.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/memory_inheritance.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/plan_resolution.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/project_memory.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/validation.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/worktree/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/worktree/cleanup.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/worktree/config_copy.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/session/worktree/create.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/sidecar/__init__.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/sidecar/docker.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/forge/sidecar/secrets.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/analyze/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/challenge/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/consensus/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/consensus/resources/synthesis.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/debate/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/panel/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/panel/resources/synthesis.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/0-enable.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/11-config.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/15-skills.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/18-disable.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/19-uninstall.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/6-hook.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/9-direct-commands.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/scripts/start-container.sh +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/qa/scripts/walkthrough-state.py +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/references/claude-4.6.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/references/claude-4.8.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/references/gemini-3.1.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/references/gpt-5.5.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/references/skills-writing-guide.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/resources/code-anthropic.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/resources/code-gemini.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/resources/code-openai.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review/resources/code.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review-docs/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs-anthropic.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs-gemini.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs-openai.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/smoke-test/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/smoke-test/scripts/smoke-test.sh +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/SKILL.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/code-anthropic.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/code-gemini.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/code-openai.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/code.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs-anthropic.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs-gemini.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs-openai.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs.md +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/walkthrough/scripts/setup-test-repo.sh +0 -0
- {multi_forge-0.5.0 → multi_forge-0.7.0}/src/skills/walkthrough/scripts/walkthrough-state.py +0 -0
|
@@ -59,10 +59,25 @@ ipython_config.py
|
|
|
59
59
|
__pypackages__/
|
|
60
60
|
|
|
61
61
|
# Claude Code local artifacts (machine-specific)
|
|
62
|
-
.claude
|
|
62
|
+
.claude/*
|
|
63
|
+
!.claude/commands/
|
|
64
|
+
.claude/commands/*
|
|
65
|
+
!.claude/commands/gather-context.md
|
|
66
|
+
!.claude/commands/refactor_audit.md
|
|
67
|
+
!.claude/commands/simplicity_audit.md
|
|
68
|
+
|
|
69
|
+
# Codex local artifacts
|
|
70
|
+
.agents/*
|
|
71
|
+
!.agents/skills/
|
|
72
|
+
.agents/skills/*
|
|
73
|
+
!.agents/skills/gather-context/
|
|
74
|
+
!.agents/skills/gather-context/SKILL.md
|
|
75
|
+
!.agents/skills/refactor-audit/
|
|
76
|
+
!.agents/skills/refactor-audit/SKILL.md
|
|
77
|
+
!.agents/skills/simplicity-audit/
|
|
78
|
+
!.agents/skills/simplicity-audit/SKILL.md
|
|
63
79
|
|
|
64
80
|
# Codex local config
|
|
65
|
-
.agents
|
|
66
81
|
.codex/
|
|
67
82
|
|
|
68
83
|
# Forge local artifacts (machine-specific, may contain sensitive transcript snippets)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multi-forge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.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
|
|
@@ -56,15 +56,18 @@ Description-Content-Type: text/markdown
|
|
|
56
56
|
**Multi-runtime agent toolkit: proxy routing, cost control, session management, and policy enforcement for coding
|
|
57
57
|
agents.**
|
|
58
58
|
|
|
59
|
-
Forge sits between you and your coding agent (Claude Code
|
|
60
|
-
multi-provider model routing, cost visibility with spend caps, and autonomous
|
|
61
|
-
`forge session start` instead of `claude
|
|
62
|
-
state across sessions, and
|
|
59
|
+
Forge sits between you and your coding agent (Claude Code by default, with Codex as an alternate runtime and Gemini
|
|
60
|
+
next), adding persistent sessions, multi-provider model routing, cost visibility with spend caps, and autonomous
|
|
61
|
+
verification. You run `forge session start` instead of `claude`; Forge then routes to your chosen model provider, tracks
|
|
62
|
+
state across sessions, and enforces configured policies.
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
65
|
# Use Claude with session tracking (no proxy needed)
|
|
66
66
|
forge session start
|
|
67
67
|
|
|
68
|
+
# Or run a different runtime entirely -- Codex as an alternate frontend
|
|
69
|
+
forge session start --runtime codex # interactive TUI; hooks/policy need a one-time Codex trust enrollment
|
|
70
|
+
|
|
68
71
|
# Or route through different model providers (after creating proxies -- see Quick Start)
|
|
69
72
|
forge session start planner --proxy openrouter-openai # GPT for planning
|
|
70
73
|
forge session start --proxy openrouter-gemini # Gemini for review
|
|
@@ -146,7 +149,7 @@ forge extension enable
|
|
|
146
149
|
# Launch Claude with session tracking (no proxy needed)
|
|
147
150
|
forge session start
|
|
148
151
|
|
|
149
|
-
# Or with multi-model routing via OpenRouter (
|
|
152
|
+
# Or with multi-model routing via OpenRouter (no LiteLLM):
|
|
150
153
|
forge auth login -c openrouter # Store OPENROUTER_API_KEY
|
|
151
154
|
forge proxy create openrouter-anthropic # Create and start a Claude-family proxy
|
|
152
155
|
forge session start --proxy openrouter-anthropic
|
|
@@ -173,6 +176,12 @@ Existing pre-OSS Forge installs are not supported in-place. If upgrading:
|
|
|
173
176
|
4. If you had `FORGE_CONTEXT_LIMIT` in your shell config, remove it. Use `CLAUDE_CODE_AUTO_COMPACT_WINDOW` for native
|
|
174
177
|
Claude Code behavior, or `forge config set context_limit=N` for Forge proxy fallback.
|
|
175
178
|
|
|
179
|
+
> [!NOTE]
|
|
180
|
+
> **Corrupt state?** If Forge reports that its state is corrupt, it names the offending file and stops -- it never
|
|
181
|
+
> silently runs on bad state. To recover, run `forge clean` to detect and remove corrupt Forge-written state. For a full
|
|
182
|
+
> reset, delete `.forge` (project-local) or `~/.forge` (global) and re-run `forge extension enable`. Forge recreates
|
|
183
|
+
> whatever it needs on the next run. Your own files and `proxy.yaml` config are never touched by `forge clean`.
|
|
184
|
+
|
|
176
185
|
### Example Workflow: Plan, Execute, Review
|
|
177
186
|
|
|
178
187
|
With proxies configured, a typical feature workflow looks like:
|
|
@@ -198,37 +207,39 @@ forge session fork planner --into ../executor-worktree # Path to executor's wor
|
|
|
198
207
|
git push origin feature-branch
|
|
199
208
|
```
|
|
200
209
|
|
|
201
|
-
|
|
202
|
-
code change is checked against the approved plan. Sessions track artifacts and
|
|
203
|
-
|
|
204
|
-
inside Claude Code for an interactive walkthrough.
|
|
210
|
+
This workflow can assign different model roles to planning, execution, and review. The `--supervise` flag wires the
|
|
211
|
+
planner as a semantic supervisor -- every code change is checked against the approved plan. Sessions track artifacts and
|
|
212
|
+
transcripts automatically, so forks and resumes can reuse that context. See the [end-user guide](docs/end-user/) for the
|
|
213
|
+
full tour, or run `/forge:walkthrough` inside Claude Code for an interactive walkthrough.
|
|
205
214
|
|
|
206
215
|
## CLI Overview
|
|
207
216
|
|
|
208
|
-
| Command Group
|
|
209
|
-
|
|
|
210
|
-
| `forge claude`
|
|
211
|
-
| `forge session`
|
|
212
|
-
| `forge memory`
|
|
213
|
-
| `forge proxy`
|
|
214
|
-
| `forge
|
|
215
|
-
| `forge policy`
|
|
216
|
-
| `forge workflow`
|
|
217
|
-
| `forge search`
|
|
218
|
-
| `forge config`
|
|
219
|
-
| `forge extension`
|
|
220
|
-
| `forge info`
|
|
217
|
+
| Command Group | Purpose |
|
|
218
|
+
| ----------------- | -------------------------------------------- |
|
|
219
|
+
| `forge claude` | Bare launch, settings preset management |
|
|
220
|
+
| `forge session` | Named sessions, worktrees, resume, fork |
|
|
221
|
+
| `forge memory` | Project memory passports, shadow proposals |
|
|
222
|
+
| `forge proxy` | Model routing, templates, tier mappings |
|
|
223
|
+
| `forge auth` | Credential management (`credentials.yaml`) |
|
|
224
|
+
| `forge policy` | Policy enforcement, plan supervision |
|
|
225
|
+
| `forge workflow` | Workflow runners (panel, analyze, debate) |
|
|
226
|
+
| `forge search` | Transcript search across sessions |
|
|
227
|
+
| `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
|
|
228
|
+
| `forge extension` | Enable/sync/disable extensions |
|
|
229
|
+
| `forge info` | System health and installation info |
|
|
221
230
|
|
|
222
231
|
Run `forge <command> --help` for details on any command.
|
|
223
232
|
|
|
224
233
|
## Documentation
|
|
225
234
|
|
|
226
|
-
| Audience
|
|
227
|
-
|
|
|
228
|
-
| **Users**
|
|
229
|
-
| **Developers**
|
|
230
|
-
| **Architecture**
|
|
231
|
-
| **
|
|
235
|
+
| Audience | Location | Contents |
|
|
236
|
+
| ------------------- | ---------------------------------------------------- | ----------------------------------------------------- |
|
|
237
|
+
| **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
|
|
238
|
+
| **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
|
|
239
|
+
| **Architecture** | [docs/design.md](docs/design.md) | Core system narrative, data flow, invariants |
|
|
240
|
+
| **Workflow design** | [docs/design_workflows.md](docs/design_workflows.md) | Policy, skills, workflow runners, memory architecture |
|
|
241
|
+
| **CLI reference** | [docs/cli_reference.md](docs/cli_reference.md) | Terminal and direct-command inventory |
|
|
242
|
+
| **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
|
|
232
243
|
|
|
233
244
|
## Contributing
|
|
234
245
|
|
|
@@ -15,15 +15,18 @@
|
|
|
15
15
|
**Multi-runtime agent toolkit: proxy routing, cost control, session management, and policy enforcement for coding
|
|
16
16
|
agents.**
|
|
17
17
|
|
|
18
|
-
Forge sits between you and your coding agent (Claude Code
|
|
19
|
-
multi-provider model routing, cost visibility with spend caps, and autonomous
|
|
20
|
-
`forge session start` instead of `claude
|
|
21
|
-
state across sessions, and
|
|
18
|
+
Forge sits between you and your coding agent (Claude Code by default, with Codex as an alternate runtime and Gemini
|
|
19
|
+
next), adding persistent sessions, multi-provider model routing, cost visibility with spend caps, and autonomous
|
|
20
|
+
verification. You run `forge session start` instead of `claude`; Forge then routes to your chosen model provider, tracks
|
|
21
|
+
state across sessions, and enforces configured policies.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
24
|
# Use Claude with session tracking (no proxy needed)
|
|
25
25
|
forge session start
|
|
26
26
|
|
|
27
|
+
# Or run a different runtime entirely -- Codex as an alternate frontend
|
|
28
|
+
forge session start --runtime codex # interactive TUI; hooks/policy need a one-time Codex trust enrollment
|
|
29
|
+
|
|
27
30
|
# Or route through different model providers (after creating proxies -- see Quick Start)
|
|
28
31
|
forge session start planner --proxy openrouter-openai # GPT for planning
|
|
29
32
|
forge session start --proxy openrouter-gemini # Gemini for review
|
|
@@ -105,7 +108,7 @@ forge extension enable
|
|
|
105
108
|
# Launch Claude with session tracking (no proxy needed)
|
|
106
109
|
forge session start
|
|
107
110
|
|
|
108
|
-
# Or with multi-model routing via OpenRouter (
|
|
111
|
+
# Or with multi-model routing via OpenRouter (no LiteLLM):
|
|
109
112
|
forge auth login -c openrouter # Store OPENROUTER_API_KEY
|
|
110
113
|
forge proxy create openrouter-anthropic # Create and start a Claude-family proxy
|
|
111
114
|
forge session start --proxy openrouter-anthropic
|
|
@@ -132,6 +135,12 @@ Existing pre-OSS Forge installs are not supported in-place. If upgrading:
|
|
|
132
135
|
4. If you had `FORGE_CONTEXT_LIMIT` in your shell config, remove it. Use `CLAUDE_CODE_AUTO_COMPACT_WINDOW` for native
|
|
133
136
|
Claude Code behavior, or `forge config set context_limit=N` for Forge proxy fallback.
|
|
134
137
|
|
|
138
|
+
> [!NOTE]
|
|
139
|
+
> **Corrupt state?** If Forge reports that its state is corrupt, it names the offending file and stops -- it never
|
|
140
|
+
> silently runs on bad state. To recover, run `forge clean` to detect and remove corrupt Forge-written state. For a full
|
|
141
|
+
> reset, delete `.forge` (project-local) or `~/.forge` (global) and re-run `forge extension enable`. Forge recreates
|
|
142
|
+
> whatever it needs on the next run. Your own files and `proxy.yaml` config are never touched by `forge clean`.
|
|
143
|
+
|
|
135
144
|
### Example Workflow: Plan, Execute, Review
|
|
136
145
|
|
|
137
146
|
With proxies configured, a typical feature workflow looks like:
|
|
@@ -157,37 +166,39 @@ forge session fork planner --into ../executor-worktree # Path to executor's wor
|
|
|
157
166
|
git push origin feature-branch
|
|
158
167
|
```
|
|
159
168
|
|
|
160
|
-
|
|
161
|
-
code change is checked against the approved plan. Sessions track artifacts and
|
|
162
|
-
|
|
163
|
-
inside Claude Code for an interactive walkthrough.
|
|
169
|
+
This workflow can assign different model roles to planning, execution, and review. The `--supervise` flag wires the
|
|
170
|
+
planner as a semantic supervisor -- every code change is checked against the approved plan. Sessions track artifacts and
|
|
171
|
+
transcripts automatically, so forks and resumes can reuse that context. See the [end-user guide](docs/end-user/) for the
|
|
172
|
+
full tour, or run `/forge:walkthrough` inside Claude Code for an interactive walkthrough.
|
|
164
173
|
|
|
165
174
|
## CLI Overview
|
|
166
175
|
|
|
167
|
-
| Command Group
|
|
168
|
-
|
|
|
169
|
-
| `forge claude`
|
|
170
|
-
| `forge session`
|
|
171
|
-
| `forge memory`
|
|
172
|
-
| `forge proxy`
|
|
173
|
-
| `forge
|
|
174
|
-
| `forge policy`
|
|
175
|
-
| `forge workflow`
|
|
176
|
-
| `forge search`
|
|
177
|
-
| `forge config`
|
|
178
|
-
| `forge extension`
|
|
179
|
-
| `forge info`
|
|
176
|
+
| Command Group | Purpose |
|
|
177
|
+
| ----------------- | -------------------------------------------- |
|
|
178
|
+
| `forge claude` | Bare launch, settings preset management |
|
|
179
|
+
| `forge session` | Named sessions, worktrees, resume, fork |
|
|
180
|
+
| `forge memory` | Project memory passports, shadow proposals |
|
|
181
|
+
| `forge proxy` | Model routing, templates, tier mappings |
|
|
182
|
+
| `forge auth` | Credential management (`credentials.yaml`) |
|
|
183
|
+
| `forge policy` | Policy enforcement, plan supervision |
|
|
184
|
+
| `forge workflow` | Workflow runners (panel, analyze, debate) |
|
|
185
|
+
| `forge search` | Transcript search across sessions |
|
|
186
|
+
| `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
|
|
187
|
+
| `forge extension` | Enable/sync/disable extensions |
|
|
188
|
+
| `forge info` | System health and installation info |
|
|
180
189
|
|
|
181
190
|
Run `forge <command> --help` for details on any command.
|
|
182
191
|
|
|
183
192
|
## Documentation
|
|
184
193
|
|
|
185
|
-
| Audience
|
|
186
|
-
|
|
|
187
|
-
| **Users**
|
|
188
|
-
| **Developers**
|
|
189
|
-
| **Architecture**
|
|
190
|
-
| **
|
|
194
|
+
| Audience | Location | Contents |
|
|
195
|
+
| ------------------- | ---------------------------------------------------- | ----------------------------------------------------- |
|
|
196
|
+
| **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
|
|
197
|
+
| **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
|
|
198
|
+
| **Architecture** | [docs/design.md](docs/design.md) | Core system narrative, data flow, invariants |
|
|
199
|
+
| **Workflow design** | [docs/design_workflows.md](docs/design_workflows.md) | Policy, skills, workflow runners, memory architecture |
|
|
200
|
+
| **CLI reference** | [docs/cli_reference.md](docs/cli_reference.md) | Terminal and direct-command inventory |
|
|
201
|
+
| **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
|
|
191
202
|
|
|
192
203
|
## Contributing
|
|
193
204
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "multi-forge"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.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"
|
|
@@ -122,16 +122,20 @@ disallow_untyped_calls = false
|
|
|
122
122
|
constraint-dependencies = [
|
|
123
123
|
"filelock>=3.20.3",
|
|
124
124
|
"virtualenv>=20.36.1",
|
|
125
|
-
"aiohttp>=3.14.
|
|
126
|
-
"cryptography>=
|
|
127
|
-
"python-multipart>=0.0.
|
|
125
|
+
"aiohttp>=3.14.1",
|
|
126
|
+
"cryptography>=48.0.1",
|
|
127
|
+
"python-multipart>=0.0.31",
|
|
128
128
|
"Pygments>=2.20.0",
|
|
129
|
-
"
|
|
129
|
+
"PyJWT>=2.13.0",
|
|
130
|
+
"starlette>=1.3.1",
|
|
130
131
|
]
|
|
131
|
-
# litellm
|
|
132
|
-
# Forge doesn't use
|
|
132
|
+
# litellm proxy extras can pin vulnerable transitive dependencies before
|
|
133
|
+
# upstream metadata catches up. Forge doesn't use these directly; override to
|
|
134
|
+
# force patched versions required by Dependabot alerts.
|
|
133
135
|
override-dependencies = [
|
|
136
|
+
"cryptography>=48.0.1",
|
|
134
137
|
"fastapi-sso>=0.19.0",
|
|
138
|
+
"python-multipart>=0.0.31",
|
|
135
139
|
]
|
|
136
140
|
|
|
137
141
|
[dependency-groups]
|
|
@@ -12,17 +12,40 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Literal
|
|
13
13
|
|
|
14
14
|
from forge.backend.registry import (
|
|
15
|
-
|
|
15
|
+
ManagedBackendProcess,
|
|
16
16
|
BackendRegistry,
|
|
17
17
|
BackendRegistryStore,
|
|
18
18
|
)
|
|
19
|
+
from forge.backend.sources import (
|
|
20
|
+
BackendInstanceAmbiguousError,
|
|
21
|
+
BackendInstanceMatchKind,
|
|
22
|
+
BackendInstanceNotFoundError,
|
|
23
|
+
BackendInstanceResolution,
|
|
24
|
+
BackendInstanceResolutionError,
|
|
25
|
+
LocalBackendLifecycle,
|
|
26
|
+
ModelSource,
|
|
27
|
+
ModelSourceCapabilities,
|
|
28
|
+
ModelSourceCatalogError,
|
|
29
|
+
ModelSourceNotFoundError,
|
|
30
|
+
SourceEndpoint,
|
|
31
|
+
backend_kind_for_source,
|
|
32
|
+
get_model_source,
|
|
33
|
+
list_model_sources,
|
|
34
|
+
model_source_for_template,
|
|
35
|
+
required_env_vars_for_source,
|
|
36
|
+
resolve_backend_instance,
|
|
37
|
+
resolve_backend_instance_id,
|
|
38
|
+
resolve_model_source_id,
|
|
39
|
+
template_env_vars_by_template,
|
|
40
|
+
validate_model_sources,
|
|
41
|
+
)
|
|
19
42
|
|
|
20
43
|
|
|
21
44
|
@dataclass(frozen=True)
|
|
22
45
|
class BackendEnsureResult:
|
|
23
46
|
"""Result of ensure_backend() operation."""
|
|
24
47
|
|
|
25
|
-
|
|
48
|
+
process: ManagedBackendProcess
|
|
26
49
|
source: Literal["reuse", "start"]
|
|
27
50
|
|
|
28
51
|
|
|
@@ -30,35 +53,35 @@ class BackendAdapter(ABC):
|
|
|
30
53
|
"""Abstract base class for backend lifecycle management."""
|
|
31
54
|
|
|
32
55
|
@abstractmethod
|
|
33
|
-
def start(self,
|
|
34
|
-
"""Start backend, return
|
|
56
|
+
def start(self, process_id: str, config_path: Path, port: int) -> ManagedBackendProcess:
|
|
57
|
+
"""Start backend, return managed process details.
|
|
35
58
|
|
|
36
59
|
Args:
|
|
37
|
-
|
|
60
|
+
process_id: Managed process ID (e.g., "litellm-4000")
|
|
38
61
|
config_path: Path to backend config file
|
|
39
62
|
port: Port number to bind
|
|
40
63
|
|
|
41
64
|
Returns:
|
|
42
|
-
|
|
65
|
+
ManagedBackendProcess with PID and status
|
|
43
66
|
|
|
44
67
|
Raises:
|
|
45
68
|
BackendStartError: If backend fails to start
|
|
46
69
|
"""
|
|
47
70
|
|
|
48
71
|
@abstractmethod
|
|
49
|
-
def stop(self,
|
|
72
|
+
def stop(self, process: ManagedBackendProcess) -> None:
|
|
50
73
|
"""Stop backend (best effort).
|
|
51
74
|
|
|
52
75
|
Args:
|
|
53
|
-
|
|
76
|
+
process: Managed backend process to stop
|
|
54
77
|
"""
|
|
55
78
|
|
|
56
79
|
@abstractmethod
|
|
57
|
-
def health_check(self,
|
|
80
|
+
def health_check(self, process: ManagedBackendProcess) -> bool:
|
|
58
81
|
"""Check if backend is healthy.
|
|
59
82
|
|
|
60
83
|
Args:
|
|
61
|
-
|
|
84
|
+
process: Managed backend process to check
|
|
62
85
|
|
|
63
86
|
Returns:
|
|
64
87
|
True if healthy, False otherwise
|
|
@@ -90,16 +113,16 @@ class BackendManager:
|
|
|
90
113
|
"""
|
|
91
114
|
self.adapters[adapter_type] = adapter
|
|
92
115
|
|
|
93
|
-
def ensure_backend(self,
|
|
116
|
+
def ensure_backend(self, process_id: str, adapter_type: str, port: int) -> BackendEnsureResult:
|
|
94
117
|
"""Ensure backend is running (reuse -> start pattern).
|
|
95
118
|
|
|
96
119
|
Args:
|
|
97
|
-
|
|
120
|
+
process_id: Managed process ID (e.g., "litellm-4000")
|
|
98
121
|
adapter_type: Adapter type (e.g., "litellm")
|
|
99
122
|
port: Port number
|
|
100
123
|
|
|
101
124
|
Returns:
|
|
102
|
-
BackendEnsureResult with
|
|
125
|
+
BackendEnsureResult with process and source ("reuse" or "start")
|
|
103
126
|
|
|
104
127
|
Raises:
|
|
105
128
|
BackendStartError: If backend fails to start
|
|
@@ -111,64 +134,86 @@ class BackendManager:
|
|
|
111
134
|
raise ValueError(f"No adapter registered for type: {adapter_type}")
|
|
112
135
|
|
|
113
136
|
registry = self.registry_store.read()
|
|
114
|
-
existing = registry.
|
|
137
|
+
existing = registry.processes.get(process_id)
|
|
115
138
|
|
|
116
139
|
if existing:
|
|
117
140
|
# health_check works with or without PID (port probe fallback)
|
|
118
141
|
if adapter.health_check(existing):
|
|
119
|
-
return BackendEnsureResult(
|
|
142
|
+
return BackendEnsureResult(process=existing, source="reuse")
|
|
120
143
|
|
|
121
144
|
def remove_dead(reg: BackendRegistry) -> None:
|
|
122
|
-
reg.
|
|
145
|
+
reg.processes.pop(process_id, None)
|
|
123
146
|
|
|
124
147
|
self.registry_store.update(timeout_s=10.0, mutate=remove_dead)
|
|
125
148
|
|
|
126
149
|
config_path = get_backend_config_path(adapter_type)
|
|
127
150
|
if not config_path.exists():
|
|
128
151
|
raise BackendStartError(
|
|
129
|
-
f"Backend config not found: {config_path}\n"
|
|
152
|
+
f"Backend config not found: {config_path}\n"
|
|
153
|
+
f"Create it with: forge model backend create {adapter_type}"
|
|
130
154
|
)
|
|
131
155
|
|
|
132
|
-
|
|
156
|
+
process = adapter.start(process_id, config_path, port)
|
|
133
157
|
|
|
134
|
-
def
|
|
135
|
-
reg.
|
|
158
|
+
def add_process(reg: BackendRegistry) -> None:
|
|
159
|
+
reg.processes[process_id] = process
|
|
136
160
|
|
|
137
|
-
self.registry_store.update(timeout_s=10.0, mutate=
|
|
161
|
+
self.registry_store.update(timeout_s=10.0, mutate=add_process)
|
|
138
162
|
|
|
139
|
-
return BackendEnsureResult(
|
|
163
|
+
return BackendEnsureResult(process=process, source="start")
|
|
140
164
|
|
|
141
|
-
def stop_backend(self,
|
|
165
|
+
def stop_backend(self, process_id: str) -> None:
|
|
142
166
|
"""Stop backend and remove from registry.
|
|
143
167
|
|
|
144
168
|
Args:
|
|
145
|
-
|
|
169
|
+
process_id: Managed process ID
|
|
146
170
|
|
|
147
171
|
Raises:
|
|
148
|
-
ValueError: If
|
|
172
|
+
ValueError: If managed process not found
|
|
149
173
|
"""
|
|
150
174
|
registry = self.registry_store.read()
|
|
151
|
-
|
|
175
|
+
process = registry.processes.get(process_id)
|
|
152
176
|
|
|
153
|
-
if not
|
|
154
|
-
raise ValueError(f"
|
|
177
|
+
if not process:
|
|
178
|
+
raise ValueError(f"Managed process not found: {process_id}")
|
|
155
179
|
|
|
156
|
-
adapter = self.adapters.get(
|
|
180
|
+
adapter = self.adapters.get(process.adapter_type)
|
|
157
181
|
if adapter:
|
|
158
|
-
adapter.stop(
|
|
182
|
+
adapter.stop(process)
|
|
159
183
|
|
|
160
|
-
def
|
|
161
|
-
reg.
|
|
184
|
+
def remove_process(reg: BackendRegistry) -> None:
|
|
185
|
+
reg.processes.pop(process_id, None)
|
|
162
186
|
|
|
163
|
-
self.registry_store.update(timeout_s=10.0, mutate=
|
|
187
|
+
self.registry_store.update(timeout_s=10.0, mutate=remove_process)
|
|
164
188
|
|
|
165
189
|
|
|
166
190
|
__all__ = [
|
|
167
191
|
"BackendAdapter",
|
|
168
192
|
"BackendEnsureResult",
|
|
169
|
-
"
|
|
193
|
+
"BackendInstanceAmbiguousError",
|
|
194
|
+
"ManagedBackendProcess",
|
|
195
|
+
"BackendInstanceMatchKind",
|
|
170
196
|
"BackendManager",
|
|
197
|
+
"BackendInstanceNotFoundError",
|
|
198
|
+
"BackendInstanceResolution",
|
|
199
|
+
"BackendInstanceResolutionError",
|
|
171
200
|
"BackendRegistry",
|
|
172
201
|
"BackendRegistryStore",
|
|
173
202
|
"BackendStartError",
|
|
203
|
+
"LocalBackendLifecycle",
|
|
204
|
+
"ModelSource",
|
|
205
|
+
"ModelSourceCapabilities",
|
|
206
|
+
"ModelSourceCatalogError",
|
|
207
|
+
"ModelSourceNotFoundError",
|
|
208
|
+
"SourceEndpoint",
|
|
209
|
+
"backend_kind_for_source",
|
|
210
|
+
"get_model_source",
|
|
211
|
+
"list_model_sources",
|
|
212
|
+
"model_source_for_template",
|
|
213
|
+
"required_env_vars_for_source",
|
|
214
|
+
"resolve_backend_instance",
|
|
215
|
+
"resolve_backend_instance_id",
|
|
216
|
+
"resolve_model_source_id",
|
|
217
|
+
"template_env_vars_by_template",
|
|
218
|
+
"validate_model_sources",
|
|
174
219
|
]
|
|
@@ -19,7 +19,7 @@ from pathlib import Path
|
|
|
19
19
|
import httpx
|
|
20
20
|
|
|
21
21
|
from forge.backend import BackendAdapter, BackendStartError
|
|
22
|
-
from forge.backend.registry import
|
|
22
|
+
from forge.backend.registry import ManagedBackendProcess
|
|
23
23
|
from forge.core.paths import get_forge_home
|
|
24
24
|
from forge.core.state import now_iso
|
|
25
25
|
|
|
@@ -67,16 +67,16 @@ class LiteLLMAdapter(BackendAdapter):
|
|
|
67
67
|
|
|
68
68
|
return False
|
|
69
69
|
|
|
70
|
-
def start(self,
|
|
70
|
+
def start(self, process_id: str, config_path: Path, port: int) -> ManagedBackendProcess:
|
|
71
71
|
"""Start LiteLLM backend.
|
|
72
72
|
|
|
73
73
|
Args:
|
|
74
|
-
|
|
74
|
+
process_id: Managed process ID (e.g., "litellm-4000")
|
|
75
75
|
config_path: Path to LiteLLM config file
|
|
76
76
|
port: Port number to bind
|
|
77
77
|
|
|
78
78
|
Returns:
|
|
79
|
-
|
|
79
|
+
ManagedBackendProcess with PID and status
|
|
80
80
|
|
|
81
81
|
Raises:
|
|
82
82
|
BackendStartError: If backend fails to start
|
|
@@ -114,8 +114,8 @@ class LiteLLMAdapter(BackendAdapter):
|
|
|
114
114
|
pass # Process already exited
|
|
115
115
|
raise BackendStartError(f"LiteLLM failed to start on port {port}\nCheck logs: {log_file}")
|
|
116
116
|
|
|
117
|
-
return
|
|
118
|
-
|
|
117
|
+
return ManagedBackendProcess(
|
|
118
|
+
process_id=process_id,
|
|
119
119
|
adapter_type="litellm",
|
|
120
120
|
port=port,
|
|
121
121
|
pid=proc.pid,
|
|
@@ -123,34 +123,34 @@ class LiteLLMAdapter(BackendAdapter):
|
|
|
123
123
|
created_at=now_iso(),
|
|
124
124
|
)
|
|
125
125
|
|
|
126
|
-
def stop(self,
|
|
126
|
+
def stop(self, process: ManagedBackendProcess) -> None:
|
|
127
127
|
"""Stop LiteLLM backend (best effort).
|
|
128
128
|
|
|
129
129
|
Args:
|
|
130
|
-
|
|
130
|
+
process: Managed backend process to stop
|
|
131
131
|
"""
|
|
132
|
-
if
|
|
132
|
+
if process.pid is None:
|
|
133
133
|
return
|
|
134
134
|
|
|
135
135
|
try:
|
|
136
|
-
os.kill(
|
|
136
|
+
os.kill(process.pid, 15) # SIGTERM
|
|
137
137
|
except (ProcessLookupError, PermissionError):
|
|
138
138
|
pass
|
|
139
139
|
|
|
140
|
-
def health_check(self,
|
|
140
|
+
def health_check(self, process: ManagedBackendProcess) -> bool:
|
|
141
141
|
"""Check if LiteLLM backend is healthy.
|
|
142
142
|
|
|
143
143
|
Uses /health/liveliness for fast checks (~5ms) rather than the full
|
|
144
144
|
/health endpoint which contacts all model providers (~5-10s).
|
|
145
145
|
|
|
146
146
|
Args:
|
|
147
|
-
|
|
147
|
+
process: Managed backend process to check
|
|
148
148
|
|
|
149
149
|
Returns:
|
|
150
150
|
True if healthy, False otherwise
|
|
151
151
|
"""
|
|
152
152
|
try:
|
|
153
|
-
url = f"http://localhost:{
|
|
153
|
+
url = f"http://localhost:{process.port}/health/liveliness"
|
|
154
154
|
with httpx.Client(timeout=httpx.Timeout(2.0)) as client:
|
|
155
155
|
response = client.get(url)
|
|
156
156
|
return response.status_code == 200
|