@wooojin/forgen 0.4.13 → 0.5.5

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 (166) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +261 -0
  3. package/README.ja.md +16 -12
  4. package/README.ko.md +12 -8
  5. package/README.md +90 -27
  6. package/README.zh.md +16 -12
  7. package/assets/claude/commands/forge-loop.md +7 -1
  8. package/assets/claude/commands/ship.md +18 -1
  9. package/assets/opencode/forgen.ts +52 -0
  10. package/assets/shared/hook-registry.json +210 -22
  11. package/dist/checks/_shared/meta-guard-dispatch.d.ts +7 -0
  12. package/dist/checks/_shared/meta-guard-dispatch.js +12 -2
  13. package/dist/checks/_shared/model-profile.d.ts +25 -0
  14. package/dist/checks/_shared/model-profile.js +63 -0
  15. package/dist/cli.js +99 -153
  16. package/dist/core/auto-compound-runner.d.ts +0 -11
  17. package/dist/core/auto-compound-runner.js +199 -92
  18. package/dist/core/changelog-cli.d.ts +4 -1
  19. package/dist/core/changelog-cli.js +8 -7
  20. package/dist/core/compound-consent.d.ts +15 -0
  21. package/dist/core/compound-consent.js +48 -0
  22. package/dist/core/compound-sweep-cli.d.ts +60 -0
  23. package/dist/core/compound-sweep-cli.js +374 -0
  24. package/dist/core/config-injector.d.ts +16 -1
  25. package/dist/core/config-injector.js +47 -28
  26. package/dist/core/dashboard-cli.js +40 -16
  27. package/dist/core/dashboard.d.ts +3 -4
  28. package/dist/core/dashboard.js +15 -34
  29. package/dist/core/dev-cli.d.ts +13 -0
  30. package/dist/core/dev-cli.js +70 -0
  31. package/dist/core/doctor.d.ts +16 -5
  32. package/dist/core/doctor.js +190 -176
  33. package/dist/core/drift-score.d.ts +2 -0
  34. package/dist/core/drift-score.js +9 -1
  35. package/dist/core/harness.js +115 -43
  36. package/dist/core/health-cli.d.ts +2 -0
  37. package/dist/core/health-cli.js +6 -1
  38. package/dist/core/host-detect.d.ts +3 -1
  39. package/dist/core/host-detect.js +26 -1
  40. package/dist/core/migrate-cli.js +15 -0
  41. package/dist/core/migrate-evidence-host.d.ts +2 -1
  42. package/dist/core/migrate-tenetx.d.ts +50 -0
  43. package/dist/core/migrate-tenetx.js +262 -0
  44. package/dist/core/probe-workflow-cli.d.ts +3 -3
  45. package/dist/core/probe-workflow-cli.js +13 -13
  46. package/dist/core/recall-cli.js +1 -1
  47. package/dist/core/regress-map-cli.js +1 -1
  48. package/dist/core/rendered-rules-manifest.d.ts +29 -0
  49. package/dist/core/rendered-rules-manifest.js +60 -0
  50. package/dist/core/session-store.js +14 -3
  51. package/dist/core/settings-injector.d.ts +3 -0
  52. package/dist/core/settings-injector.js +12 -16
  53. package/dist/core/spawn.d.ts +37 -1
  54. package/dist/core/spawn.js +116 -9
  55. package/dist/core/state-gc.js +1 -0
  56. package/dist/core/status-cli.d.ts +20 -0
  57. package/dist/core/status-cli.js +100 -0
  58. package/dist/core/statusline-cli.d.ts +7 -0
  59. package/dist/core/statusline-cli.js +63 -19
  60. package/dist/core/transcript-summary.d.ts +18 -0
  61. package/dist/core/transcript-summary.js +81 -0
  62. package/dist/core/trust-layer-intent.d.ts +21 -1
  63. package/dist/core/trust-layer-intent.js +7 -0
  64. package/dist/core/types.d.ts +3 -2
  65. package/dist/core/uninstall.js +12 -0
  66. package/dist/core/usage-telemetry.d.ts +7 -1
  67. package/dist/core/usage-telemetry.js +7 -9
  68. package/dist/core/v1-bootstrap.js +1 -1
  69. package/dist/core/watch-cli.js +1 -1
  70. package/dist/engine/compound-extractor.js +10 -0
  71. package/dist/engine/compound-loop.js +55 -7
  72. package/dist/engine/compound-share.d.ts +85 -0
  73. package/dist/engine/compound-share.js +606 -0
  74. package/dist/engine/correction-cluster-runner.d.ts +38 -0
  75. package/dist/engine/correction-cluster-runner.js +188 -0
  76. package/dist/engine/correction-clustering.d.ts +80 -0
  77. package/dist/engine/correction-clustering.js +167 -0
  78. package/dist/engine/enforce-classifier.d.ts +10 -1
  79. package/dist/engine/enforce-classifier.js +111 -22
  80. package/dist/engine/extraction-session.js +10 -3
  81. package/dist/engine/private-filter.d.ts +36 -0
  82. package/dist/engine/private-filter.js +100 -0
  83. package/dist/engine/ranking-pipeline.js +4 -2
  84. package/dist/engine/relevance-gate.d.ts +12 -0
  85. package/dist/engine/relevance-gate.js +12 -0
  86. package/dist/engine/roi-demotion.d.ts +79 -0
  87. package/dist/engine/roi-demotion.js +159 -0
  88. package/dist/engine/solution-format.d.ts +1 -0
  89. package/dist/engine/solution-format.js +26 -0
  90. package/dist/engine/solution-matcher.js +10 -1
  91. package/dist/fgx.js +7 -6
  92. package/dist/forge/cli.js +8 -2
  93. package/dist/hooks/compound-reflection.js +6 -1
  94. package/dist/hooks/context-guard.d.ts +16 -1
  95. package/dist/hooks/context-guard.js +99 -49
  96. package/dist/hooks/hook-config.js +5 -0
  97. package/dist/hooks/hook-registry.d.ts +6 -1
  98. package/dist/hooks/hooks-generator.js +3 -0
  99. package/dist/hooks/post-tool-use.js +2 -3
  100. package/dist/hooks/pre-compact.js +14 -0
  101. package/dist/hooks/pre-tool-use.js +5 -1
  102. package/dist/hooks/session-end.d.ts +34 -0
  103. package/dist/hooks/session-end.js +100 -0
  104. package/dist/hooks/session-recovery.js +18 -1
  105. package/dist/hooks/shared/hook-timing.js +6 -1
  106. package/dist/hooks/shared/stop-triggers.d.ts +29 -2
  107. package/dist/hooks/shared/stop-triggers.js +35 -2
  108. package/dist/hooks/solution-injector.d.ts +28 -0
  109. package/dist/hooks/solution-injector.js +126 -28
  110. package/dist/hooks/stop-guard.js +5 -2
  111. package/dist/hooks/subagent-stop-guard.js +4 -1
  112. package/dist/host/capabilities-claude.js +1 -0
  113. package/dist/host/capabilities-codex.js +1 -0
  114. package/dist/host/capabilities-opencode.d.ts +26 -0
  115. package/dist/host/capabilities-opencode.js +78 -0
  116. package/dist/host/capabilities-registry.d.ts +7 -0
  117. package/dist/host/capabilities-registry.js +14 -0
  118. package/dist/host/codex-rules-context.d.ts +25 -0
  119. package/dist/host/codex-rules-context.js +62 -0
  120. package/dist/host/exec-host.d.ts +14 -3
  121. package/dist/host/exec-host.js +15 -2
  122. package/dist/host/host-binding.d.ts +27 -0
  123. package/dist/host/host-binding.js +11 -0
  124. package/dist/host/host-runtime.js +18 -0
  125. package/dist/host/install-codex.d.ts +66 -0
  126. package/dist/host/install-codex.js +293 -25
  127. package/dist/host/install-opencode.d.ts +38 -0
  128. package/dist/host/install-opencode.js +148 -0
  129. package/dist/host/install-orchestrator.d.ts +4 -1
  130. package/dist/host/install-orchestrator.js +30 -1
  131. package/dist/host/invoke-agent.d.ts +3 -2
  132. package/dist/host/invoke-agent.js +1 -0
  133. package/dist/host/opencode/context-cli.d.ts +15 -0
  134. package/dist/host/opencode/context-cli.js +25 -0
  135. package/dist/host/opencode/guard-cli.d.ts +13 -0
  136. package/dist/host/opencode/guard-cli.js +39 -0
  137. package/dist/host/opencode/plugin/forgen.d.ts +31 -0
  138. package/dist/host/opencode/plugin/forgen.js +60 -0
  139. package/dist/host/opencode/translate.d.ts +49 -0
  140. package/dist/host/opencode/translate.js +96 -0
  141. package/dist/host/parity-harness.d.ts +10 -2
  142. package/dist/host/parity-harness.js +7 -3
  143. package/dist/host/projection.d.ts +37 -3
  144. package/dist/host/projection.js +104 -42
  145. package/dist/mcp/tools.js +17 -4
  146. package/dist/store/evidence-store.d.ts +2 -6
  147. package/dist/store/evidence-store.js +164 -46
  148. package/dist/store/host-mismatch.d.ts +2 -1
  149. package/dist/store/host-mismatch.js +8 -8
  150. package/dist/store/profile-store.d.ts +3 -2
  151. package/dist/store/rule-store.d.ts +41 -0
  152. package/dist/store/rule-store.js +77 -2
  153. package/dist/store/types.d.ts +9 -2
  154. package/hooks/hooks.json +13 -1
  155. package/package.json +3 -2
  156. package/plugin.json +2 -2
  157. package/skills/architecture-decision/SKILL.md +18 -0
  158. package/skills/calibrate/SKILL.md +18 -0
  159. package/skills/code-review/SKILL.md +17 -0
  160. package/skills/compound/SKILL.md +17 -0
  161. package/skills/deep-interview/SKILL.md +7 -0
  162. package/skills/docker/SKILL.md +18 -0
  163. package/skills/forge-loop/SKILL.md +30 -1
  164. package/skills/learn/SKILL.md +15 -0
  165. package/skills/retro/SKILL.md +16 -0
  166. package/skills/ship/SKILL.md +36 -1
