multi-forge 0.6.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.6.0 → multi_forge-0.7.0}/.gitignore +17 -2
- {multi_forge-0.6.0 → multi_forge-0.7.0}/PKG-INFO +27 -21
- {multi_forge-0.6.0 → multi_forge-0.7.0}/README.md +26 -20
- {multi_forge-0.6.0 → multi_forge-0.7.0}/pyproject.toml +11 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/__init__.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/backend/__init__.py +79 -34
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/backend/adapters/litellm.py +13 -13
- {multi_forge-0.6.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.6.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.6.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.6.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.6.0 → multi_forge-0.7.0}/src/forge/cli/editor.py +4 -4
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/extensions.py +34 -26
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/gc.py +12 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/guards.py +13 -17
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/commands.py +63 -6
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/direct_commands.py +86 -24
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/install.py +7 -3
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/policy.py +140 -6
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/logs.py +163 -53
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/main.py +85 -10
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/memory.py +120 -218
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/memory_report.py +70 -27
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/cli/proxy.py +235 -178
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/proxy_audit.py +5 -5
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/proxy_costs.py +96 -89
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/runtime.py +34 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/search.py +228 -65
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/session.py +32 -299
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/session_codex.py +35 -37
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/session_fork.py +419 -335
- multi_forge-0.7.0/src/forge/cli/session_lane.py +309 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/session_lifecycle.py +653 -955
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/session_manage.py +78 -178
- multi_forge-0.7.0/src/forge/cli/session_memory.py +265 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/session_model_pin.py +2 -90
- 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.6.0 → multi_forge-0.7.0}/src/forge/cli/status_line.py +29 -9
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/statusline/context.py +90 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/statusline/registry.py +5 -2
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/cli/transfer.py +72 -26
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/workflow.py +171 -440
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/dataclass_utils.py +7 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/backends/litellm.yaml +1 -1
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +9 -13
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +10 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +2 -8
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +1 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +1 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +1 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +2 -8
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +2 -8
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +5 -5
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/loader.py +176 -90
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/schema.py +220 -24
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/core/auth/secrets.py +4 -61
- {multi_forge-0.6.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.6.0/src/forge/core/auth/capabilities.py → multi_forge-0.7.0/src/forge/core/credential_registry.py +11 -102
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/core/invoker/_lifecycle.py +39 -2
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/invoker/claude.py +4 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/invoker/codex.py +4 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/invoker/codex_stream.py +60 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/invoker/types.py +4 -0
- multi_forge-0.7.0/src/forge/core/lanes.py +160 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/__init__.py +2 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/litellm.py +24 -4
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/openai_compat.py +76 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/openrouter.py +43 -5
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/credentials.py +2 -30
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/detection.py +1 -4
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/types.py +39 -1
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/core/ops/codex_bridge.py +11 -8
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/codex_enrollment.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/codex_interactive.py +10 -4
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/codex_session.py +14 -4
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/context.py +9 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/gc.py +164 -16
- multi_forge-0.7.0/src/forge/core/ops/provider_trace.py +280 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/proxy.py +8 -6
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/resolution.py +3 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/session.py +20 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/ops/session_context.py +14 -1
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/cost_tracking.py +4 -106
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/env.py +150 -9
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/session_runner.py +36 -0
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/core/runtime/__init__.py +2 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/runtime/codex_preflight.py +54 -9
- multi_forge-0.7.0/src/forge/core/runtime/codex_preflight_cache.py +172 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/runtime/registry.py +1 -1
- multi_forge-0.7.0/src/forge/core/runtime_vocab.py +28 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/state/__init__.py +2 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/state/exceptions.py +20 -0
- {multi_forge-0.6.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.6.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.6.0 → multi_forge-0.7.0}/src/forge/core/usage/correlation.py +69 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/usage/emit.py +212 -154
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/core/workqueue/__init__.py +2 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/workqueue/queue.py +51 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/cli.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/exceptions.py +20 -2
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/hooks.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/preset.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/settings_merge.py +1 -46
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/tracking.py +3 -16
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/coding_standards.py +3 -3
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/registry.py +6 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/engine.py +114 -16
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/semantic/plan_check.py +87 -10
- 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.6.0 → multi_forge-0.7.0}/src/forge/policy/semantic/supervisor.py +538 -64
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/policy/team/config.py +6 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/team/handlers.py +74 -5
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/types.py +9 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/workflow/stages.py +125 -28
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/audit_logger.py +87 -117
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/client_adapter.py +41 -3
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/client_factory.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/converters.py +109 -16
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/cost_logger.py +79 -99
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/cost_tracker.py +117 -16
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/metrics.py +1 -1
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/proxy/proxies.py +13 -1
- {multi_forge-0.6.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.6.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.6.0 → multi_forge-0.7.0}/src/forge/proxy/utils.py +104 -8
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/__init__.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/adversarial.py +2 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/consensus.py +3 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/engine.py +11 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/models.py +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/runtime_config.py +327 -41
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/__init__.py +1 -3
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/engine.py +2 -52
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/index_state.py +10 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/store.py +9 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/active.py +25 -13
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/artifacts.py +8 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/claude/invoke.py +2 -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.6.0 → multi_forge-0.7.0}/src/forge/session/direct_model.py +21 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/effective.py +2 -9
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/exceptions.py +40 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/hooks/session_start.py +12 -0
- {multi_forge-0.6.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.6.0/src/forge/cli → multi_forge-0.7.0/src/forge/session}/launch_confirmation.py +66 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/manager.py +36 -13
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/session/models.py +131 -5
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/overrides.py +13 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/passport.py +0 -10
- {multi_forge-0.6.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.6.0 → multi_forge-0.7.0}/src/forge/session/store.py +36 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/transfer.py +94 -29
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/sidecar/container.py +47 -9
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/SKILL.md +2 -2
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/10-resume.md +11 -11
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/12-search.md +11 -5
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/13-policy.md +7 -7
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/16-memory.md +4 -4
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/17-info.md +8 -8
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/2-extension.md +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/20-cleanup.md +4 -6
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/3-authentication.md +21 -21
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/4-proxy.md +23 -21
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/5-session.md +63 -6
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/7-costs.md +72 -100
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/8-status-line.md +3 -3
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist.md +15 -13
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/report-template.md +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/walkthrough/SKILL.md +1 -1
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/walkthrough/resources/checklist.md +4 -4
- multi_forge-0.6.0/src/forge/cli/activity.py +0 -168
- multi_forge-0.6.0/src/forge/cli/backend.py +0 -308
- multi_forge-0.6.0/src/forge/cli/output.py +0 -92
- multi_forge-0.6.0/src/forge/cli/policy.py +0 -1246
- multi_forge-0.6.0/src/forge/config/defaults/templates/openrouter-anthropic.yaml +0 -25
- multi_forge-0.6.0/src/forge/core/ops/usage_summary.py +0 -500
- multi_forge-0.6.0/src/forge/core/run_id.py +0 -44
- multi_forge-0.6.0/src/forge/core/usage/billing.py +0 -28
- multi_forge-0.6.0/src/forge/core/usage/vocabulary.py +0 -70
- multi_forge-0.6.0/src/forge/policy/semantic/promotion.py +0 -18
- multi_forge-0.6.0/src/forge/session/codex_invoke.py +0 -81
- multi_forge-0.6.0/src/forge/session/shadow_curation.py +0 -331
- {multi_forge-0.6.0 → multi_forge-0.7.0}/LICENSE +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/NOTICE +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/agents/.gitkeep +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/commands/.gitkeep +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/backend/adapters/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/backend/creation.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/_group.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/_helpers.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/codex_patch.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/codex_policy.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/codex_transfer.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/protocols.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/hooks/verification.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/statusline/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/statusline/names.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/cli/statusline/palette.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/backends/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/config/defaults/templates/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/auth/credentials_file.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/auth/protocols.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/data/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/invoker/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/clients/base.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/errors.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/llm/protocols.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/logging.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/models/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/models/catalog.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/models/types.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/naming.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/paths.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/process.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/headless_json.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/proxy.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/routing.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/structured_output.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/reactive/throttle.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/runtime/codex_rollouts.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/state/lock.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/state/timestamps.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/transcript.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/typing_helpers.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/core/workqueue/types.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/codex_hooks.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/installer.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/models.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/install/version.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/base.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/deterministic/tdd.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/protocols.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/queries.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/semantic/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/store.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/team/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/team/prompts.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/workflow/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/workflow/branches.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/workflow/config.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/workflow/divergence.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/policy/workflow/policy.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/base_client.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/data_models.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/error_hints.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/intercept.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/model_spec.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/proxy_identity.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/proxy/proxy_startup.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/__init__.py +0 -0
- {multi_forge-0.6.0/src/skills/consensus → multi_forge-0.7.0/src/forge/review}/resources/code_consensus_evaluation.md +0 -0
- {multi_forge-0.6.0/src/skills/debate → multi_forge-0.7.0/src/forge/review}/resources/code_debate_evaluation.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview-performance.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview-quick.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview-security.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/codereview.md +0 -0
- {multi_forge-0.6.0/src/skills/consensus → multi_forge-0.7.0/src/forge/review}/resources/consensus_evaluation.md +0 -0
- {multi_forge-0.6.0/src/skills/debate → multi_forge-0.7.0/src/forge/review}/resources/debate_evaluation.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/docreview-quick.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/docreview.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/resources/thinkdeep.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/routing.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/review/synthesis.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/bm25_store.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/content_store.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/exceptions.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/extractor.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/search/tokenizer.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/__init__.py +0 -0
- /multi_forge-0.6.0/src/forge/cli/session_addendum.py → /multi_forge-0.7.0/src/forge/session/addendum.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/claude/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/claude/cleanup.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/claude/paths.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/claude/relocate.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/cleanup.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/codex_handoff.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/config.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/hooks/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/hooks/models.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/identity.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/memory_inheritance.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/plan_resolution.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/project_memory.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/validation.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/worktree/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/worktree/cleanup.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/worktree/config_copy.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/session/worktree/create.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/sidecar/__init__.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/sidecar/docker.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/forge/sidecar/secrets.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/analyze/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/challenge/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/consensus/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/consensus/resources/synthesis.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/debate/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/panel/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/panel/resources/synthesis.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/0-enable.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/11-config.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/15-skills.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/18-disable.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/19-uninstall.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/6-hook.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/resources/checklist/9-direct-commands.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/scripts/start-container.sh +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/qa/scripts/walkthrough-state.py +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/references/claude-4.6.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/references/claude-4.8.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/references/gemini-3.1.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/references/gpt-5.5.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/references/skills-writing-guide.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/resources/code-anthropic.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/resources/code-gemini.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/resources/code-openai.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review/resources/code.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review-docs/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs-anthropic.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs-gemini.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs-openai.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/review-docs/resources/docs.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/smoke-test/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/smoke-test/scripts/smoke-test.sh +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/SKILL.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/code-anthropic.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/code-gemini.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/code-openai.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/code.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs-anthropic.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs-gemini.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs-openai.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/understand/resources/docs.md +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
- {multi_forge-0.6.0 → multi_forge-0.7.0}/src/skills/walkthrough/scripts/setup-test-repo.sh +0 -0
- {multi_forge-0.6.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
|
|
@@ -58,8 +58,8 @@ agents.**
|
|
|
58
58
|
|
|
59
59
|
Forge sits between you and your coding agent (Claude Code by default, with Codex as an alternate runtime and Gemini
|
|
60
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
|
|
62
|
-
|
|
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)
|
|
@@ -149,7 +149,7 @@ forge extension enable
|
|
|
149
149
|
# Launch Claude with session tracking (no proxy needed)
|
|
150
150
|
forge session start
|
|
151
151
|
|
|
152
|
-
# Or with multi-model routing via OpenRouter (
|
|
152
|
+
# Or with multi-model routing via OpenRouter (no LiteLLM):
|
|
153
153
|
forge auth login -c openrouter # Store OPENROUTER_API_KEY
|
|
154
154
|
forge proxy create openrouter-anthropic # Create and start a Claude-family proxy
|
|
155
155
|
forge session start --proxy openrouter-anthropic
|
|
@@ -176,6 +176,12 @@ Existing pre-OSS Forge installs are not supported in-place. If upgrading:
|
|
|
176
176
|
4. If you had `FORGE_CONTEXT_LIMIT` in your shell config, remove it. Use `CLAUDE_CODE_AUTO_COMPACT_WINDOW` for native
|
|
177
177
|
Claude Code behavior, or `forge config set context_limit=N` for Forge proxy fallback.
|
|
178
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
|
+
|
|
179
185
|
### Example Workflow: Plan, Execute, Review
|
|
180
186
|
|
|
181
187
|
With proxies configured, a typical feature workflow looks like:
|
|
@@ -201,26 +207,26 @@ forge session fork planner --into ../executor-worktree # Path to executor's wor
|
|
|
201
207
|
git push origin feature-branch
|
|
202
208
|
```
|
|
203
209
|
|
|
204
|
-
|
|
205
|
-
code change is checked against the approved plan. Sessions track artifacts and
|
|
206
|
-
|
|
207
|
-
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.
|
|
208
214
|
|
|
209
215
|
## CLI Overview
|
|
210
216
|
|
|
211
|
-
| Command Group
|
|
212
|
-
|
|
|
213
|
-
| `forge claude`
|
|
214
|
-
| `forge session`
|
|
215
|
-
| `forge memory`
|
|
216
|
-
| `forge proxy`
|
|
217
|
-
| `forge
|
|
218
|
-
| `forge policy`
|
|
219
|
-
| `forge workflow`
|
|
220
|
-
| `forge search`
|
|
221
|
-
| `forge config`
|
|
222
|
-
| `forge extension`
|
|
223
|
-
| `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 |
|
|
224
230
|
|
|
225
231
|
Run `forge <command> --help` for details on any command.
|
|
226
232
|
|
|
@@ -17,8 +17,8 @@ agents.**
|
|
|
17
17
|
|
|
18
18
|
Forge sits between you and your coding agent (Claude Code by default, with Codex as an alternate runtime and Gemini
|
|
19
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
|
|
21
|
-
|
|
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)
|
|
@@ -108,7 +108,7 @@ forge extension enable
|
|
|
108
108
|
# Launch Claude with session tracking (no proxy needed)
|
|
109
109
|
forge session start
|
|
110
110
|
|
|
111
|
-
# Or with multi-model routing via OpenRouter (
|
|
111
|
+
# Or with multi-model routing via OpenRouter (no LiteLLM):
|
|
112
112
|
forge auth login -c openrouter # Store OPENROUTER_API_KEY
|
|
113
113
|
forge proxy create openrouter-anthropic # Create and start a Claude-family proxy
|
|
114
114
|
forge session start --proxy openrouter-anthropic
|
|
@@ -135,6 +135,12 @@ Existing pre-OSS Forge installs are not supported in-place. If upgrading:
|
|
|
135
135
|
4. If you had `FORGE_CONTEXT_LIMIT` in your shell config, remove it. Use `CLAUDE_CODE_AUTO_COMPACT_WINDOW` for native
|
|
136
136
|
Claude Code behavior, or `forge config set context_limit=N` for Forge proxy fallback.
|
|
137
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
|
+
|
|
138
144
|
### Example Workflow: Plan, Execute, Review
|
|
139
145
|
|
|
140
146
|
With proxies configured, a typical feature workflow looks like:
|
|
@@ -160,26 +166,26 @@ forge session fork planner --into ../executor-worktree # Path to executor's wor
|
|
|
160
166
|
git push origin feature-branch
|
|
161
167
|
```
|
|
162
168
|
|
|
163
|
-
|
|
164
|
-
code change is checked against the approved plan. Sessions track artifacts and
|
|
165
|
-
|
|
166
|
-
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.
|
|
167
173
|
|
|
168
174
|
## CLI Overview
|
|
169
175
|
|
|
170
|
-
| Command Group
|
|
171
|
-
|
|
|
172
|
-
| `forge claude`
|
|
173
|
-
| `forge session`
|
|
174
|
-
| `forge memory`
|
|
175
|
-
| `forge proxy`
|
|
176
|
-
| `forge
|
|
177
|
-
| `forge policy`
|
|
178
|
-
| `forge workflow`
|
|
179
|
-
| `forge search`
|
|
180
|
-
| `forge config`
|
|
181
|
-
| `forge extension`
|
|
182
|
-
| `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 |
|
|
183
189
|
|
|
184
190
|
Run `forge <command> --help` for details on any command.
|
|
185
191
|
|
|
@@ -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
|