multi-forge 0.2.0__py3-none-any.whl
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.
- forge/__init__.py +3 -0
- forge/_extensions/agents/.gitkeep +0 -0
- forge/_extensions/commands/.gitkeep +0 -0
- forge/_extensions/skills/analyze/SKILL.md +87 -0
- forge/_extensions/skills/challenge/SKILL.md +91 -0
- forge/_extensions/skills/consensus/SKILL.md +120 -0
- forge/_extensions/skills/consensus/resources/code_consensus_evaluation.md +94 -0
- forge/_extensions/skills/consensus/resources/consensus_evaluation.md +70 -0
- forge/_extensions/skills/consensus/resources/synthesis.md +101 -0
- forge/_extensions/skills/debate/SKILL.md +116 -0
- forge/_extensions/skills/debate/resources/code_debate_evaluation.md +101 -0
- forge/_extensions/skills/debate/resources/debate_evaluation.md +90 -0
- forge/_extensions/skills/panel/SKILL.md +141 -0
- forge/_extensions/skills/panel/resources/synthesis.md +103 -0
- forge/_extensions/skills/qa/SKILL.md +704 -0
- forge/_extensions/skills/qa/resources/checklist/0-enable.md +78 -0
- forge/_extensions/skills/qa/resources/checklist/1-preflight.md +24 -0
- forge/_extensions/skills/qa/resources/checklist/10-resume.md +143 -0
- forge/_extensions/skills/qa/resources/checklist/11-config.md +150 -0
- forge/_extensions/skills/qa/resources/checklist/12-search.md +58 -0
- forge/_extensions/skills/qa/resources/checklist/13-guard.md +237 -0
- forge/_extensions/skills/qa/resources/checklist/14-workflow.md +305 -0
- forge/_extensions/skills/qa/resources/checklist/15-skills.md +155 -0
- forge/_extensions/skills/qa/resources/checklist/16-handoff.md +224 -0
- forge/_extensions/skills/qa/resources/checklist/17-info.md +50 -0
- forge/_extensions/skills/qa/resources/checklist/18-disable.md +84 -0
- forge/_extensions/skills/qa/resources/checklist/19-uninstall.md +146 -0
- forge/_extensions/skills/qa/resources/checklist/2-extensions.md +188 -0
- forge/_extensions/skills/qa/resources/checklist/20-cleanup.md +36 -0
- forge/_extensions/skills/qa/resources/checklist/3-auth.md +234 -0
- forge/_extensions/skills/qa/resources/checklist/4-proxy.md +481 -0
- forge/_extensions/skills/qa/resources/checklist/5-session.md +541 -0
- forge/_extensions/skills/qa/resources/checklist/6-hooks.md +275 -0
- forge/_extensions/skills/qa/resources/checklist/7-costs.md +309 -0
- forge/_extensions/skills/qa/resources/checklist/8-status-line.md +174 -0
- forge/_extensions/skills/qa/resources/checklist/9-direct-commands.md +146 -0
- forge/_extensions/skills/qa/resources/checklist.md +103 -0
- forge/_extensions/skills/qa/resources/report-template.md +62 -0
- forge/_extensions/skills/qa/scripts/start-container.sh +529 -0
- forge/_extensions/skills/qa/scripts/walkthrough-state.py +1137 -0
- forge/_extensions/skills/review/SKILL.md +125 -0
- forge/_extensions/skills/review/references/claude-4.6.md +474 -0
- forge/_extensions/skills/review/references/claude-4.7.md +710 -0
- forge/_extensions/skills/review/references/gemini-3.1.md +546 -0
- forge/_extensions/skills/review/references/gpt-5.5.md +490 -0
- forge/_extensions/skills/review/references/skills-writing-guide.md +1588 -0
- forge/_extensions/skills/review/resources/code-anthropic.md +160 -0
- forge/_extensions/skills/review/resources/code-gemini.md +184 -0
- forge/_extensions/skills/review/resources/code-openai.md +203 -0
- forge/_extensions/skills/review/resources/code.md +160 -0
- forge/_extensions/skills/review-docs/SKILL.md +121 -0
- forge/_extensions/skills/review-docs/resources/docs-anthropic.md +170 -0
- forge/_extensions/skills/review-docs/resources/docs-gemini.md +204 -0
- forge/_extensions/skills/review-docs/resources/docs-openai.md +231 -0
- forge/_extensions/skills/review-docs/resources/docs.md +170 -0
- forge/_extensions/skills/smoke-test/SKILL.md +27 -0
- forge/_extensions/skills/smoke-test/scripts/smoke-test.sh +118 -0
- forge/_extensions/skills/understand/SKILL.md +148 -0
- forge/_extensions/skills/understand/resources/code-anthropic.md +163 -0
- forge/_extensions/skills/understand/resources/code-gemini.md +194 -0
- forge/_extensions/skills/understand/resources/code-openai.md +181 -0
- forge/_extensions/skills/understand/resources/code.md +163 -0
- forge/_extensions/skills/understand/resources/docs-anthropic.md +177 -0
- forge/_extensions/skills/understand/resources/docs-gemini.md +202 -0
- forge/_extensions/skills/understand/resources/docs-openai.md +191 -0
- forge/_extensions/skills/understand/resources/docs.md +177 -0
- forge/_extensions/skills/walkthrough/SKILL.md +599 -0
- forge/_extensions/skills/walkthrough/resources/checklist.md +765 -0
- forge/_extensions/skills/walkthrough/scripts/run-in-repo.sh +118 -0
- forge/_extensions/skills/walkthrough/scripts/setup-test-repo.sh +198 -0
- forge/_extensions/skills/walkthrough/scripts/walkthrough-state.py +1137 -0
- forge/backend/__init__.py +174 -0
- forge/backend/adapters/__init__.py +38 -0
- forge/backend/adapters/litellm.py +158 -0
- forge/backend/creation.py +89 -0
- forge/backend/registry.py +178 -0
- forge/cli/__init__.py +16 -0
- forge/cli/auth.py +483 -0
- forge/cli/backend.py +298 -0
- forge/cli/claude.py +411 -0
- forge/cli/config_cmd.py +303 -0
- forge/cli/extensions.py +1001 -0
- forge/cli/gc.py +165 -0
- forge/cli/guard.py +1018 -0
- forge/cli/guards.py +106 -0
- forge/cli/handoff.py +110 -0
- forge/cli/hooks/__init__.py +36 -0
- forge/cli/hooks/_group.py +20 -0
- forge/cli/hooks/_helpers.py +149 -0
- forge/cli/hooks/commands.py +1677 -0
- forge/cli/hooks/direct_commands.py +1304 -0
- forge/cli/hooks/install.py +232 -0
- forge/cli/hooks/policy.py +151 -0
- forge/cli/hooks/read_hygiene.py +74 -0
- forge/cli/hooks/verification.py +370 -0
- forge/cli/logs.py +406 -0
- forge/cli/main.py +292 -0
- forge/cli/proxy.py +1821 -0
- forge/cli/proxy_costs.py +313 -0
- forge/cli/search.py +416 -0
- forge/cli/session.py +892 -0
- forge/cli/session_addendum.py +81 -0
- forge/cli/session_fork.py +750 -0
- forge/cli/session_handoff.py +141 -0
- forge/cli/session_lifecycle.py +2053 -0
- forge/cli/session_manage.py +1336 -0
- forge/cli/session_memory.py +201 -0
- forge/cli/status_line.py +1398 -0
- forge/cli/workflow.py +1964 -0
- forge/config/__init__.py +110 -0
- forge/config/dataclass_utils.py +88 -0
- forge/config/defaults/__init__.py +0 -0
- forge/config/defaults/backends/__init__.py +0 -0
- forge/config/defaults/backends/litellm.yaml +196 -0
- forge/config/defaults/templates/__init__.py +0 -0
- forge/config/defaults/templates/litellm-anthropic-local.yaml +33 -0
- forge/config/defaults/templates/litellm-anthropic.yaml +24 -0
- forge/config/defaults/templates/litellm-gemini-flash-local.yaml +37 -0
- forge/config/defaults/templates/litellm-gemini-local.yaml +32 -0
- forge/config/defaults/templates/litellm-gemini-test.yaml +34 -0
- forge/config/defaults/templates/litellm-gemini.yaml +21 -0
- forge/config/defaults/templates/litellm-openai-codex-local.yaml +36 -0
- forge/config/defaults/templates/litellm-openai-local.yaml +38 -0
- forge/config/defaults/templates/litellm-openai.yaml +28 -0
- forge/config/defaults/templates/openrouter-anthropic.yaml +23 -0
- forge/config/defaults/templates/openrouter-deepseek.yaml +26 -0
- forge/config/defaults/templates/openrouter-gemini-flash.yaml +26 -0
- forge/config/defaults/templates/openrouter-gemini.yaml +23 -0
- forge/config/defaults/templates/openrouter-glm.yaml +23 -0
- forge/config/defaults/templates/openrouter-kimi.yaml +30 -0
- forge/config/defaults/templates/openrouter-minimax.yaml +26 -0
- forge/config/defaults/templates/openrouter-openai-codex.yaml +23 -0
- forge/config/defaults/templates/openrouter-openai.yaml +28 -0
- forge/config/defaults/templates/openrouter-qwen.yaml +25 -0
- forge/config/loader.py +675 -0
- forge/config/schema.py +448 -0
- forge/core/__init__.py +5 -0
- forge/core/auth/__init__.py +67 -0
- forge/core/auth/capabilities.py +219 -0
- forge/core/auth/credentials_file.py +244 -0
- forge/core/auth/protocols.py +18 -0
- forge/core/auth/secrets.py +243 -0
- forge/core/auth/template_secrets.py +112 -0
- forge/core/data/__init__.py +5 -0
- forge/core/data/model_catalog.yaml +1522 -0
- forge/core/data/pricing.yaml +140 -0
- forge/core/data/system_prompt_addendums/__init__.py +0 -0
- forge/core/data/system_prompt_addendums/gemini.md +330 -0
- forge/core/data/system_prompt_addendums/openai.md +328 -0
- forge/core/llm/__init__.py +231 -0
- forge/core/llm/clients/__init__.py +14 -0
- forge/core/llm/clients/base.py +115 -0
- forge/core/llm/clients/litellm.py +619 -0
- forge/core/llm/clients/openai_compat.py +244 -0
- forge/core/llm/clients/openrouter.py +234 -0
- forge/core/llm/credentials.py +439 -0
- forge/core/llm/detection.py +86 -0
- forge/core/llm/errors.py +44 -0
- forge/core/llm/protocols.py +80 -0
- forge/core/llm/types.py +176 -0
- forge/core/logging.py +146 -0
- forge/core/models/__init__.py +91 -0
- forge/core/models/catalog.py +467 -0
- forge/core/models/pricing.py +165 -0
- forge/core/models/types.py +167 -0
- forge/core/naming.py +212 -0
- forge/core/ops/__init__.py +73 -0
- forge/core/ops/context.py +141 -0
- forge/core/ops/gc.py +802 -0
- forge/core/ops/proxy.py +146 -0
- forge/core/ops/resolution.py +135 -0
- forge/core/ops/session.py +344 -0
- forge/core/ops/session_context.py +548 -0
- forge/core/paths.py +38 -0
- forge/core/process.py +54 -0
- forge/core/reactive/__init__.py +38 -0
- forge/core/reactive/cost_tracking.py +300 -0
- forge/core/reactive/env.py +180 -0
- forge/core/reactive/proxy.py +78 -0
- forge/core/reactive/routing.py +622 -0
- forge/core/reactive/session_runner.py +185 -0
- forge/core/reactive/structured_output.py +62 -0
- forge/core/reactive/tagger.py +94 -0
- forge/core/reactive/throttle.py +132 -0
- forge/core/state/__init__.py +59 -0
- forge/core/state/exceptions.py +59 -0
- forge/core/state/io.py +140 -0
- forge/core/state/lock.py +99 -0
- forge/core/state/timestamps.py +60 -0
- forge/core/transcript.py +78 -0
- forge/core/typing_helpers.py +24 -0
- forge/core/workqueue/__init__.py +67 -0
- forge/core/workqueue/queue.py +552 -0
- forge/core/workqueue/types.py +63 -0
- forge/guard/__init__.py +26 -0
- forge/guard/deterministic/__init__.py +26 -0
- forge/guard/deterministic/base.py +158 -0
- forge/guard/deterministic/coding_standards.py +256 -0
- forge/guard/deterministic/registry.py +148 -0
- forge/guard/deterministic/tdd.py +171 -0
- forge/guard/engine.py +216 -0
- forge/guard/protocols.py +91 -0
- forge/guard/queries.py +96 -0
- forge/guard/semantic/__init__.py +34 -0
- forge/guard/semantic/promotion.py +18 -0
- forge/guard/semantic/supervisor.py +813 -0
- forge/guard/semantic/verdict.py +183 -0
- forge/guard/store.py +124 -0
- forge/guard/team/__init__.py +6 -0
- forge/guard/team/config.py +24 -0
- forge/guard/team/handlers.py +209 -0
- forge/guard/team/prompts.py +41 -0
- forge/guard/types.py +125 -0
- forge/guard/workflow/__init__.py +17 -0
- forge/guard/workflow/branches.py +67 -0
- forge/guard/workflow/config.py +63 -0
- forge/guard/workflow/divergence.py +113 -0
- forge/guard/workflow/policy.py +87 -0
- forge/guard/workflow/stages.py +205 -0
- forge/install/__init__.py +55 -0
- forge/install/cli.py +281 -0
- forge/install/exceptions.py +163 -0
- forge/install/hooks.py +109 -0
- forge/install/installer.py +1037 -0
- forge/install/models.py +321 -0
- forge/install/preset.py +272 -0
- forge/install/settings_merge.py +831 -0
- forge/install/tracking.py +238 -0
- forge/install/version.py +141 -0
- forge/proxy/__init__.py +0 -0
- forge/proxy/base_client.py +181 -0
- forge/proxy/client_adapter.py +476 -0
- forge/proxy/client_factory.py +531 -0
- forge/proxy/converters.py +1206 -0
- forge/proxy/cost_logger.py +132 -0
- forge/proxy/cost_tracker.py +242 -0
- forge/proxy/data_models.py +338 -0
- forge/proxy/error_hints.py +92 -0
- forge/proxy/metrics.py +222 -0
- forge/proxy/model_spec.py +158 -0
- forge/proxy/proxies.py +333 -0
- forge/proxy/proxy_identity.py +134 -0
- forge/proxy/proxy_orchestrator.py +1018 -0
- forge/proxy/proxy_startup.py +54 -0
- forge/proxy/server.py +1561 -0
- forge/proxy/utils.py +537 -0
- forge/review/__init__.py +6 -0
- forge/review/adversarial.py +111 -0
- forge/review/consensus.py +236 -0
- forge/review/engine.py +356 -0
- forge/review/models.py +437 -0
- forge/review/resources/__init__.py +5 -0
- forge/review/resources/codereview-performance.md +85 -0
- forge/review/resources/codereview-quick.md +75 -0
- forge/review/resources/codereview-security.md +92 -0
- forge/review/resources/codereview.md +85 -0
- forge/review/resources/docreview-quick.md +75 -0
- forge/review/resources/docreview.md +86 -0
- forge/review/resources/thinkdeep.md +89 -0
- forge/review/routing.py +368 -0
- forge/review/synthesis.py +73 -0
- forge/runtime_config.py +438 -0
- forge/search/__init__.py +55 -0
- forge/search/bm25_store.py +264 -0
- forge/search/content_store.py +197 -0
- forge/search/engine.py +352 -0
- forge/search/exceptions.py +51 -0
- forge/search/extractor.py +234 -0
- forge/search/index_state.py +295 -0
- forge/search/store.py +215 -0
- forge/search/tokenizer.py +24 -0
- forge/session/__init__.py +130 -0
- forge/session/active.py +339 -0
- forge/session/artifacts.py +202 -0
- forge/session/claude/__init__.py +50 -0
- forge/session/claude/cleanup.py +105 -0
- forge/session/claude/invoke.py +236 -0
- forge/session/claude/paths.py +200 -0
- forge/session/cleanup.py +216 -0
- forge/session/config.py +34 -0
- forge/session/direct_model.py +107 -0
- forge/session/effective.py +169 -0
- forge/session/exceptions.py +255 -0
- forge/session/handoff.py +881 -0
- forge/session/handoff_agent.py +544 -0
- forge/session/hooks/__init__.py +35 -0
- forge/session/hooks/models.py +73 -0
- forge/session/hooks/session_start.py +507 -0
- forge/session/identity.py +84 -0
- forge/session/index.py +553 -0
- forge/session/manager.py +1506 -0
- forge/session/models.py +572 -0
- forge/session/overrides.py +344 -0
- forge/session/plan_resolution.py +286 -0
- forge/session/prev_sessions.py +128 -0
- forge/session/store.py +431 -0
- forge/session/validation.py +47 -0
- forge/session/worktree/__init__.py +65 -0
- forge/session/worktree/cleanup.py +262 -0
- forge/session/worktree/config_copy.py +203 -0
- forge/session/worktree/create.py +332 -0
- forge/sidecar/__init__.py +29 -0
- forge/sidecar/container.py +161 -0
- forge/sidecar/docker.py +86 -0
- forge/sidecar/secrets.py +19 -0
- multi_forge-0.2.0.dist-info/METADATA +242 -0
- multi_forge-0.2.0.dist-info/RECORD +311 -0
- multi_forge-0.2.0.dist-info/WHEEL +4 -0
- multi_forge-0.2.0.dist-info/entry_points.txt +2 -0
- multi_forge-0.2.0.dist-info/licenses/LICENSE +203 -0
- multi_forge-0.2.0.dist-info/licenses/NOTICE +14 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
## 0. Install Forge (New User Flow)
|
|
2
|
+
|
|
3
|
+
This simulates what a new user does to install Forge from scratch.
|
|
4
|
+
|
|
5
|
+
### 0.1 Pre-requisites Check
|
|
6
|
+
|
|
7
|
+
<!-- auto -->
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Check you have the required tools
|
|
11
|
+
python3 --version # Need 3.11+
|
|
12
|
+
uv --version # Need uv package manager
|
|
13
|
+
git --version # Need git
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- [ ] Python 3.11+ installed
|
|
17
|
+
- [ ] uv installed
|
|
18
|
+
- [ ] git installed
|
|
19
|
+
|
|
20
|
+
### 0.2 Verify Clean State
|
|
21
|
+
|
|
22
|
+
<!-- auto -->
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Ensure no previous Forge installation
|
|
26
|
+
ls -la ~/.forge/ # Should not exist
|
|
27
|
+
which forge # Should not be on PATH (or points to dev venv)
|
|
28
|
+
|
|
29
|
+
# Check Claude settings have no Forge hooks
|
|
30
|
+
cat ~/.claude/settings.json | jq '.hooks' 2>/dev/null || true
|
|
31
|
+
cat ~/.claude/settings.local.json | jq '.hooks' 2>/dev/null || true
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- [ ] `~/.forge/` does not exist
|
|
35
|
+
- [ ] No Forge hooks in `~/.claude/settings.json`
|
|
36
|
+
- [ ] No Forge hooks in `~/.claude/settings.local.json`
|
|
37
|
+
|
|
38
|
+
### 0.3 Install via setup.sh
|
|
39
|
+
|
|
40
|
+
<!-- auto -->
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Install Forge using the local copy (already in container at /forge/)
|
|
44
|
+
cd /forge && /forge/scripts/setup.sh --local
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- [ ] Prerequisites check passes
|
|
48
|
+
- [ ] Repository linked at `~/.forge/repo/` (symlink to `/forge`)
|
|
49
|
+
- [ ] `setup.sh --local` completes successfully
|
|
50
|
+
- [ ] `forge` binary available (at `~/.local/bin/forge` for `--local` mode)
|
|
51
|
+
- [ ] Success message displayed
|
|
52
|
+
|
|
53
|
+
> Note: `setup.sh` installs Forge but does not automatically install Claude extensions. After install, run:
|
|
54
|
+
>
|
|
55
|
+
> - `forge extension enable --scope user` (installs commands/agents/skills/hooks)
|
|
56
|
+
|
|
57
|
+
### 0.4 Verify Installation
|
|
58
|
+
|
|
59
|
+
<!-- auto -->
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Source your profile (or restart terminal)
|
|
63
|
+
source ~/.zshrc # or ~/.bash_profile
|
|
64
|
+
|
|
65
|
+
# Verify forge is on PATH
|
|
66
|
+
which forge
|
|
67
|
+
forge --version
|
|
68
|
+
|
|
69
|
+
# Check installation artifacts
|
|
70
|
+
ls -la ~/.forge/
|
|
71
|
+
ls -la ~/.forge/repo/
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- [ ] `forge` command available on PATH
|
|
75
|
+
- [ ] `~/.forge/` directory created
|
|
76
|
+
- [ ] `~/.forge/repo/` contains repo (symlink or clone)
|
|
77
|
+
|
|
78
|
+
---
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- prereq: 0.3 -->
|
|
2
|
+
|
|
3
|
+
## 1. Pre-Flight for Extension Tests
|
|
4
|
+
|
|
5
|
+
### 1.1 Pre-Flight Checks
|
|
6
|
+
|
|
7
|
+
<!-- auto -->
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Navigate to test repo
|
|
11
|
+
cd $FORGE_TEST_REPO
|
|
12
|
+
|
|
13
|
+
# IMPORTANT: Verify pre-existing user settings exist
|
|
14
|
+
cat .claude/settings.local.json | jq '.'
|
|
15
|
+
# Should include permissions.allow ["Bash(npm test)", "Bash(uv run pytest*)"] and env.MY_CUSTOM_VAR="should-survive-forge".
|
|
16
|
+
|
|
17
|
+
# Optional: verify project settings file exists too
|
|
18
|
+
ls -la .claude/settings.json 2>/dev/null || true
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- [ ] Test repo has `.claude/settings.local.json` with pre-existing settings
|
|
22
|
+
- [ ] Note the original content for later verification
|
|
23
|
+
|
|
24
|
+
---
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<!-- prereq: 0.3, 2.1, 5.1 -->
|
|
2
|
+
|
|
3
|
+
## 10. Session Resume (Phase 10 Feature)
|
|
4
|
+
|
|
5
|
+
### 10.1 Create Parent Session Artifacts
|
|
6
|
+
|
|
7
|
+
<!-- auto -->
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Create a mock transcript artifact for testing resume
|
|
11
|
+
SESSION_JSON=".forge/sessions/test-session-1/forge.session.json"
|
|
12
|
+
SESSION_ID=$(jq -r '.confirmed.claude_session_id // "fixture-transcript"' "$SESSION_JSON")
|
|
13
|
+
TRANSCRIPT_REL=".forge/artifacts/test-session-1/transcripts/${SESSION_ID}.jsonl"
|
|
14
|
+
TRANSCRIPT_ABS="$FORGE_TEST_REPO/${TRANSCRIPT_REL}"
|
|
15
|
+
|
|
16
|
+
mkdir -p "$(dirname "$TRANSCRIPT_ABS")"
|
|
17
|
+
cat > "$TRANSCRIPT_ABS" << 'EOF'
|
|
18
|
+
{"requestId":"req-1","timestamp":"2026-03-16T00:00:00Z","message":{"role":"user","content":[{"type":"text","text":"Create a hello world function"}]}}
|
|
19
|
+
{"requestId":"req-1","timestamp":"2026-03-16T00:00:01Z","message":{"role":"assistant","content":[{"type":"text","text":"I'll create a simple hello world function for you."},{"type":"tool_use","id":"tool-1","name":"Write","input":{"file_path":"src/hello.py","content":"def hello():\n return 'Hello, World!'"}}]}}
|
|
20
|
+
{"requestId":"req-1","timestamp":"2026-03-16T00:00:02Z","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"tool-1","content":"File written successfully"}]}}
|
|
21
|
+
{"requestId":"req-2","timestamp":"2026-03-16T00:00:03Z","message":{"role":"user","content":[{"type":"text","text":"Now add a test"}]}}
|
|
22
|
+
{"requestId":"req-2","timestamp":"2026-03-16T00:00:04Z","message":{"role":"assistant","content":[{"type":"text","text":"I'll add a test for the hello function."},{"type":"tool_use","id":"tool-2","name":"Write","input":{"file_path":"tests/test_hello.py","content":"from src.hello import hello\n\ndef test_hello():\n assert hello() == 'Hello, World!'"}}]}}
|
|
23
|
+
{"requestId":"req-2","timestamp":"2026-03-16T00:00:05Z","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"tool-2","content":"File written successfully"}]}}
|
|
24
|
+
EOF
|
|
25
|
+
|
|
26
|
+
# Update session file with a realistic transcript artifact entry
|
|
27
|
+
jq \
|
|
28
|
+
--arg transcript_abs "$TRANSCRIPT_ABS" \
|
|
29
|
+
--arg transcript_rel "$TRANSCRIPT_REL" \
|
|
30
|
+
--arg session_id "$SESSION_ID" \
|
|
31
|
+
'
|
|
32
|
+
.confirmed.transcript_path = $transcript_abs
|
|
33
|
+
| .confirmed.artifacts = ((.confirmed.artifacts // {}) + {
|
|
34
|
+
transcripts: [{
|
|
35
|
+
captured_at: "2026-03-16T00:00:00Z",
|
|
36
|
+
reason: "stop",
|
|
37
|
+
source_path: $transcript_abs,
|
|
38
|
+
session_id: $session_id,
|
|
39
|
+
copied_path: $transcript_rel,
|
|
40
|
+
copied: true
|
|
41
|
+
}]
|
|
42
|
+
})
|
|
43
|
+
' "$SESSION_JSON" > /tmp/session.json && mv /tmp/session.json "$SESSION_JSON"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- [ ] Transcript artifact created under `.forge/artifacts/test-session-1/transcripts/`
|
|
47
|
+
- [ ] Session file updated with transcript path and `confirmed.artifacts.transcripts[]`
|
|
48
|
+
|
|
49
|
+
### 10.2 Resume with Minimal Strategy
|
|
50
|
+
|
|
51
|
+
<!-- prereq: 10.1 -->
|
|
52
|
+
|
|
53
|
+
<!-- requires: api_key -->
|
|
54
|
+
|
|
55
|
+
<!-- human:guided -->
|
|
56
|
+
|
|
57
|
+
In the **container shell**, resume with `--strategy minimal`. Claude will launch — verify the new session was created,
|
|
58
|
+
then exit.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
# Resume with minimal strategy (just lineage pointer)
|
|
62
|
+
forge session resume test-session-1 --fresh --strategy minimal --child-name test-resumed-minimal
|
|
63
|
+
|
|
64
|
+
# Check derived session
|
|
65
|
+
cat .forge/sessions/test-resumed-minimal/forge.session.json | jq '.confirmed.derivation'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- [ ] New session created
|
|
69
|
+
- [ ] Derivation shows parent, strategy, and transcript artifact path
|
|
70
|
+
|
|
71
|
+
### 10.3 Resume with Structured Strategy
|
|
72
|
+
|
|
73
|
+
<!-- prereq: 10.1 -->
|
|
74
|
+
|
|
75
|
+
<!-- requires: api_key -->
|
|
76
|
+
|
|
77
|
+
<!-- human:guided -->
|
|
78
|
+
|
|
79
|
+
In the **container shell**, resume with `--strategy structured`. Claude will launch — verify the handoff file was
|
|
80
|
+
created, then exit.
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
# Resume with structured strategy (conversation skeleton)
|
|
84
|
+
forge session resume test-session-1 --fresh --strategy structured --child-name test-resumed-structured
|
|
85
|
+
|
|
86
|
+
# Check processed handoff
|
|
87
|
+
cat .forge/prev_sessions/test-session-1/generated.md
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- [ ] Handoff file created at `.forge/prev_sessions/<parent>/children/<child>.md`
|
|
91
|
+
- [ ] Contains conversation skeleton with truncated tool results
|
|
92
|
+
|
|
93
|
+
### 10.4 Resume with Full Strategy
|
|
94
|
+
|
|
95
|
+
<!-- prereq: 10.1 -->
|
|
96
|
+
|
|
97
|
+
<!-- requires: api_key -->
|
|
98
|
+
|
|
99
|
+
<!-- human:guided -->
|
|
100
|
+
|
|
101
|
+
In the **container shell**, resume with `--strategy full`. This includes the complete transcript — the budget check may
|
|
102
|
+
fail if the transcript is too large for the proxy context window.
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
# Resume with full strategy (complete transcript)
|
|
106
|
+
forge session resume test-session-1 --fresh --strategy full --child-name test-resumed-full
|
|
107
|
+
|
|
108
|
+
# Check the handoff
|
|
109
|
+
cat .forge/prev_sessions/test-session-1/generated.md
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- [ ] Full transcript included
|
|
113
|
+
- [ ] Budget check passed (or error if too large)
|
|
114
|
+
|
|
115
|
+
### 10.5 Resume with AI-Curated Strategy
|
|
116
|
+
|
|
117
|
+
<!-- prereq: 10.1 -->
|
|
118
|
+
|
|
119
|
+
<!-- requires: api_key -->
|
|
120
|
+
|
|
121
|
+
<!-- human:guided -->
|
|
122
|
+
|
|
123
|
+
In the **container shell**, resume with `--strategy ai-curated`. This uses OpenRouter directly to select highlights from
|
|
124
|
+
the parent transcript, then launches the child session. Expect a security warning about external API access.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
# Resume with AI-curated strategy (LLM-selected highlights)
|
|
128
|
+
# NOTE: Requires OPENROUTER_API_KEY in the default QA provider profile.
|
|
129
|
+
forge session delete test-resumed-ai --yes --force 2>/dev/null || true
|
|
130
|
+
forge session resume test-session-1 --fresh --strategy ai-curated --child-name test-resumed-ai
|
|
131
|
+
|
|
132
|
+
# Check the curated output or fallback output
|
|
133
|
+
cat .forge/prev_sessions/test-session-1/generated.md
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- [ ] Parent transcript fixture from 10.1 exists
|
|
137
|
+
- [ ] Security warning shown about sending transcript content to OpenRouter
|
|
138
|
+
- [ ] Default OpenRouter QA profile: handoff shows `Strategy: ai-curated` and LLM-selected highlights
|
|
139
|
+
- [ ] If OpenRouter auth is unavailable, fallback to structured is acceptable and the warning explains the auth failure
|
|
140
|
+
- [ ] No warning about missing remote LiteLLM infrastructure in the default OpenRouter QA profile
|
|
141
|
+
- [ ] No `No transcript available; using minimal strategy` warning
|
|
142
|
+
|
|
143
|
+
---
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<!-- prereq: 0.3 -->
|
|
2
|
+
|
|
3
|
+
## 11. Runtime Config + Claude Preset (`forge config`, `forge claude preset`)
|
|
4
|
+
|
|
5
|
+
### 11.1 Initialize Config
|
|
6
|
+
|
|
7
|
+
<!-- auto -->
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Config auto-creates with commented defaults on first access
|
|
11
|
+
forge config show
|
|
12
|
+
|
|
13
|
+
# Verify file created
|
|
14
|
+
cat ${FORGE_HOME:-$HOME/.forge}/config.yaml
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- [ ] Config file created at `${FORGE_HOME:-$HOME/.forge}/config.yaml`
|
|
18
|
+
- [ ] Shows commented defaults (proxy_mode, sidecar_image, etc.)
|
|
19
|
+
|
|
20
|
+
### 11.2 Show Effective Config
|
|
21
|
+
|
|
22
|
+
<!-- auto -->
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
forge config show
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- [ ] Shows all settings with current values
|
|
29
|
+
- [ ] Shows defaults when no overrides set
|
|
30
|
+
|
|
31
|
+
### 11.3 Set and Reset Values
|
|
32
|
+
|
|
33
|
+
<!-- auto -->
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Set a value
|
|
37
|
+
forge config set status_timeout=1.0
|
|
38
|
+
|
|
39
|
+
# Switch proxy mode default (host vs sidecar)
|
|
40
|
+
forge config set proxy_mode=sidecar
|
|
41
|
+
|
|
42
|
+
# Verify
|
|
43
|
+
forge config show | grep status_timeout
|
|
44
|
+
forge config show | grep proxy_mode
|
|
45
|
+
|
|
46
|
+
# Reset one key
|
|
47
|
+
forge config reset status_timeout
|
|
48
|
+
|
|
49
|
+
# Reset all
|
|
50
|
+
forge config reset
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- [ ] `set` persists the value
|
|
54
|
+
- [ ] `reset` restores default
|
|
55
|
+
- [ ] Type validation works (rejects invalid values)
|
|
56
|
+
|
|
57
|
+
### 11.4 Edit in Editor
|
|
58
|
+
|
|
59
|
+
<!-- human:guided -->
|
|
60
|
+
|
|
61
|
+
In the **container shell**, run `forge config edit`. Verify `$EDITOR` opens `${FORGE_HOME:-$HOME/.forge}/config.yaml`.
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
forge config edit
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- [ ] Opens `${FORGE_HOME:-$HOME/.forge}/config.yaml` in `$EDITOR`
|
|
68
|
+
|
|
69
|
+
### 11.5 Show Claude Preset
|
|
70
|
+
|
|
71
|
+
<!-- auto -->
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Show current preset (raw JSON auto-creates on first access)
|
|
75
|
+
forge claude preset show --raw
|
|
76
|
+
|
|
77
|
+
# Verify file created and built-in keys present
|
|
78
|
+
python3 - <<'PY'
|
|
79
|
+
import json
|
|
80
|
+
import os
|
|
81
|
+
from pathlib import Path
|
|
82
|
+
|
|
83
|
+
forge_home = Path(os.environ.get("FORGE_HOME", str(Path.home() / ".forge")))
|
|
84
|
+
path = forge_home / "claude.preset.json"
|
|
85
|
+
data = json.loads(path.read_text())
|
|
86
|
+
has_hooks = "hooks" in data
|
|
87
|
+
has_statusline = "statusLine" in data
|
|
88
|
+
print("PRESET_PATH=" + str(path))
|
|
89
|
+
print("HAS_HOOKS=" + str(has_hooks))
|
|
90
|
+
print("HAS_STATUSLINE=" + str(has_statusline))
|
|
91
|
+
PY
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- [ ] Preset file created at `${FORGE_HOME:-$HOME/.forge}/claude.preset.json`
|
|
95
|
+
- [ ] Built-in preset includes `hooks` and `statusLine`
|
|
96
|
+
|
|
97
|
+
### 11.6 Reset Claude Preset
|
|
98
|
+
|
|
99
|
+
<!-- auto -->
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Add a disposable custom env var to the preset
|
|
103
|
+
python3 - <<'PY'
|
|
104
|
+
import json
|
|
105
|
+
import os
|
|
106
|
+
from pathlib import Path
|
|
107
|
+
|
|
108
|
+
forge_home = Path(os.environ.get("FORGE_HOME", str(Path.home() / ".forge")))
|
|
109
|
+
path = forge_home / "claude.preset.json"
|
|
110
|
+
data = json.loads(path.read_text())
|
|
111
|
+
data.setdefault("env", {})["QA_TEMP_PRESET"] = "1"
|
|
112
|
+
path.write_text(json.dumps(data, indent=2) + "\n")
|
|
113
|
+
print("ADDED_QA_TEMP_PRESET=1")
|
|
114
|
+
PY
|
|
115
|
+
|
|
116
|
+
# Reset to built-in defaults without prompting
|
|
117
|
+
forge claude preset reset --force
|
|
118
|
+
|
|
119
|
+
# Verify temporary key removed and built-in env preserved
|
|
120
|
+
python3 - <<'PY'
|
|
121
|
+
import json
|
|
122
|
+
import os
|
|
123
|
+
from pathlib import Path
|
|
124
|
+
|
|
125
|
+
forge_home = Path(os.environ.get("FORGE_HOME", str(Path.home() / ".forge")))
|
|
126
|
+
path = forge_home / "claude.preset.json"
|
|
127
|
+
data = json.loads(path.read_text())
|
|
128
|
+
env = data.get("env", {})
|
|
129
|
+
has_qa_temp_preset = "QA_TEMP_PRESET" in env
|
|
130
|
+
print("HAS_QA_TEMP_PRESET=" + str(has_qa_temp_preset))
|
|
131
|
+
PY
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- [ ] `reset --force` restores the built-in preset non-interactively
|
|
135
|
+
- [ ] Custom preset additions are removed while built-in values remain
|
|
136
|
+
|
|
137
|
+
### 11.7 Edit Claude Preset in Editor
|
|
138
|
+
|
|
139
|
+
<!-- human:guided -->
|
|
140
|
+
|
|
141
|
+
In the **container shell**, run `forge claude preset edit`. Verify `$EDITOR` opens
|
|
142
|
+
`${FORGE_HOME:-$HOME/.forge}/claude.preset.json`.
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
forge claude preset edit
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- [ ] Opens `${FORGE_HOME:-$HOME/.forge}/claude.preset.json` in `$EDITOR`
|
|
149
|
+
|
|
150
|
+
---
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<!-- prereq: 0.3, 10.1 -->
|
|
2
|
+
|
|
3
|
+
## 12. Search (`forge search`)
|
|
4
|
+
|
|
5
|
+
### 12.1 Check Index Status
|
|
6
|
+
|
|
7
|
+
<!-- auto -->
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
forge search status
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- [ ] Shows index statistics (document count, store health)
|
|
14
|
+
- [ ] Shows index location
|
|
15
|
+
|
|
16
|
+
### 12.2 Build/Rebuild Index
|
|
17
|
+
|
|
18
|
+
<!-- auto -->
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Full rebuild from all transcript artifacts
|
|
22
|
+
forge search rebuild-index
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- [ ] Rebuilds index from `.forge/artifacts/`
|
|
26
|
+
- [ ] Reports number of documents indexed
|
|
27
|
+
|
|
28
|
+
### 12.3 Search Transcripts
|
|
29
|
+
|
|
30
|
+
<!-- auto -->
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Search for a keyword
|
|
34
|
+
forge search -q "hello world"
|
|
35
|
+
|
|
36
|
+
# Limit results
|
|
37
|
+
forge search -q "test" -n 3
|
|
38
|
+
|
|
39
|
+
# Search all projects
|
|
40
|
+
forge search -q "hello world" --scope all
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- [ ] Returns JSON results with session_name, score, snippet
|
|
44
|
+
- [ ] `--scope all` searches indexed projects (including the current project)
|
|
45
|
+
- [ ] Results ranked by BM25 relevance
|
|
46
|
+
|
|
47
|
+
### 12.4 Clean Orphaned Entries
|
|
48
|
+
|
|
49
|
+
<!-- auto -->
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
forge search clean
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- [ ] Removes entries for deleted transcripts
|
|
56
|
+
- [ ] Reports removed/pruned count or "No orphaned entries found."
|
|
57
|
+
|
|
58
|
+
---
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
<!-- prereq: 0.3, 5.1 -->
|
|
2
|
+
|
|
3
|
+
## 13. Policy/Guard (`forge guard`)
|
|
4
|
+
|
|
5
|
+
### 13.1 Guard Status
|
|
6
|
+
|
|
7
|
+
<!-- auto -->
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
forge guard status
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- [ ] Shows enabled/disabled state
|
|
14
|
+
- [ ] Shows active bundles (if any)
|
|
15
|
+
- [ ] Shows fail mode (if guard was previously enabled; omitted when never configured)
|
|
16
|
+
|
|
17
|
+
### 13.2 Enable TDD Enforcement
|
|
18
|
+
|
|
19
|
+
<!-- auto -->
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Enable TDD bundle
|
|
23
|
+
forge guard enable --bundle tdd
|
|
24
|
+
|
|
25
|
+
# Verify
|
|
26
|
+
forge guard status
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- [ ] TDD bundle activated
|
|
30
|
+
- [ ] `tests-before-impl` and `no-skip-tests` rules listed
|
|
31
|
+
|
|
32
|
+
### 13.3 Enable with Permissive Mode
|
|
33
|
+
|
|
34
|
+
<!-- auto -->
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Enable TDD in warn-only mode
|
|
38
|
+
forge guard enable --bundle tdd --permissive
|
|
39
|
+
|
|
40
|
+
# Verify
|
|
41
|
+
forge guard status
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- [ ] TDD in permissive mode (warns instead of blocks)
|
|
45
|
+
|
|
46
|
+
### 13.4 Enable Coding Standards
|
|
47
|
+
|
|
48
|
+
<!-- auto -->
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
forge guard enable --bundle coding_standards
|
|
52
|
+
|
|
53
|
+
forge guard status
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- [ ] Coding standards bundle activated
|
|
57
|
+
- [ ] `no-type-checking` and `no-backward-compat` rules listed
|
|
58
|
+
|
|
59
|
+
### 13.5 On-Demand Policy Check
|
|
60
|
+
|
|
61
|
+
<!-- auto -->
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Create a second commit so HEAD~1 is valid
|
|
65
|
+
echo 'print("new")' >> src/main.py
|
|
66
|
+
git add -A && git commit -q -m "add code for guard diff test"
|
|
67
|
+
|
|
68
|
+
# Check a diff against policies
|
|
69
|
+
git diff HEAD~1 | forge guard check --bundle tdd --bundle coding_standards --diff
|
|
70
|
+
|
|
71
|
+
# Check with JSON output
|
|
72
|
+
git diff HEAD~1 | forge guard check --bundle tdd --diff --json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- [ ] Evaluates diff against specified bundles
|
|
76
|
+
- [ ] `--json` produces structured output with `passed` and `clean` fields
|
|
77
|
+
|
|
78
|
+
### 13.6 Supervisor CLI Surface (Phase 19)
|
|
79
|
+
|
|
80
|
+
<!-- auto -->
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Verify CLI is wired up
|
|
84
|
+
forge guard supervisor --help
|
|
85
|
+
|
|
86
|
+
# Missing file produces clear error (exit 2)
|
|
87
|
+
forge guard supervisor -f /nonexistent/file.py -r 00000000-0000-0000-0000-000000000000 --json
|
|
88
|
+
echo "exit: $?"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- [ ] `--help` shows usage with `-f`, `-r`, `--json`, `--proxy`, `--timeout` options
|
|
92
|
+
- [ ] Missing file produces clear error and exit 2
|
|
93
|
+
|
|
94
|
+
### 13.7 Manual Supervisor Wiring (Planner -> Supervisor -> Executor)
|
|
95
|
+
|
|
96
|
+
<!-- prereq: 2.4, 4.2 -->
|
|
97
|
+
|
|
98
|
+
<!-- requires: api_key -->
|
|
99
|
+
|
|
100
|
+
<!-- human:guided -->
|
|
101
|
+
|
|
102
|
+
This is a hands-on live-Claude smoke test. Do the phases in order. The terminal commands are copy/paste blocks for the
|
|
103
|
+
container shell; the prompt blocks are for the Claude session that opens after each `forge session ...` command. If live
|
|
104
|
+
Claude launch is unavailable in this environment, mark this step `Skip` rather than inventing evidence.
|
|
105
|
+
|
|
106
|
+
**Phase 1: create an approved planner session**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cd $FORGE_TEST_REPO
|
|
110
|
+
|
|
111
|
+
forge session delete guard-planner --force 2>/dev/null || true
|
|
112
|
+
forge session delete guard-supervisor --force 2>/dev/null || true
|
|
113
|
+
forge session delete guard-executor --force 2>/dev/null || true
|
|
114
|
+
rm -f src/supervisor_demo.py
|
|
115
|
+
|
|
116
|
+
forge session start guard-planner --proxy "$FORGE_QA_OPENAI_PROXY"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
In Claude, type:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
/plan
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Then paste:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
Skip the exploration step. Create a plan only. Do not edit files or run any write tools.
|
|
129
|
+
|
|
130
|
+
The exact approved plan should be:
|
|
131
|
+
1. Create `src/supervisor_demo.py`
|
|
132
|
+
2. Add:
|
|
133
|
+
def greet(name: str) -> str:
|
|
134
|
+
return f"hello, {name}"
|
|
135
|
+
3. Do not modify any other files
|
|
136
|
+
|
|
137
|
+
After showing the plan, wait for my approval.
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
When Claude shows the plan, paste:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
I approve this exact plan. Do not implement it in this session. Wait.
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Then exit Claude:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
/exit
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Back in the container shell, verify that Claude wrote a plan file:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
ls ~/.claude/plans/
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Phase 2: promote a dedicated supervisor session**
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
cd $FORGE_TEST_REPO
|
|
162
|
+
|
|
163
|
+
forge session fork guard-planner --name guard-supervisor --no-launch
|
|
164
|
+
forge session resume guard-supervisor
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
In Claude, paste:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
Reply with this exact phrase: supervisor ready
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Then exit:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
/exit
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Phase 3: fork a direct executor and wire the supervisor**
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
cd $FORGE_TEST_REPO
|
|
183
|
+
|
|
184
|
+
forge session fork guard-planner --name guard-executor --no-proxy --no-launch
|
|
185
|
+
forge guard supervise guard-supervisor --session guard-executor --supervisor-proxy "$FORGE_QA_OPENAI_PROXY"
|
|
186
|
+
FORGE_SESSION=guard-executor forge guard status
|
|
187
|
+
forge session resume guard-executor
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
In Claude, paste:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
Create the file `src/supervisor_demo.py` with exactly this content:
|
|
194
|
+
|
|
195
|
+
def greet(name: str) -> str:
|
|
196
|
+
return f"hello, {name}"
|
|
197
|
+
|
|
198
|
+
Do not modify any other files. Do not add tests, docstrings, or imports.
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
After Claude finishes, exit:
|
|
202
|
+
|
|
203
|
+
```text
|
|
204
|
+
/exit
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Phase 4: inspect the result and run the one-shot supervisor check**
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
cd $FORGE_TEST_REPO
|
|
211
|
+
|
|
212
|
+
cat src/supervisor_demo.py
|
|
213
|
+
forge guard supervisor -f src/supervisor_demo.py -r guard-supervisor --json
|
|
214
|
+
echo "exit: $?"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
- [ ] Planner and supervisor sessions launch successfully; the planner has an approved plan and the supervisor session
|
|
218
|
+
materializes with a confirmed Claude session
|
|
219
|
+
- [ ] Executor forks planner with `--no-proxy`, `forge guard supervise` wires `guard-supervisor`, `forge guard status`
|
|
220
|
+
shows `Supervisor: Configured`, and the executor implements the exact tiny planned file
|
|
221
|
+
- [ ] `forge guard supervisor -f src/supervisor_demo.py -r guard-supervisor --json` returns structured output for the
|
|
222
|
+
real tiny task (expected: aligned / exit 0)
|
|
223
|
+
|
|
224
|
+
### 13.8 Disable Policies
|
|
225
|
+
|
|
226
|
+
<!-- auto -->
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
forge guard disable
|
|
230
|
+
|
|
231
|
+
forge guard status
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
- [ ] All policies disabled
|
|
235
|
+
- [ ] Status confirms disabled state
|
|
236
|
+
|
|
237
|
+
---
|