package/README.md CHANGED
@@ -3,8 +3,9 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <strong>When your agent says "done", forgen makes it prove it.</strong><br/>
7
- Turn-level self-verification + personalized rules for <strong>Claude Code</strong> and <strong>Codex CLI</strong>, at <strong>$0 extra API cost</strong>.
6
+ <strong>forgen makes Claude fit <em>you</em> — and measures whether that actually helps, honestly.</strong><br/>
7
+ Your corrections become persistent rules; past solutions resurface when relevant; stale ones fade.<br/>
8
+ For <strong>Claude Code</strong> and <strong>Codex CLI</strong>, at <strong>$0 extra API cost</strong>.
8
9
  </p>
9
10
 
10
11
  <p align="center">
@@ -35,7 +36,7 @@
35
36
 
36
37
  ## The first block (30 seconds)
37
38
 
38
- You've been burned: Claude says "tests pass, implementation done" — you run it — it doesn't work. forgen closes that gap.
39
+ Here's forgen's most *visible* mechanism — a live guard you can trigger in 30 seconds. Fair warning up front (this is the honest-measurement tool, after all): on current frontier models this particular guard rarely fires, because Opus 4.8 / Sonnet 5 mostly stopped making unverified "done" claims on their own (we measured **blocks = 0** — see the caveat below). So treat this as a **safety net for weaker models and the occasional tail case**, not forgen's daily value. The daily value is quieter: your corrections becoming rules, and past solutions resurfacing. But the guard is the fastest thing to *see*, so we lead with it.
39
40
 
