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.
Files changed (311) hide show
  1. forge/__init__.py +3 -0
  2. forge/_extensions/agents/.gitkeep +0 -0
  3. forge/_extensions/commands/.gitkeep +0 -0
  4. forge/_extensions/skills/analyze/SKILL.md +87 -0
  5. forge/_extensions/skills/challenge/SKILL.md +91 -0
  6. forge/_extensions/skills/consensus/SKILL.md +120 -0
  7. forge/_extensions/skills/consensus/resources/code_consensus_evaluation.md +94 -0
  8. forge/_extensions/skills/consensus/resources/consensus_evaluation.md +70 -0
  9. forge/_extensions/skills/consensus/resources/synthesis.md +101 -0
  10. forge/_extensions/skills/debate/SKILL.md +116 -0
  11. forge/_extensions/skills/debate/resources/code_debate_evaluation.md +101 -0
  12. forge/_extensions/skills/debate/resources/debate_evaluation.md +90 -0
  13. forge/_extensions/skills/panel/SKILL.md +141 -0
  14. forge/_extensions/skills/panel/resources/synthesis.md +103 -0
  15. forge/_extensions/skills/qa/SKILL.md +704 -0
  16. forge/_extensions/skills/qa/resources/checklist/0-enable.md +78 -0
  17. forge/_extensions/skills/qa/resources/checklist/1-preflight.md +24 -0
  18. forge/_extensions/skills/qa/resources/checklist/10-resume.md +143 -0
  19. forge/_extensions/skills/qa/resources/checklist/11-config.md +150 -0
  20. forge/_extensions/skills/qa/resources/checklist/12-search.md +58 -0
  21. forge/_extensions/skills/qa/resources/checklist/13-guard.md +237 -0
  22. forge/_extensions/skills/qa/resources/checklist/14-workflow.md +305 -0
  23. forge/_extensions/skills/qa/resources/checklist/15-skills.md +155 -0
  24. forge/_extensions/skills/qa/resources/checklist/16-handoff.md +224 -0
  25. forge/_extensions/skills/qa/resources/checklist/17-info.md +50 -0
  26. forge/_extensions/skills/qa/resources/checklist/18-disable.md +84 -0
  27. forge/_extensions/skills/qa/resources/checklist/19-uninstall.md +146 -0
  28. forge/_extensions/skills/qa/resources/checklist/2-extensions.md +188 -0
  29. forge/_extensions/skills/qa/resources/checklist/20-cleanup.md +36 -0
  30. forge/_extensions/skills/qa/resources/checklist/3-auth.md +234 -0
  31. forge/_extensions/skills/qa/resources/checklist/4-proxy.md +481 -0
  32. forge/_extensions/skills/qa/resources/checklist/5-session.md +541 -0
  33. forge/_extensions/skills/qa/resources/checklist/6-hooks.md +275 -0
  34. forge/_extensions/skills/qa/resources/checklist/7-costs.md +309 -0
  35. forge/_extensions/skills/qa/resources/checklist/8-status-line.md +174 -0
  36. forge/_extensions/skills/qa/resources/checklist/9-direct-commands.md +146 -0
  37. forge/_extensions/skills/qa/resources/checklist.md +103 -0
  38. forge/_extensions/skills/qa/resources/report-template.md +62 -0
  39. forge/_extensions/skills/qa/scripts/start-container.sh +529 -0
  40. forge/_extensions/skills/qa/scripts/walkthrough-state.py +1137 -0
  41. forge/_extensions/skills/review/SKILL.md +125 -0
  42. forge/_extensions/skills/review/references/claude-4.6.md +474 -0
  43. forge/_extensions/skills/review/references/claude-4.7.md +710 -0
  44. forge/_extensions/skills/review/references/gemini-3.1.md +546 -0
  45. forge/_extensions/skills/review/references/gpt-5.5.md +490 -0
  46. forge/_extensions/skills/review/references/skills-writing-guide.md +1588 -0
  47. forge/_extensions/skills/review/resources/code-anthropic.md +160 -0
  48. forge/_extensions/skills/review/resources/code-gemini.md +184 -0
  49. forge/_extensions/skills/review/resources/code-openai.md +203 -0
  50. forge/_extensions/skills/review/resources/code.md +160 -0
  51. forge/_extensions/skills/review-docs/SKILL.md +121 -0
  52. forge/_extensions/skills/review-docs/resources/docs-anthropic.md +170 -0
  53. forge/_extensions/skills/review-docs/resources/docs-gemini.md +204 -0
  54. forge/_extensions/skills/review-docs/resources/docs-openai.md +231 -0
  55. forge/_extensions/skills/review-docs/resources/docs.md +170 -0
  56. forge/_extensions/skills/smoke-test/SKILL.md +27 -0
  57. forge/_extensions/skills/smoke-test/scripts/smoke-test.sh +118 -0
  58. forge/_extensions/skills/understand/SKILL.md +148 -0
  59. forge/_extensions/skills/understand/resources/code-anthropic.md +163 -0
  60. forge/_extensions/skills/understand/resources/code-gemini.md +194 -0
  61. forge/_extensions/skills/understand/resources/code-openai.md +181 -0
  62. forge/_extensions/skills/understand/resources/code.md +163 -0
  63. forge/_extensions/skills/understand/resources/docs-anthropic.md +177 -0
  64. forge/_extensions/skills/understand/resources/docs-gemini.md +202 -0
  65. forge/_extensions/skills/understand/resources/docs-openai.md +191 -0
  66. forge/_extensions/skills/understand/resources/docs.md +177 -0
  67. forge/_extensions/skills/walkthrough/SKILL.md +599 -0
  68. forge/_extensions/skills/walkthrough/resources/checklist.md +765 -0
  69. forge/_extensions/skills/walkthrough/scripts/run-in-repo.sh +118 -0
  70. forge/_extensions/skills/walkthrough/scripts/setup-test-repo.sh +198 -0
  71. forge/_extensions/skills/walkthrough/scripts/walkthrough-state.py +1137 -0
  72. forge/backend/__init__.py +174 -0
  73. forge/backend/adapters/__init__.py +38 -0
  74. forge/backend/adapters/litellm.py +158 -0
  75. forge/backend/creation.py +89 -0
  76. forge/backend/registry.py +178 -0
  77. forge/cli/__init__.py +16 -0
  78. forge/cli/auth.py +483 -0
  79. forge/cli/backend.py +298 -0
  80. forge/cli/claude.py +411 -0
  81. forge/cli/config_cmd.py +303 -0
  82. forge/cli/extensions.py +1001 -0
  83. forge/cli/gc.py +165 -0
  84. forge/cli/guard.py +1018 -0
  85. forge/cli/guards.py +106 -0
  86. forge/cli/handoff.py +110 -0
  87. forge/cli/hooks/__init__.py +36 -0
  88. forge/cli/hooks/_group.py +20 -0
  89. forge/cli/hooks/_helpers.py +149 -0
  90. forge/cli/hooks/commands.py +1677 -0
  91. forge/cli/hooks/direct_commands.py +1304 -0
  92. forge/cli/hooks/install.py +232 -0
  93. forge/cli/hooks/policy.py +151 -0
  94. forge/cli/hooks/read_hygiene.py +74 -0
  95. forge/cli/hooks/verification.py +370 -0
  96. forge/cli/logs.py +406 -0
  97. forge/cli/main.py +292 -0
  98. forge/cli/proxy.py +1821 -0
  99. forge/cli/proxy_costs.py +313 -0
  100. forge/cli/search.py +416 -0
  101. forge/cli/session.py +892 -0
  102. forge/cli/session_addendum.py +81 -0
  103. forge/cli/session_fork.py +750 -0
  104. forge/cli/session_handoff.py +141 -0
  105. forge/cli/session_lifecycle.py +2053 -0
  106. forge/cli/session_manage.py +1336 -0
  107. forge/cli/session_memory.py +201 -0
  108. forge/cli/status_line.py +1398 -0
  109. forge/cli/workflow.py +1964 -0
  110. forge/config/__init__.py +110 -0
  111. forge/config/dataclass_utils.py +88 -0
  112. forge/config/defaults/__init__.py +0 -0
  113. forge/config/defaults/backends/__init__.py +0 -0
  114. forge/config/defaults/backends/litellm.yaml +196 -0
  115. forge/config/defaults/templates/__init__.py +0 -0
  116. forge/config/defaults/templates/litellm-anthropic-local.yaml +33 -0
  117. forge/config/defaults/templates/litellm-anthropic.yaml +24 -0
  118. forge/config/defaults/templates/litellm-gemini-flash-local.yaml +37 -0
  119. forge/config/defaults/templates/litellm-gemini-local.yaml +32 -0
  120. forge/config/defaults/templates/litellm-gemini-test.yaml +34 -0
  121. forge/config/defaults/templates/litellm-gemini.yaml +21 -0
  122. forge/config/defaults/templates/litellm-openai-codex-local.yaml +36 -0
  123. forge/config/defaults/templates/litellm-openai-local.yaml +38 -0
  124. forge/config/defaults/templates/litellm-openai.yaml +28 -0
  125. forge/config/defaults/templates/openrouter-anthropic.yaml +23 -0
  126. forge/config/defaults/templates/openrouter-deepseek.yaml +26 -0
  127. forge/config/defaults/templates/openrouter-gemini-flash.yaml +26 -0
  128. forge/config/defaults/templates/openrouter-gemini.yaml +23 -0
  129. forge/config/defaults/templates/openrouter-glm.yaml +23 -0
  130. forge/config/defaults/templates/openrouter-kimi.yaml +30 -0
  131. forge/config/defaults/templates/openrouter-minimax.yaml +26 -0
  132. forge/config/defaults/templates/openrouter-openai-codex.yaml +23 -0
  133. forge/config/defaults/templates/openrouter-openai.yaml +28 -0
  134. forge/config/defaults/templates/openrouter-qwen.yaml +25 -0
  135. forge/config/loader.py +675 -0
  136. forge/config/schema.py +448 -0
  137. forge/core/__init__.py +5 -0
  138. forge/core/auth/__init__.py +67 -0
  139. forge/core/auth/capabilities.py +219 -0
  140. forge/core/auth/credentials_file.py +244 -0
  141. forge/core/auth/protocols.py +18 -0
  142. forge/core/auth/secrets.py +243 -0
  143. forge/core/auth/template_secrets.py +112 -0
  144. forge/core/data/__init__.py +5 -0
  145. forge/core/data/model_catalog.yaml +1522 -0
  146. forge/core/data/pricing.yaml +140 -0
  147. forge/core/data/system_prompt_addendums/__init__.py +0 -0
  148. forge/core/data/system_prompt_addendums/gemini.md +330 -0
  149. forge/core/data/system_prompt_addendums/openai.md +328 -0
  150. forge/core/llm/__init__.py +231 -0
  151. forge/core/llm/clients/__init__.py +14 -0
  152. forge/core/llm/clients/base.py +115 -0
  153. forge/core/llm/clients/litellm.py +619 -0
  154. forge/core/llm/clients/openai_compat.py +244 -0
  155. forge/core/llm/clients/openrouter.py +234 -0
  156. forge/core/llm/credentials.py +439 -0
  157. forge/core/llm/detection.py +86 -0
  158. forge/core/llm/errors.py +44 -0
  159. forge/core/llm/protocols.py +80 -0
  160. forge/core/llm/types.py +176 -0
  161. forge/core/logging.py +146 -0
  162. forge/core/models/__init__.py +91 -0
  163. forge/core/models/catalog.py +467 -0
  164. forge/core/models/pricing.py +165 -0
  165. forge/core/models/types.py +167 -0
  166. forge/core/naming.py +212 -0
  167. forge/core/ops/__init__.py +73 -0
  168. forge/core/ops/context.py +141 -0
  169. forge/core/ops/gc.py +802 -0
  170. forge/core/ops/proxy.py +146 -0
  171. forge/core/ops/resolution.py +135 -0
  172. forge/core/ops/session.py +344 -0
  173. forge/core/ops/session_context.py +548 -0
  174. forge/core/paths.py +38 -0
  175. forge/core/process.py +54 -0
  176. forge/core/reactive/__init__.py +38 -0
  177. forge/core/reactive/cost_tracking.py +300 -0
  178. forge/core/reactive/env.py +180 -0
  179. forge/core/reactive/proxy.py +78 -0
  180. forge/core/reactive/routing.py +622 -0
  181. forge/core/reactive/session_runner.py +185 -0
  182. forge/core/reactive/structured_output.py +62 -0
  183. forge/core/reactive/tagger.py +94 -0
  184. forge/core/reactive/throttle.py +132 -0
  185. forge/core/state/__init__.py +59 -0
  186. forge/core/state/exceptions.py +59 -0
  187. forge/core/state/io.py +140 -0
  188. forge/core/state/lock.py +99 -0
  189. forge/core/state/timestamps.py +60 -0
  190. forge/core/transcript.py +78 -0
  191. forge/core/typing_helpers.py +24 -0
  192. forge/core/workqueue/__init__.py +67 -0
  193. forge/core/workqueue/queue.py +552 -0
  194. forge/core/workqueue/types.py +63 -0
  195. forge/guard/__init__.py +26 -0
  196. forge/guard/deterministic/__init__.py +26 -0
  197. forge/guard/deterministic/base.py +158 -0
  198. forge/guard/deterministic/coding_standards.py +256 -0
  199. forge/guard/deterministic/registry.py +148 -0
  200. forge/guard/deterministic/tdd.py +171 -0
  201. forge/guard/engine.py +216 -0
  202. forge/guard/protocols.py +91 -0
  203. forge/guard/queries.py +96 -0
  204. forge/guard/semantic/__init__.py +34 -0
  205. forge/guard/semantic/promotion.py +18 -0
  206. forge/guard/semantic/supervisor.py +813 -0
  207. forge/guard/semantic/verdict.py +183 -0
  208. forge/guard/store.py +124 -0
  209. forge/guard/team/__init__.py +6 -0
  210. forge/guard/team/config.py +24 -0
  211. forge/guard/team/handlers.py +209 -0
  212. forge/guard/team/prompts.py +41 -0
  213. forge/guard/types.py +125 -0
  214. forge/guard/workflow/__init__.py +17 -0
  215. forge/guard/workflow/branches.py +67 -0
  216. forge/guard/workflow/config.py +63 -0
  217. forge/guard/workflow/divergence.py +113 -0
  218. forge/guard/workflow/policy.py +87 -0
  219. forge/guard/workflow/stages.py +205 -0
  220. forge/install/__init__.py +55 -0
  221. forge/install/cli.py +281 -0
  222. forge/install/exceptions.py +163 -0
  223. forge/install/hooks.py +109 -0
  224. forge/install/installer.py +1037 -0
  225. forge/install/models.py +321 -0
  226. forge/install/preset.py +272 -0
  227. forge/install/settings_merge.py +831 -0
  228. forge/install/tracking.py +238 -0
  229. forge/install/version.py +141 -0
  230. forge/proxy/__init__.py +0 -0
  231. forge/proxy/base_client.py +181 -0
  232. forge/proxy/client_adapter.py +476 -0
  233. forge/proxy/client_factory.py +531 -0
  234. forge/proxy/converters.py +1206 -0
  235. forge/proxy/cost_logger.py +132 -0
  236. forge/proxy/cost_tracker.py +242 -0
  237. forge/proxy/data_models.py +338 -0
  238. forge/proxy/error_hints.py +92 -0
  239. forge/proxy/metrics.py +222 -0
  240. forge/proxy/model_spec.py +158 -0
  241. forge/proxy/proxies.py +333 -0
  242. forge/proxy/proxy_identity.py +134 -0
  243. forge/proxy/proxy_orchestrator.py +1018 -0
  244. forge/proxy/proxy_startup.py +54 -0
  245. forge/proxy/server.py +1561 -0
  246. forge/proxy/utils.py +537 -0
  247. forge/review/__init__.py +6 -0
  248. forge/review/adversarial.py +111 -0
  249. forge/review/consensus.py +236 -0
  250. forge/review/engine.py +356 -0
  251. forge/review/models.py +437 -0
  252. forge/review/resources/__init__.py +5 -0
  253. forge/review/resources/codereview-performance.md +85 -0
  254. forge/review/resources/codereview-quick.md +75 -0
  255. forge/review/resources/codereview-security.md +92 -0
  256. forge/review/resources/codereview.md +85 -0
  257. forge/review/resources/docreview-quick.md +75 -0
  258. forge/review/resources/docreview.md +86 -0
  259. forge/review/resources/thinkdeep.md +89 -0
  260. forge/review/routing.py +368 -0
  261. forge/review/synthesis.py +73 -0
  262. forge/runtime_config.py +438 -0
  263. forge/search/__init__.py +55 -0
  264. forge/search/bm25_store.py +264 -0
  265. forge/search/content_store.py +197 -0
  266. forge/search/engine.py +352 -0
  267. forge/search/exceptions.py +51 -0
  268. forge/search/extractor.py +234 -0
  269. forge/search/index_state.py +295 -0
  270. forge/search/store.py +215 -0
  271. forge/search/tokenizer.py +24 -0
  272. forge/session/__init__.py +130 -0
  273. forge/session/active.py +339 -0
  274. forge/session/artifacts.py +202 -0
  275. forge/session/claude/__init__.py +50 -0
  276. forge/session/claude/cleanup.py +105 -0
  277. forge/session/claude/invoke.py +236 -0
  278. forge/session/claude/paths.py +200 -0
  279. forge/session/cleanup.py +216 -0
  280. forge/session/config.py +34 -0
  281. forge/session/direct_model.py +107 -0
  282. forge/session/effective.py +169 -0
  283. forge/session/exceptions.py +255 -0
  284. forge/session/handoff.py +881 -0
  285. forge/session/handoff_agent.py +544 -0
  286. forge/session/hooks/__init__.py +35 -0
  287. forge/session/hooks/models.py +73 -0
  288. forge/session/hooks/session_start.py +507 -0
  289. forge/session/identity.py +84 -0
  290. forge/session/index.py +553 -0
  291. forge/session/manager.py +1506 -0
  292. forge/session/models.py +572 -0
  293. forge/session/overrides.py +344 -0
  294. forge/session/plan_resolution.py +286 -0
  295. forge/session/prev_sessions.py +128 -0
  296. forge/session/store.py +431 -0
  297. forge/session/validation.py +47 -0
  298. forge/session/worktree/__init__.py +65 -0
  299. forge/session/worktree/cleanup.py +262 -0
  300. forge/session/worktree/config_copy.py +203 -0
  301. forge/session/worktree/create.py +332 -0
  302. forge/sidecar/__init__.py +29 -0
  303. forge/sidecar/container.py +161 -0
  304. forge/sidecar/docker.py +86 -0
  305. forge/sidecar/secrets.py +19 -0
  306. multi_forge-0.2.0.dist-info/METADATA +242 -0
  307. multi_forge-0.2.0.dist-info/RECORD +311 -0
  308. multi_forge-0.2.0.dist-info/WHEEL +4 -0
  309. multi_forge-0.2.0.dist-info/entry_points.txt +2 -0
  310. multi_forge-0.2.0.dist-info/licenses/LICENSE +203 -0
  311. 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
+ ---