40
41
  ```
41
42
  You: "Update the auth middleware."
@@ -57,7 +58,7 @@ Claude: "측정 없이 점수를 매겼습니다. 실 테스트부터 실행합
57
58
 
58
59
  The same mechanism also fires when Claude writes conclusions faster than evidence ("done. passed. shipped. verified." with no measurement context), or claims facts ("테스트가 통과합니다") without ever having executed them. You can also define **custom rules** (e.g. "require npm test evidence before saying 'done' in this repo") via `forgen compound --rule` — they slot into the same Stop-hook dispatcher.
59
60
 
60
- This is **Mech-B self-check prompt-inject**. It works because Claude Code's Stop hook accepts `decision: "block"` + `reason`, and Claude in the next turn reads that reason as input. Codex CLI gets the same treatment via the symmetric host adapter (v0.4.3, [multi-host core design](docs/superpowers/specs/2026-04-27-forgen-multi-host-core-design.md)). We verified it end-to-end on 10 scenarios at $1.74 total cost ([A1 spike report](docs/spike/mech-b-a1-verification-report.md)), and v0.4.1 added built-in guards so you get the first block **without writing any rule**.
61
+ This is **Mech-B self-check prompt-inject**. It works because Claude Code's Stop hook accepts `decision: "block"` + `reason`, and Claude in the next turn reads that reason as input. Codex CLI gets the same treatment via the symmetric host adapter (v0.4.3, [multi-host core design](docs/superpowers/specs/2026-04-27-forgen-multi-host-core-design.md)). We verified it end-to-end on 10 scenarios at $1.74 total cost (A1 spike report — archived in git history, `docs/spike/` pre-v0.5.0), and v0.4.1 added built-in guards so you get the first block **without writing any rule**.
61
62
 
62
63
  > **v0.4.3 self-correction story:** the same guards detected their own 16-day false-positive (strict φ 65.66% — 84% from a single Korean-regex bug), and the [`forgen-eval`](packages/forgen-eval/) introspect testbed (alpha) flagged a `TEST-1` wiring gap on top of it. Both fixes shipped in v0.4.3 — forgen finding and fixing forgen. Details in [CHANGELOG](CHANGELOG.md).
63
64
 
@@ -73,18 +74,53 @@ This is **Mech-B self-check prompt-inject**. It works because Claude Code's Stop
73
74
  > is rescinded as a broken-testbed artifact; ψ (forgen+mem coexistence) is
74
75
  > confirmed as ≈0 — **forgen alone is the recommended path**. See
75
76
  > [`docs/release/v0.4.5-draft.md`](docs/release/v0.4.5-draft.md).
76
-
77
- 🎬 **See it happen** (27 seconds):
77
+ >
78
+ > **Scope caveat (v0.5.0, ADR-010 + 2026-07-20 honest null):** the δ numbers
79
+ > above were measured on the **models of their era** (Claude Sonnet 4.x-class,
80
+ > Codex) and we do **not** carry them forward as a claim about current frontier
81
+ > models. Two separate current-model findings, kept distinct:
82
+ >
83
+ > 1. **Completion-guard / false-completion pressure → null (honest).** On
84
+ > **Opus 4.8** and **Sonnet 5** we measured completion-guard **blocks = 0** —
85
+ > frontier models got honest on their own. Our v0.5.0 judge redesign re-scored the
86
+ > hard "false-completion pressure" cases and found **no measurable behavioral δ
87
+ > on that dataset** (all arms avoid blatant false completion;
88
+ > [`docs/release/v0.5.0-recalibration.md`](docs/release/v0.5.0-recalibration.md)).
89
+ > We publish that null rather than bury it.
90
+ >
91
+ > 2. **Cross-session user-specific policy adherence → δ > 0 (measured).** forgen's
92
+ > real mechanism is not blocking but *re-injecting your corrections in a later
93
+ > session where a vanilla model has no memory of them*. On that — the honest place
94
+ > the effect lives — we measured a **significant δ**: forgen makes the model follow
95
+ > the user's prior-session policies **14/14**, vanilla **4/14 (Sonnet 5)** / **7/14
96
+ > (Opus 4.8)** → **δ = 0.714, 95% CI [0.429, 0.929]** (Sonnet 5) and **δ = 0.500,
97
+ > 95% CI [0.214, 0.786]** (Opus 4.8), confirmed by a blind human rater (Cohen's
98
+ > κ = 0.748 vs the LLM judge)
99
+ > ([`docs/release/v0.5.0-persistence-delta.md`](docs/release/v0.5.0-persistence-delta.md)).
100
+ > **δ is orthogonal to model capability** — the stronger model (Opus) follows more
101
+ > general good-practice on its own, so δ shrinks there, but on *user-specific*
102
+ > policies neither model guesses right and only forgen does. This is
103
+ > **"internal measurement" grade**: the dataset is maintainer-authored (bootstrap),
104
+ > the judge is intra-family (Claude), and only one human rater has confirmed it. We
105
+ > do **not** make external effect claims until an independent rater panel + external
106
+ > reviewer + a cross-family judge reproduce it.
107
+ >
108
+ > What forgen reliably provides: **personalization** (corrections → persistent
109
+ > rules, cross-session δ above), **recall** (past solutions injected when relevant),
110
+ > **ROI demotion** of stale knowledge, and **deterministic guards** (secrets,
111
+ > destructive commands) that fire regardless of model honesty. Per-model guard
112
+ > behavior: measured-honest models get advisory mode instead of blocking.
113
+
114
+ 🎬 **See it happen** — try the guard live on your own install:
78
115
 
79
116
  ```bash
80
- # Watch the full loop live — actual hook, actual rule, actual block/approve cycle
81
- bash docs/demo/mech-b-demo.sh
82
-
83
- # Or replay the pre-recorded asciinema cast
84
- asciinema play docs/demo/mech-b-block-unblock.cast
117
+ # Real hook, real block: a self-score claim with zero measurement evidence
118
+ echo '{"session_id":"demo","last_assistant_message":"이번 작업 신뢰도 90% 로 평가됩니다."}' \
119
+ | node "$(npm root -g)/@wooojin/forgen/dist/hooks/stop-guard.js"
120
+ # → decision:"block" + the exact reason Claude reads on its next turn
85
121
  ```
86
122
 
87
- See [`docs/demo/README.md`](docs/demo/README.md) for what's real vs simulated in the demo.
123
+ (The pre-v0.5.0 scripted demo lived in `docs/demo/` — archived in git history.)
88
124
 
89
125
  ---
90
126
 
@@ -179,20 +215,21 @@ Behind the scenes:
179
215
 
180
216
  You say: "Don't refactor files I didn't ask you to touch."
181
217
 
182
- Claude calls the `correction-record` MCP tool. The correction is stored as structured evidence with axis classification (`judgment_philosophy`), kind (`avoid-this`), and confidence score. A temporary rule is created for immediate effect in the current session.
218
+ Claude calls the `correction-record` MCP tool. The correction is stored as structured evidence with axis classification (`judgment_philosophy`), kind (`avoid-this`), and confidence score. A temporary rule is created for immediate effect in the current session. At session end it promotes to a **permanent rule** — this deterministic corrections → rules path runs with **zero network egress** and is what our measured cross-session δ rides on.
219
+
220
+ Softer corrections you never explicitly flag ("음… 이렇게 최소로만 짜면 나중에 다 다시 해야 하는 거 아니야?") are harder to catch in real time. If you opt into transcript extraction (below), forgen also **retroactively mines** those from the conversation — but such auto-mined rules are **advisory-only** (they surface as context, never block or enforce) and age out if you never act on them.
183
221
 
184
222
  ### Between sessions (automatic)
185
223
 
186
- When a session ends, auto-compound extracts:
187
- - Solutions (reusable patterns with context)
188
- - Behavioral observations (how you work)
189
- - A session learning summary
224
+ **Always on (deterministic, zero egress):** your explicit corrections promote to permanent rules; near-duplicate corrections cluster and strengthen; facets micro-adjust from accumulated evidence; a time-based `compound sweep` backstop (optionally on cron) makes sure long or interrupted sessions don't lose that learning.
190
225
 
191
- Facets are micro-adjusted based on accumulated evidence. If your corrections consistently point away from your current pack, mismatch detection triggers after 3 sessions and recommends a pack change.
226
+ **Opt-in (`forgen compound consent on`):** a background Haiku pass reads a *redacted summary* of the session transcript to extract reusable solutions, behavioral observations, and the softer corrections above. This is **off by default** — forgen does not send your conversations anywhere unless you turn it on, and secrets / `<private>` ranges are stripped before anything is sent. `forgen doctor` always shows the current state.
227
+
228
+ If your corrections consistently point away from your current pack, mismatch detection triggers after 3 sessions and recommends a pack change.
192
229
 
193
230
  ### Next session
194
231
 
195
- Updated rules are rendered with your corrections included. Compound knowledge is searchable via MCP. Retrieval precision grows as your personal accumulation grows — the mechanism is in place from day 1 (starter-pack covers common dev queries on a fresh install), and the signal-to-noise ratio improves over roughly 2–4 weeks of real use as low-fitness solutions are auto-demoted and your specific patterns get promoted.
232
+ Updated rules are rendered with your corrections included. Compound knowledge is searchable via MCP. The retrieval mechanism is in place from day 1 (starter-pack covers common dev queries on a fresh install); as you accumulate your own solutions, low-fitness ones get auto-demoted (ROI loop) and your specific patterns get promoted, so what surfaces skews toward *your* corpus over time. We describe this as a mechanism, not a measured speedup — we make no effect-size claim (see the honest-null caveat above).
196
233
 
197
234
  ---
198
235
 
@@ -207,6 +244,7 @@ forgen install both # 3-choice interactive: claude / codex / both
207
244
  # or non-interactive:
208
245
  forgen install claude
209
246
  forgen install codex
247
+ # Codex only: trust the forgen hooks once with `/hooks` inside codex — Codex skips untrusted hooks (forgen doctor shows [Codex Hooks])
210
248
 
211
249
  # 3. First run — 4-question onboarding (English or Korean)
212
250
  forgen # default: Claude
@@ -229,7 +267,7 @@ forgen doctor --quick
229
267
 
230
268
  > **Vendor dependency:** Forgen wraps Claude Code and Codex CLI symmetrically (Claude is the behavior reference; Codex extends with equivalence). Upstream API/CLI changes may affect behavior. Tested with Claude Code 1.0.x / 2.1.x and Codex 0.x.
231
269
 
232
- > **Upgrading from v0.4.x?** Run `forgen install claude` (or `codex` / `both`) after upgrading — v0.4.3+ requires explicit host registration. Then `forgen doctor --quick` to verify.
270
+ > **Upgrading from v0.4.x?** Run `forgen install claude` (or `codex` / `both`) after upgrading — v0.4.3+ requires explicit host registration. Then run `forgen migrate tenetx --dry-run` to preview and reclaim legacy global rule sprawl (v0.5.0 moved ALL rule injection to project scope — stale `~/.claude/rules/forge-*.md` from older versions should be reclaimed; see CHANGELOG). Finally `forgen doctor --quick` to verify.
233
271
 
234
272
  ### Try your first block
235
273
 
@@ -349,8 +387,8 @@ entries in `~/.forgen/state/implicit-feedback.jsonl`. Idempotent — safe to re-
349
387
  | |
350
388
  v |
351
389
  +------------------+ |
352
- | Session Ends | auto-compound extracts: |
353
- | | solutions + observations + summary |
390
+ | Session Ends | corrections -> rules (always, egress 0) |
391
+ | | transcript extract: opt-in (Haiku) |
354
392
  +--------+---------+ |
355
393
  | |
356
394
  v |
@@ -399,6 +437,30 @@ Each solution starts as an `experiment`. As it gets reflected in your code acros
399
437
  | **Behavioral patterns** | Auto-detected at 3+ observations | Applied to `forge-behavioral.md` |
400
438
  | **Evidence** | Corrections + observations | Drives facet adjustments + rule creation |
401
439
 
440
+ *Solutions and behavioral patterns come from the **opt-in** transcript-extraction pass (`forgen compound consent on`, off by default). Corrections → rules and facet adjustments are always-on and never leave your machine.*
441
+
442
+ ### Keeping things out of the corpus (`<private>`)
443
+
444
+ Wrap anything you don't want learned in a `<private>…</private>` block, or end a
445
+ line with a `// forgen:private` marker (`#` and `/*` comment styles also work):
446
+
447
+ ```
448
+ Here's the approach — <private>internal API key rotation playbook</private> — use it.
449
+ const token = "…"; // forgen:private
450
+ ```
451
+
452
+ Those ranges are stripped before every learning-corpus capture path: correction
453
+ records, solution extraction, the automatic session-end compound runner,
454
+ prompt-history, and session-search indexing. Unclosed or malformed tags **fail
455
+ closed** (treated as private to end-of-text) so a forgotten `</private>` never
456
+ leaks.
457
+
458
+ > **Scope:** `<private>` controls **what forgen learns from**, not what the model
459
+ > sees. The text was already sent to Claude as part of your conversation — the tag
460
+ > excludes it from persistent capture (compound solutions, evidence, search index),
461
+ > it does not make the current turn private. This is a separate axis from the
462
+ > secret-filter, which blocks credentials from being committed.
463
+
402
464
  ### Solution auto-injection
403
465
 
404
466
  Every prompt you type is matched against your accumulated solutions. Relevant ones are automatically injected into Claude's context — no manual lookup needed.
@@ -672,9 +734,10 @@ forgen skill list # List promoted skills
672
734
 
673
735
  ```bash
674
736
  forgen init # Initialize project (+ 15 starter-pack solutions)
675
- forgen migrate [implicit-feedback|all]
676
- # One-shot schema migrations (idempotent)
677
- forgen doctor # System diagnostics (10 categories + harness maturity)
737
+ forgen migrate [implicit-feedback|evidence-host|tenetx|all]
738
+ # One-shot migrations (idempotent). tenetx: reclaim
739
+ # legacy global rules (--dry-run/--yes/--apply-settings)
740
+ forgen doctor # Forgen-specific diagnostics (plugin cache, hooks, state, parity, gates — env health: native /doctor)
678
741
  forgen doctor --prune-state # Daily hygiene: state GC + T4 rule decay (90d idle → retire)
679
742
  forgen dashboard # Knowledge overview (6 sections)
680
743
  forgen config hooks # View hook status + context budget
@@ -712,7 +775,7 @@ Three CI gates prove forgen does not violate its own L1 rules before release:
712
775
  ```bash
713
776
  node scripts/self-gate.cjs # Static: mock-in-prod, secrets, enforce_via, release-artifact
714
777
  node scripts/self-gate-runtime.cjs # Runtime smoke: 6 hook scenarios
715
- node scripts/self-gate-release.cjs # Tag-only: version/tag/CHANGELOG/dist/e2e-report consistency
778
+ node scripts/self-gate-release.cjs # Tag-only: version/tag/CHANGELOG/dist/smoke-report consistency
716
779
  ```
717
780
 
718
781
  Triggered by `.github/workflows/self-gate.yml` on push main / PR main / tag v*. Dogfood opt-in: see [.forgen/README.md](.forgen/README.md).
@@ -843,7 +906,7 @@ forgen and [claude-mem](https://github.com/thedotmack/claude-mem) solve **comple
843
906
  | **Trigger** | Stop / PreToolUse hooks | UserPromptSubmit hook |
844
907
  | **Cost** | $0 (in-turn block/reason) | $0 (vector recall, local) |
845
908
 
846
- Install both as separate Claude Code plugins (Plugin model — forgen does not bundle claude-mem; AGPL-3.0 stays at arm's length). When both are present forgen's auto-detect yields context budget so claude-mem's recall has room to land, and the orchestration contract — order, failure isolation, Stop-hook ownership — is documented in [ADR-004](docs/adr/ADR-004-claude-mem-hook-orchestration.md). The pairing is one of the 5 arms tracked by [forgen-eval](packages/forgen-eval/) (see [claude-mem spike](docs/spike/2026-04-28-claude-mem-spike.md)).
909
+ Install both as separate Claude Code plugins (Plugin model — forgen does not bundle claude-mem; AGPL-3.0 stays at arm's length). When both are present forgen's auto-detect yields context budget so claude-mem's recall has room to land, and the orchestration contract — order, failure isolation, Stop-hook ownership — is documented in [ADR-004](docs/adr/ADR-004-claude-mem-hook-orchestration.md). The pairing is one of the 5 arms tracked by [forgen-eval](packages/forgen-eval/) (claude-mem spike report — archived in git history, `docs/spike/` pre-v0.5.0).
847
910
 
848
911
  ```
849
912
  You: "fix the auth flow"
package/README.zh.md CHANGED
@@ -55,19 +55,19 @@ Claude: "撤回完成声明。证据文件不存在。先执行 e2e..."
55
55
 
56
56
  **刚刚发生了什么**: Claude 的 Stop hook 被你定义的规则 (`L1-e2e-before-done`) 拦截。Claude 读取了 block `reason`, 撤回过早的完成声明, 产生证据, 重新提交。**零额外 API 调用** — 全部发生在 Claude 本来就会产出的同一个 session turn 内。
57
57
 
58
- 这就是 **Mech-B 自检 prompt-inject**。它工作是因为 Claude Code 的 Stop hook 接受 `decision: "block"` + `reason`, 而 Claude 在下一轮把那个 reason 作为输入读取。我们用 10 个场景、$1.74 总成本端到端验证 ([A1 spike report](docs/spike/mech-b-a1-verification-report.md))。
58
+ 这就是 **Mech-B 自检 prompt-inject**。它工作是因为 Claude Code 的 Stop hook 接受 `decision: "block"` + `reason`, 而 Claude 在下一轮把那个 reason 作为输入读取。我们用 10 个场景、$1.74 总成本端到端验证 (A1 spike report — 已归档于 git 历史, `docs/spike/` pre-v0.5.0)。
59
59
 
60
60
  🎬 **观看实际运行** (27秒):
61
61
 
62
62
  ```bash
63
63
  # 现场观看完整循环 — 真实的 hook、真实的规则、真实的 block/approve 周期
64
- bash docs/demo/mech-b-demo.sh
64
+ # demo 脚本已归档于 git 历史 (docs/demo/ pre-v0.5.0)
65
65
 
66
66
  # 或重放预录制的 asciinema cast
67
- asciinema play docs/demo/mech-b-block-unblock.cast
67
+ # asciinema cast 同上
68
68
  ```
69
69
 
70
- 关于 demo 中"真实 vs 模拟"的详情见 [`docs/demo/README.md`](docs/demo/README.md)。
70
+
71
71
 
72
72
  ---
73
73
 
@@ -162,16 +162,17 @@ forgen # 用它代替 `claude`
162
162
 
163
163
  你说: "不要重构我没要求你动的文件。"
164
164
 
165
- Claude 调用 `correction-record` MCP 工具。纠正作为结构化证据存储,包含轴分类(`judgment_philosophy`)、种类(`avoid-this`)和置信度分数。为当前会话创建一条临时规则以立即生效。
165
+ Claude 调用 `correction-record` MCP 工具。纠正作为结构化证据存储,包含轴分类(`judgment_philosophy`)、种类(`avoid-this`)和置信度分数。为当前会话创建一条临时规则以立即生效。会话结束时,该规则会晋升为**永久规则** —— 这条确定性的 corrections → rules 路径以**零网络 egress** 运行,我们测得的 cross-session δ 正是建立在这条路径上。
166
+
167
+ 那些你从未明确指出的柔性纠正("嗯…只写这么点最小实现,以后不会全部返工吗?")在实时中更难捕捉。如果你 opt-in 启用 transcript 提取(见下文),forgen 还会从对话中**回溯挖掘(retroactively mine)**这类纠正 —— 但这样自动挖掘出的规则是 **advisory-only**(仅作为上下文呈现,绝不阻断或强制),若你始终不采纳,它们会随时间 age-out。
166
168
 
167
169
  ### 会话之间(自动)
168
170
 
169
- 会话结束时,auto-compound 提取:
170
- - 解决方案(带上下文的可复用模式)
171
- - 行为观察(你的工作方式)
172
- - 会话学习摘要
171
+ **Always on(确定性,egress 0):** 你的明确纠正晋升为永久规则; 近乎重复的纠正被聚类并强化; facet 基于累积证据微调; 一个基于时间的 `compound sweep` 兜底机制(可选择挂到 cron)确保漫长或被中断的会话不会丢失这些学习。
173
172
 
174
- 基于累积的证据对 facet 进行微调。如果你的纠正持续指向与当前 pack 不同的方向,3个会话后触发不匹配检测,推荐更换 pack。
173
+ **Opt-in(`forgen compound consent on`):** 后台的 Haiku 通道读取会话 transcript 的*脱敏(redacted)摘要*,提取可复用的解决方案、行为观察,以及上述柔性纠正。它**默认关闭** —— 除非你开启,否则 forgen 不会把你的对话发送到任何地方,且在发送前会剥离 secret / `<private>` 区间。`forgen doctor` 始终显示当前状态。
174
+
175
+ 如果你的纠正持续指向与当前 pack 不同的方向,3个会话后触发不匹配检测,推荐更换 pack。
175
176
 
176
177
  ### 下一个会话
177
178
 
@@ -190,6 +191,7 @@ forgen install both # 三选交互: claude / codex / both
190
191
  # 或非交互:
191
192
  forgen install claude
192
193
  forgen install codex
194
+ # 仅 Codex: 在 codex 内用 `/hooks` 信任一次 forgen 钩子 — Codex 会跳过未信任的钩子 (用 forgen doctor 的 [Codex Hooks] 查看)
193
195
 
194
196
  # 3. 首次运行 — 4题引导问卷 (英语/韩语选择)
195
197
  forgen # 默认: Claude
@@ -269,8 +271,8 @@ forgen config default-host codex # 设置持久默认主机
269
271
  | |
270
272
  v |
271
273
  +------------------+ |
272
- | 会话结束 | auto-compound 提取: |
273
- | | 解决方案 + 观察 + 摘要 |
274
+ | 会话结束 | corrections -> rules (始终, egress 0) |
275
+ | | transcript 提取: opt-in (Haiku) |
274
276
  +--------+---------+ |
275
277
  | |
276
278
  v |
@@ -300,6 +302,8 @@ experiment (0.30) → candidate (0.55) → verified (0.75) → mature (0.90)
300
302
  | **行为模式** | 3次以上观察时自动检测 | 应用到 `forge-behavioral.md` |
301
303
  | **证据** | 纠正 + 观察 | 驱动 facet 调整 + 规则创建 |
302
304
 
305
+ *解决方案与行为模式来自 **opt-in** 的 transcript 提取通道(`forgen compound consent on`,默认关闭)。corrections → rules 与 facet 调整则始终在线(always-on),绝不离开你的机器。*
306
+
303
307
  ### 解决方案自动注入
304
308
 
305
309
  你输入的每个提示都会与你积累的解决方案进行匹配。相关的解决方案会自动注入 Claude 的上下文 — 无需手动查找。
@@ -88,13 +88,19 @@ PRD 확정 직후 **반드시** `~/.forgen/state/forge-loop.json`에 저장:
88
88
  mkdir -p ~/.forgen/state
89
89
  cat > ~/.forgen/state/forge-loop.json <<EOF
90
90
  {"active":true,"startedAt":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","stories":[
91
- {"id":"US-001","title":"...","passes":false,"attempts":0}
91
+ {"id":"US-001","title":"...","passes":false,"attempts":0,"acceptanceCriteria":["..."]}
92
92
  ]}
93
93
  EOF
94
94
  ```
95
95
 
96
96
  이 파일이 있어야 Claude가 중간에 멈추지 않도록 Stop 훅이 차단합니다.
97
+ 소유 세션은 최초 차단 시점에 Stop 훅이 자동 귀속하므로(`sessionId` 필드) 이
98
+ 파일을 쓸 때 세션 ID를 직접 넣을 필요는 없습니다 — 단, 귀속된 세션과 다른
99
+ 세션에서는 이 루프가 차단하지 않습니다. 24시간 이상 갱신이 없으면 자동
100
+ 해제(1회성 안내 포함)되며, 연속 30회 차단 시에도 안전 상한으로 자동 해제됩니다.
97
101
  스토리 완료 시 `passes: true`로 업데이트. 전체 완료는 Stop 훅이 자동 처리.
102
+ `acceptanceCriteria[0]`은 차단 메시지에 `AC1:`로 노출되므로 있으면 첫 항목을
103
+ 구체적이고 검증 가능한 문장으로 작성하세요 (없어도 정상 동작).
98
104
 
99
105
  ### goal-only 모드 — Phase 1 종료 분기
100
106
 
@@ -166,10 +166,27 @@ npm version {patch|minor|major} --no-git-tag-version
166
166
 
167
167
  커밋을 주제별 그룹핑 -> CHANGELOG.md 상단에 추가.
168
168
 
169
+ ## Step 6.5: Smoke 증거 생성 (forgen 레포 한정)
170
+
171
+ forgen 레포 자체를 ship 할 때는 릴리스 커밋 전에 smoke 증거를 생성한다
172
+ (ADR-010 W0-2 — CI self-gate 가 릴리스 커밋에서 smoke-report 를 요구).
173
+
174
+ ```bash
175
+ # forgen 레포에서만. vitest 는 Step 3 에서 이미 돌았지만 게이트 증거는
176
+ # smoke.cjs 산출물만 인정 — 전체 실행 (실제 프로세스 산출물 원칙).
177
+ if [ -f scripts/smoke.cjs ]; then
178
+ node scripts/smoke.cjs || ABORT
179
+ fi
180
+ ```
181
+
182
+ - 실패 -> ABORT ("smoke 증거 생성 실패 — 게이트 통과 불가")
183
+
169
184
  ## Step 7: 릴리스 커밋
170
185
 
171
186
  ```bash
172
- git add package.json CHANGELOG.md
187
+ git add package.json package-lock.json CHANGELOG.md
188
+ # forgen 레포: smoke 증거 포함
189
+ [ -f .forgen-release/smoke-report.json ] && git add .forgen-release/smoke-report.json
173
190
  git commit -m "release: v{version}"
174
191
  ```
175
192
 
@@ -0,0 +1,52 @@
1
+ // forgen-managed — do not edit; regenerated by `forgen install opencode`
2
+ /**
3
+ * forgen — OpenCode plugin (W3-3 P1). forgen 결정적 가드 + 개인화 브릿지:
4
+ * - tool.execute.before → forgen opencode-guard → block 이면 throw(도구 차단).
5
+ * - experimental.session.compacting → forgen opencode-context → forge-loop 상태 유지.
6
+ * 얇은 shim — 로직은 forgen 소유(drift-free). async execFile(이벤트루프 비차단).
7
+ * GUARD_CMD/CONTEXT_CMD 는 install-opencode 가 절대경로로 치환(런타임 PATH 비의존).
8
+ */
9
+ import { execFile } from "node:child_process"
10
+
11
+ // forgen:guard-cmd — install-opencode 가 [node, <절대 cli 경로>, opencode-guard] 로 치환
12
+ const GUARD_CMD: string[] = ["forgen", "opencode-guard"]
13
+ // forgen:context-cmd — install-opencode 가 [node, <절대 cli 경로>, opencode-context] 로 치환
14
+ const CONTEXT_CMD: string[] = ["forgen", "opencode-context"]
15
+
16
+ function runForgen(cmd: string[], stdin: string, timeout: number): Promise<string> {
17
+ return new Promise((resolve) => {
18
+ const [bin, ...rest] = cmd
19
+ const child = execFile(bin, rest, { timeout, encoding: "utf-8" }, (err, stdout) => {
20
+ if (err) console.error("[forgen] 호출 실패(fail-open):", err.message)
21
+ resolve(stdout || "")
22
+ })
23
+ child.stdin?.end(stdin)
24
+ })
25
+ }
26
+
27
+ export const forgen = async () => ({
28
+ "tool.execute.before": async (
29
+ input: { tool?: string },
30
+ output: { args?: Record<string, unknown> },
31
+ ) => {
32
+ const out = await runForgen(GUARD_CMD, JSON.stringify({ tool: input?.tool, args: output?.args }), 8000)
33
+ let decision: { block?: boolean; reason?: string } = { block: false }
34
+ try {
35
+ if (out) decision = JSON.parse(out)
36
+ } catch {
37
+ /* fail-open */
38
+ }
39
+ if (decision.block) throw new Error(decision.reason || "[forgen] blocked by guard")
40
+ },
41
+ "experimental.session.compacting": async (
42
+ _input: unknown,
43
+ output: { context?: string[] },
44
+ ) => {
45
+ const ctx = await runForgen(CONTEXT_CMD, "", 5000)
46
+ if (ctx.trim() && Array.isArray(output?.context)) {
47
+ output.context.push(ctx.trim())
48
+ }
49
+ },
50
+ })
51
+
52
+ export default forgen
@@ -1,24 +1,212 @@
1
1
  [
2
- { "name": "notepad-injector", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/notepad-injector.js", "timeout": 3, "compoundCritical": false },
3
- { "name": "context-guard", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/context-guard.js", "timeout": 2, "compoundCritical": false },
4
- { "name": "session-recovery", "tier": "compound-core", "event": "SessionStart", "matcher": "*", "script": "hooks/session-recovery.js", "timeout": 3, "compoundCritical": true },
5
- { "name": "post-tool-use", "tier": "compound-core", "event": "PostToolUse", "matcher": "*", "script": "hooks/post-tool-use.js", "timeout": 3, "compoundCritical": true },
6
- { "name": "pre-compact", "tier": "compound-core", "event": "PreCompact", "matcher": "*", "script": "hooks/pre-compact.js", "timeout": 3, "compoundCritical": false },
7
- { "name": "context-guard-stop", "tier": "compound-core", "event": "Stop", "matcher": "*", "script": "hooks/context-guard.js", "timeout": 5, "compoundCritical": false },
8
- { "name": "stop-guard", "tier": "compound-core", "event": "Stop", "matcher": "*", "script": "hooks/stop-guard.js", "timeout": 10, "compoundCritical": true },
9
- { "name": "pre-tool-use", "tier": "compound-core", "event": "PreToolUse", "matcher": "*", "script": "hooks/pre-tool-use.js", "timeout": 3, "compoundCritical": true },
10
- { "name": "secret-filter", "tier": "safety", "event": "PostToolUse", "matcher": "Write|Edit|Bash", "script": "hooks/secret-filter.js", "timeout": 3, "compoundCritical": false },
11
- { "name": "slop-detector", "tier": "safety", "event": "PostToolUse", "matcher": "Write|Edit", "script": "hooks/slop-detector.js", "timeout": 3, "compoundCritical": false },
12
- { "name": "db-guard", "tier": "safety", "event": "PreToolUse", "matcher": "Bash", "script": "hooks/db-guard.js", "timeout": 3, "compoundCritical": false },
13
- { "name": "rate-limiter", "tier": "safety", "event": "PreToolUse", "matcher": "*", "script": "hooks/rate-limiter.js", "timeout": 2, "compoundCritical": false },
14
- { "name": "intent-classifier", "tier": "workflow", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/intent-classifier.js", "timeout": 3, "compoundCritical": false },
15
- { "name": "keyword-detector", "tier": "workflow", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/keyword-detector.js", "timeout": 5, "compoundCritical": false },
16
- { "name": "permission-handler", "tier": "workflow", "event": "PermissionRequest", "matcher": "*", "script": "hooks/permission-handler.js", "timeout": 2, "compoundCritical": false },
17
- { "name": "subagent-tracker-start", "tier": "workflow", "event": "SubagentStart", "matcher": "*", "script": "hooks/subagent-tracker.js start", "timeout": 2, "compoundCritical": false },
18
- { "name": "subagent-tracker-stop", "tier": "workflow", "event": "SubagentStop", "matcher": "*", "script": "hooks/subagent-tracker.js stop", "timeout": 2, "compoundCritical": false },
19
- { "name": "subagent-stop-guard", "tier": "workflow", "event": "SubagentStop", "matcher": "*", "script": "hooks/subagent-stop-guard.js", "timeout": 10, "compoundCritical": false },
20
- { "name": "post-tool-failure", "tier": "workflow", "event": "PostToolUseFailure", "matcher": "*", "script": "hooks/post-tool-failure.js", "timeout": 3, "compoundCritical": false },
21
- { "name": "solution-injector", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/solution-injector.js", "timeout": 5, "compoundCritical": true },
22
- { "name": "skill-injector", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/skill-injector.js", "timeout": 5, "compoundCritical": true },
23
- { "name": "forge-loop-progress", "tier": "compound-core", "event": "UserPromptSubmit", "matcher": "*", "script": "hooks/forge-loop-progress.js", "timeout": 2, "compoundCritical": false }
2
+ {
3
+ "name": "notepad-injector",
4
+ "tier": "compound-core",
5
+ "event": "UserPromptSubmit",
6
+ "matcher": "*",
7
+ "script": "hooks/notepad-injector.js",
8
+ "timeout": 3,
9
+ "compoundCritical": false
10
+ },
11
+ {
12
+ "name": "context-guard",
13
+ "tier": "compound-core",
14
+ "event": "UserPromptSubmit",
15
+ "matcher": "*",
16
+ "script": "hooks/context-guard.js",
17
+ "timeout": 2,
18
+ "compoundCritical": false
19
+ },
20
+ {
21
+ "name": "session-recovery",
22
+ "tier": "compound-core",
23
+ "event": "SessionStart",
24
+ "matcher": "*",
25
+ "script": "hooks/session-recovery.js",
26
+ "timeout": 3,
27
+ "compoundCritical": true
28
+ },
29
+ {
30
+ "name": "post-tool-use",
31
+ "tier": "compound-core",
32
+ "event": "PostToolUse",
33
+ "matcher": "*",
34
+ "script": "hooks/post-tool-use.js",
35
+ "timeout": 3,
36
+ "compoundCritical": true
37
+ },
38
+ {
39
+ "name": "pre-compact",
40
+ "tier": "compound-core",
41
+ "event": "PreCompact",
42
+ "matcher": "*",
43
+ "script": "hooks/pre-compact.js",
44
+ "timeout": 3,
45
+ "compoundCritical": false
46
+ },
47
+ {
48
+ "name": "context-guard-stop",
49
+ "tier": "compound-core",
50
+ "event": "Stop",
51
+ "matcher": "*",
52
+ "script": "hooks/context-guard.js",
53
+ "timeout": 5,
54
+ "compoundCritical": false
55
+ },
56
+ {
57
+ "name": "stop-guard",
58
+ "tier": "compound-core",
59
+ "event": "Stop",
60
+ "matcher": "*",
61
+ "script": "hooks/stop-guard.js",
62
+ "timeout": 10,
63
+ "compoundCritical": true
64
+ },
65
+ {
66
+ "name": "pre-tool-use",
67
+ "tier": "compound-core",
68
+ "event": "PreToolUse",
69
+ "matcher": "*",
70
+ "script": "hooks/pre-tool-use.js",
71
+ "timeout": 3,
72
+ "compoundCritical": true
73
+ },
74
+ {
75
+ "name": "secret-filter",
76
+ "tier": "safety",
77
+ "event": "PostToolUse",
78
+ "matcher": "Write|Edit|Bash",
79
+ "script": "hooks/secret-filter.js",
80
+ "timeout": 3,
81
+ "compoundCritical": false
82
+ },
83
+ {
84
+ "name": "slop-detector",
85
+ "tier": "safety",
86
+ "event": "PostToolUse",
87
+ "matcher": "Write|Edit",
88
+ "script": "hooks/slop-detector.js",
89
+ "timeout": 3,
90
+ "compoundCritical": false
91
+ },
92
+ {
93
+ "name": "db-guard",
94
+ "tier": "safety",
95
+ "event": "PreToolUse",
96
+ "matcher": "Bash",
97
+ "script": "hooks/db-guard.js",
98
+ "timeout": 3,
99
+ "compoundCritical": false
100
+ },
101
+ {
102
+ "name": "rate-limiter",
103
+ "tier": "safety",
104
+ "event": "PreToolUse",
105
+ "matcher": "*",
106
+ "script": "hooks/rate-limiter.js",
107
+ "timeout": 2,
108
+ "compoundCritical": false
109
+ },
110
+ {
111
+ "name": "intent-classifier",
112
+ "tier": "workflow",
113
+ "event": "UserPromptSubmit",
114
+ "matcher": "*",
115
+ "script": "hooks/intent-classifier.js",
116
+ "timeout": 3,
117
+ "compoundCritical": false
118
+ },
119
+ {
120
+ "name": "keyword-detector",
121
+ "tier": "workflow",
122
+ "event": "UserPromptSubmit",
123
+ "matcher": "*",
124
+ "script": "hooks/keyword-detector.js",
125
+ "timeout": 5,
126
+ "compoundCritical": false
127
+ },
128
+ {
129
+ "name": "permission-handler",
130
+ "tier": "workflow",
131
+ "event": "PermissionRequest",
132
+ "matcher": "*",
133
+ "script": "hooks/permission-handler.js",
134
+ "timeout": 2,
135
+ "compoundCritical": false
136
+ },
137
+ {
138
+ "name": "subagent-tracker-start",
139
+ "tier": "workflow",
140
+ "event": "SubagentStart",
141
+ "matcher": "*",
142
+ "script": "hooks/subagent-tracker.js start",
143
+ "timeout": 2,
144
+ "compoundCritical": false
145
+ },
146
+ {
147
+ "name": "subagent-tracker-stop",
148
+ "tier": "workflow",
149
+ "event": "SubagentStop",
150
+ "matcher": "*",
151
+ "script": "hooks/subagent-tracker.js stop",
152
+ "timeout": 2,
153
+ "compoundCritical": false
154
+ },
155
+ {
156
+ "name": "subagent-stop-guard",
157
+ "tier": "workflow",
158
+ "event": "SubagentStop",
159
+ "matcher": "*",
160
+ "script": "hooks/subagent-stop-guard.js",
161
+ "timeout": 10,
162
+ "compoundCritical": false
163
+ },
164
+ {
165
+ "name": "post-tool-failure",
166
+ "tier": "workflow",
167
+ "event": "PostToolUseFailure",
168
+ "matcher": "*",
169
+ "script": "hooks/post-tool-failure.js",
170
+ "timeout": 3,
171
+ "compoundCritical": false
172
+ },
173
+ {
174
+ "name": "solution-injector",
175
+ "tier": "compound-core",
176
+ "event": "UserPromptSubmit",
177
+ "matcher": "*",
178
+ "script": "hooks/solution-injector.js",
179
+ "timeout": 5,
180
+ "compoundCritical": true
181
+ },
182
+ {
183
+ "name": "skill-injector",
184
+ "tier": "compound-core",
185
+ "event": "UserPromptSubmit",
186
+ "matcher": "*",
187
+ "script": "hooks/skill-injector.js",
188
+ "timeout": 5,
189
+ "compoundCritical": true
190
+ },
191
+ {
192
+ "name": "forge-loop-progress",
193
+ "tier": "compound-core",
194
+ "event": "UserPromptSubmit",
195
+ "matcher": "*",
196
+ "script": "hooks/forge-loop-progress.js",
197
+ "timeout": 2,
198
+ "compoundCritical": false
199
+ },
200
+ {
201
+ "name": "session-end",
202
+ "tier": "compound-core",
203
+ "event": "SessionEnd",
204
+ "matcher": "*",
205
+ "script": "hooks/session-end.js",
206
+ "timeout": 3,
207
+ "compoundCritical": true,
208
+ "hosts": [
209
+ "claude"
210
+ ]
211
+ }
24
212
  ]