forge-workflow 0.1.0-beta.4 → 0.1.0-beta.6

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 (196) hide show
  1. package/AGENTS.md +18 -7
  2. package/CHANGELOG.md +79 -1
  3. package/CLAUDE.md +0 -12
  4. package/CODING_STANDARDS.md +72 -0
  5. package/README.md +6 -2
  6. package/bin/forge-cmd.js +20 -0
  7. package/bin/forge.js +28 -375
  8. package/docs/INDEX.md +1 -1
  9. package/docs/guides/BEADS_GITHUB_SYNC.md +2 -31
  10. package/docs/guides/MIGRATION.md +4 -4
  11. package/docs/guides/SETUP.md +16 -16
  12. package/docs/reference/COMMANDS.md +8 -5
  13. package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +4 -0
  14. package/docs/reference/INSIGHTS_RECAP.md +9 -20
  15. package/docs/reference/INSTALL.md +4 -0
  16. package/docs/reference/LEGACY_CLAIM_REPAIR.md +112 -0
  17. package/docs/reference/RELEASE.md +5 -3
  18. package/docs/reference/TOOLCHAIN.md +8 -0
  19. package/docs/reference/github-accounts.md +134 -0
  20. package/docs/reference/protected-state-surfaces.md +4 -4
  21. package/docs/reference/shepherd.md +114 -35
  22. package/lefthook.yml +12 -0
  23. package/lib/activation/ensure-forge-home.js +33 -15
  24. package/lib/adapters/pr-state-adapter.js +359 -144
  25. package/lib/audit-evidence.js +71 -110
  26. package/lib/base-remote.js +138 -0
  27. package/lib/beta5-compatibility-evidence.js +1093 -0
  28. package/lib/bun-lockfile-proof.js +413 -0
  29. package/lib/bun-workflow-pins.js +461 -0
  30. package/lib/capabilities/index.js +9 -0
  31. package/lib/capabilities/model.js +141 -0
  32. package/lib/capabilities/probes.js +347 -0
  33. package/lib/capped-jsonl-log.js +236 -0
  34. package/lib/codex-skills.js +2 -2
  35. package/lib/commands/_manifest.js +1 -0
  36. package/lib/commands/_registry.js +50 -20
  37. package/lib/commands/clean.js +252 -32
  38. package/lib/commands/dev.js +4 -33
  39. package/lib/commands/doctor.js +37 -6
  40. package/lib/commands/gate.js +197 -27
  41. package/lib/commands/github.js +215 -0
  42. package/lib/commands/hooks.js +276 -30
  43. package/lib/commands/insights.js +8 -3
  44. package/lib/commands/memory.js +66 -2
  45. package/lib/commands/merge.js +1265 -58
  46. package/lib/commands/plan.js +33 -2
  47. package/lib/commands/pr.js +3 -1
  48. package/lib/commands/preflight.js +21 -4
  49. package/lib/commands/prime.js +21 -8
  50. package/lib/commands/push.js +146 -54
  51. package/lib/commands/recall.js +127 -49
  52. package/lib/commands/recap.js +6 -1
  53. package/lib/commands/release.js +39 -3
  54. package/lib/commands/remember.js +28 -4
  55. package/lib/commands/serve.js +26 -9
  56. package/lib/commands/setup.js +323 -98
  57. package/lib/commands/shepherd.js +591 -73
  58. package/lib/commands/ship.js +36 -91
  59. package/lib/commands/skill.js +127 -11
  60. package/lib/commands/status.js +17 -1
  61. package/lib/commands/team.js +47 -8
  62. package/lib/commands/test.js +187 -38
  63. package/lib/commands/validate.js +65 -21
  64. package/lib/commands/worktree.js +359 -45
  65. package/lib/core/runtime-graph.js +1 -1
  66. package/lib/doc-assertions.js +297 -0
  67. package/lib/existing-tdd-gate.js +253 -0
  68. package/lib/fixtures/beta5-corpus/v1/README.md +9 -0
  69. package/lib/fixtures/beta5-corpus/v1/contract/command-contract.json +26 -0
  70. package/lib/fixtures/beta5-corpus/v1/contract/package-contract.json +13 -0
  71. package/lib/fixtures/beta5-corpus/v1/contract/workflow-stage-matrix.json +8 -0
  72. package/lib/fixtures/beta5-corpus/v1/manifest.json +25 -0
  73. package/lib/fixtures/beta5-corpus/v1/state/comments.jsonl +1 -0
  74. package/lib/fixtures/beta5-corpus/v1/state/config.yaml +6 -0
  75. package/lib/fixtures/beta5-corpus/v1/state/dependencies.jsonl +1 -0
  76. package/lib/fixtures/beta5-corpus/v1/state/issues.jsonl +2 -0
  77. package/lib/fixtures/beta5-corpus/v1/state/kernel.sql +20 -0
  78. package/lib/forge-context.js +1 -4
  79. package/lib/forge-issues.js +134 -32
  80. package/lib/gate-events.js +98 -10
  81. package/lib/git-defaults.js +56 -0
  82. package/lib/github-context.js +308 -0
  83. package/lib/global-flags.js +1 -0
  84. package/lib/harness-capability-matrix.js +3 -3
  85. package/lib/hook-renderer.js +122 -5
  86. package/lib/insights.js +96 -80
  87. package/lib/issue-render.js +19 -0
  88. package/lib/kernel/backing-issue.js +14 -2
  89. package/lib/kernel/broker.js +739 -31
  90. package/lib/kernel/claim-reconciler.js +238 -0
  91. package/lib/kernel/cli-broker-factory.js +12 -1
  92. package/lib/kernel/close-on-merge.js +154 -0
  93. package/lib/kernel/fs-class.js +42 -25
  94. package/lib/kernel/lease-enforcer.js +9 -4
  95. package/lib/kernel/legacy-claim-repair.js +442 -0
  96. package/lib/kernel/live-claim-projection.js +26 -0
  97. package/lib/kernel/migrations.js +118 -3
  98. package/lib/kernel/readiness-model.js +184 -12
  99. package/lib/kernel/schema.js +49 -1
  100. package/lib/kernel/sqlite-driver.js +3435 -172
  101. package/lib/kernel/taxonomy-validator.js +4 -1
  102. package/lib/kernel/windows-private-acl.js +239 -0
  103. package/lib/lefthook-wiring.js +21 -1
  104. package/lib/memory/hygiene.js +191 -0
  105. package/lib/memory/router.js +110 -28
  106. package/lib/memory/usage-evidence.js +4 -0
  107. package/lib/memory-digest.js +106 -15
  108. package/lib/memory-recall-events.js +145 -0
  109. package/lib/memory-recall.js +71 -10
  110. package/lib/merge-rules.js +143 -21
  111. package/lib/npm-publish-workflow.js +465 -0
  112. package/lib/orientation.js +68 -43
  113. package/lib/package-root.js +2 -0
  114. package/lib/plugin-catalog.js +14 -4
  115. package/lib/pr-bundle.js +5 -6
  116. package/lib/pr-monitor/auto-actions.js +169 -28
  117. package/lib/pr-monitor/differ.js +110 -4
  118. package/lib/pr-monitor/events.js +0 -0
  119. package/lib/pr-monitor/flow-monitor.js +1424 -0
  120. package/lib/pr-monitor/gather.js +251 -44
  121. package/lib/pr-monitor/journal.js +18 -39
  122. package/lib/pr-monitor/monitor.js +117 -10
  123. package/lib/pr-monitor/process-identity.js +117 -0
  124. package/lib/pr-monitor/reconcile-executor.js +1129 -470
  125. package/lib/pr-monitor/reconcile.js +0 -0
  126. package/lib/pr-monitor/render-summary.js +293 -0
  127. package/lib/pr-monitor/review-preflight.js +269 -0
  128. package/lib/pr-monitor/shepherd-lease.js +38 -20
  129. package/lib/pr-monitor/verdict.js +438 -0
  130. package/lib/pr-monitor/watch-lifecycle.js +145 -27
  131. package/lib/pr-monitor/watch-owner.js +1414 -0
  132. package/lib/pr-monitor/watch.js +129 -58
  133. package/lib/pr-pull.js +33 -14
  134. package/lib/pr-shepherd.js +51 -11
  135. package/lib/preflight/gates.js +65 -18
  136. package/lib/preflight/runner.js +5 -0
  137. package/lib/project-memory.js +178 -4
  138. package/lib/protected-state-authority.js +1100 -0
  139. package/lib/protected-state-surfaces.js +243 -45
  140. package/lib/release-readiness.js +53 -7
  141. package/lib/review-adapter.js +65 -0
  142. package/lib/shell-utils.js +1 -1
  143. package/lib/skills-sync.js +71 -35
  144. package/lib/smart-merge.js +28 -4
  145. package/lib/symlink-utils.js +74 -26
  146. package/lib/upgrade-safety.js +39 -0
  147. package/lib/using-forge.js +19 -6
  148. package/lib/validation/risk-manifest.js +339 -0
  149. package/lib/workflow/enforce-stage.js +44 -0
  150. package/lib/workflow/plan-authority.js +225 -0
  151. package/package.json +12 -9
  152. package/scripts/commitlint.js +13 -15
  153. package/scripts/doc-asserting-tests.js +158 -0
  154. package/scripts/generate-risk-manifest.js +91 -0
  155. package/scripts/github-context-bridge.sh +10 -0
  156. package/scripts/legacy-claim-repair.js +145 -0
  157. package/scripts/lib/behavioral-eval-runner.js +310 -0
  158. package/scripts/lib/behavioral-eval-runtime.js +457 -0
  159. package/scripts/lib/eval-evidence.js +328 -0
  160. package/scripts/lib/eval-runner.js +81 -41
  161. package/scripts/lib/immutable-eval-corpus.js +309 -0
  162. package/scripts/lib/promotion-evidence-loader.js +94 -0
  163. package/scripts/lib/promotion-scorecard.js +314 -0
  164. package/scripts/npm-release-receipt.js +134 -0
  165. package/scripts/process-tree.js +773 -0
  166. package/scripts/protected-state-check.js +479 -31
  167. package/scripts/run-command-eval.js +29 -1
  168. package/scripts/sync-agent-skills.js +333 -34
  169. package/scripts/sync-d20-audit.js +172 -0
  170. package/scripts/test-full-suite.js +935 -37
  171. package/scripts/test-profile.js +13 -3
  172. package/scripts/test.js +271 -57
  173. package/skills/coverage.json +1 -0
  174. package/skills/review/SKILL.md +6 -11
  175. package/skills/review/evals/scorecard.json +4 -4
  176. package/skills/rollback/SKILL.md +4 -11
  177. package/skills/rollback/evals/scorecard.json +3 -3
  178. package/skills/setup/SKILL.md +18 -0
  179. package/skills/setup/evals/scorecard.json +3 -3
  180. package/skills/shepherd/SKILL.md +39 -16
  181. package/skills/shepherd/evals/scorecard.json +4 -4
  182. package/skills/ship/SKILL.md +4 -12
  183. package/skills/ship/evals/scorecard.json +3 -3
  184. package/skills/validate/SKILL.md +3 -0
  185. package/skills/validate/evals/scorecard.json +1 -1
  186. package/skills/worktree/SKILL.md +6 -1
  187. package/skills/worktree/evals/scorecard.json +2 -2
  188. package/lib/beads-setup.js +0 -538
  189. package/lib/beads-sync-scaffold.js +0 -189
  190. package/lib/pat-setup.js +0 -207
  191. package/lib/pr-monitor/render-sticky.js +0 -206
  192. package/lib/pr-monitor/upsert-sticky.js +0 -169
  193. package/scripts/beads-context.sh +0 -577
  194. package/scripts/beads-migrate-to-dolt.sh +0 -7
  195. package/scripts/beads-upgrade-smoke.sh +0 -284
  196. package/scripts/lib/beads-migrate-to-dolt.mjs +0 -503
@@ -4,8 +4,8 @@
4
4
  "static": {
5
5
  "token_cost": {
6
6
  "desc_chars": 1021,
7
- "body_lines": 74,
8
- "score": 43
7
+ "body_lines": 92,
8
+ "score": 41
9
9
  },
10
10
  "caps": {
11
11
  "desc_within": true,
@@ -37,5 +37,5 @@
37
37
  "variance": null,
38
38
  "note": "behavioral — W5 (LLM judge): semantic recall/precision/chain/outcome/variance, not deterministic"
39
39
  },
40
- "composite": 83
40
+ "composite": 82
41
41
  }
@@ -6,8 +6,8 @@ description: >
6
6
  open PR, converges CI check state into kernel verdicts, re-runs flaky required
7
7
  checks, reaps orphan watchers, and self-retires when no PRs remain; one-shot
8
8
  passes (forge shepherd <pr>) exist for a single bounded check. Use when a PR was
9
- just opened or shipped; when a session starts with open PRs (start the daemon in
10
- a background shell — the singleton lease makes a duplicate start a safe no-op);
9
+ just opened or shipped; when a session starts with open PRs (Forge automatically
10
+ wakes the singleton; the lease makes a duplicate start a safe no-op);
11
11
  when the user asks "why isn't my PR merging", "what's
12
12
  blocking the PR", "is the PR ready", "did a check fail / go red"; when asked to
13
13
  "keep watching / keep an eye on / babysit my PRs"; or to read PR verdicts
@@ -27,22 +27,25 @@ Forge owns your open PRs. A singleton daemon converges every open PR toward merg
27
27
  `shepherd` is the PR-ownership utility, not a workflow stage. It has two modes over the **single `forge shepherd` verb**:
28
28
 
29
29
  - **Daemon (default ownership):** `forge shepherd daemon` is a machine-wide singleton for this repo. It heartbeats and converges the whole PR world every ~60s — self-registering hand-opened PRs, restarting killed watchers, reaping verified orphans, converging CI check state into kernel verdicts, retiring merged/closed PRs — then self-retires (releases the lease, kills its children, exits) once no PRs remain open. You do NOT poll by hand; the daemon does.
30
- - **One-shot pass:** `forge shepherd <pr>` reads one PR's state, takes at most one idempotent Tier-A action, and exits. Use it for a point-in-time question about a single PR.
30
+ - **One-shot convergence:** `forge shepherd <pr>` runs the local review preflight, reads one PR's current-head state, takes at most one idempotent Tier-A action, persists bounded deltas/receipts, and exits. Use it for a point-in-time question or one bounded convergence attempt on a single PR.
31
31
 
32
32
  ## Which mode? (decision rule)
33
33
 
34
34
  - User asks about **one PR, right now** ("is #212 ready?", "why is this blocked?") → **one-shot** (`forge shepherd <pr> --pull`).
35
35
  - Anything **ongoing** — "keep", "until it merges", "watch", "babysit", multiple PRs, or a session that starts with PRs already open → **ensure the daemon is running**.
36
36
 
37
- ## Session-start ritual
37
+ ## Automatic attachment
38
38
 
39
- When a session starts and the repo has open PRs, ensure the daemon is running:
39
+ Forge wakes the singleton after a successful supported session start, every
40
+ successful push, and every successful non-dry-run ship. Push does not require a
41
+ locally resolved PR number; the daemon enumerates all open and draft PRs itself.
42
+ Ordinary commands do not launch it.
40
43
 
41
- ```bash
42
- forge shepherd daemon # start it in the HARNESS BACKGROUND SHELL
43
- ```
44
-
45
- The daemon is a **repo singleton** guarded by an O_EXCL lease, so you do NOT need a liveness check first — a second start when one is already running simply exits (the lease is already held). Start it in the harness background shell (Claude Code / Codex background-shell) so it is session-scoped and reaped with the session. NEVER launch a detached spawn from the agent: the detached path is Forge's bare-CLI fallback only. (Automatic per-command launch and a `forge prime` daemon-liveness line are planned follow-ups — W-S4c/W-S5 — not yet wired; until then you start the daemon explicitly as above.)
44
+ The daemon is a **repo singleton** guarded by an O_EXCL lease, so no liveness
45
+ check is needed first. Forge prefers a supplied harness background shell; its
46
+ bare-CLI detached fallback launches from the stable common repository root, not
47
+ the current disposable worktree. Agents never launch a detached spawn directly.
48
+ (A `forge prime` daemon-liveness line remains the separate W-S5 follow-up.)
46
49
 
47
50
  ## Reading verdicts (the common case)
48
51
 
@@ -54,12 +57,22 @@ forge shepherd events <pr> --since <seq> # only the new events since sequence
54
57
 
55
58
  `--pull` is strictly read-only (dry-run pass: no rerun, no rebase, no merge, no thread resolution). It returns one bounded, actionable-only payload — `blockers[]`, classified `requiredChecks`, failed-check log `failures[]` (matrix-deduped), and every unresolved `reviewThreads[]` — so you get "everything blocking this PR + what to fix" in one call. Passing checks and satisfied policy are omitted.
56
59
 
60
+ A plain `forge shepherd <pr>` also returns a consolidated `localPreflight`, at
61
+ most 128 `deltas`, `receiptIds`, and one explicit `handoff`. The preflight probes
62
+ CodeRabbit and runs strict lint, Sonar parity, structural drift, and affected
63
+ tests. An unavailable or unauthenticated CodeRabbit CLI is reported as
64
+ `UNAVAILABLE`/`INCOMPLETE`, never as a fabricated pass; deterministic failures or
65
+ actual review findings make the remote decision read-only for that pass. A
66
+ checkout that is not the exact PR head is `NOT_APPLICABLE`, never reviewed as if
67
+ it were authoritative.
68
+
57
69
  ### Verdict vocabulary (collapsed, W-S1)
58
70
 
59
71
  | Verdict | Meaning |
60
72
  | --- | --- |
61
73
  | `MERGE_READY` | Required checks green, branch up to date — hand off to a human to merge. |
62
74
  | `PENDING` | A Tier-A action was taken, or checks are still running — await the next tick/pass. |
75
+ | `INCOMPLETE` | Exact-head local review or durable convergence evidence is unavailable — fail closed and retry after evidence is restored. |
63
76
  | `BLOCKED` | Something actionable blocks merge (failing/missing/skipped required check, conflict, behind, unresolved threads, changes requested). Read `blockers[]`. |
64
77
  | `CI_DEAD_HEAD` | The head has no required checks running (e.g. an auto-update authored by `GITHUB_TOKEN` never re-triggered CI). Recovery is an **escalation, not an autonomous Tier-A rerun**: it needs a maintainer-provided `FORGE_PR_TOKEN` (contents + pull-requests + checks) to re-author the push so CI re-triggers. |
65
78
  | `ESCALATE` | A Tier-C condition (conflict, unreadable required set, persistent failure, oscillation, budget exhaustion). Context is posted to the PR. |
@@ -69,8 +82,8 @@ forge shepherd events <pr> --since <seq> # only the new events since sequence
69
82
 
70
83
  | Situation | Command |
71
84
  | --- | --- |
72
- | PR just opened / shipped | ensure `forge shepherd daemon` running |
73
- | Session starts, open PRs exist, daemon dead | `forge shepherd daemon` (background shell) |
85
+ | PR just opened / shipped | automatic singleton wake; read with `forge shepherd <pr> --pull` |
86
+ | Session starts with open PRs | automatic singleton wake |
74
87
  | "Why isn't my PR merging / what's blocking it" | `forge shepherd <pr> --pull` |
75
88
  | "Is the PR ready?" | `forge shepherd <pr> --pull` (read `MERGE_READY`) |
76
89
  | "A check failed / went red" | `forge shepherd <pr> --pull --json` (read `failures[]`) |
@@ -95,12 +108,22 @@ forge shepherd events <pr> --since <seq> # only the new events since sequence
95
108
  ## Kill-switches
96
109
 
97
110
  ```bash
98
- FORGE_SHEPHERD_DISABLE=1 # env: makes the shepherd trigger inert (once the auto-fire wiring lands, W-S4c)
99
- forge gate disable rail.auto_shepherd # config gate honored by the trigger + ship/push arming
111
+ FORGE_SHEPHERD_DISABLE=1 # env: makes automatic firing inert
112
+ forge gate disable rail.auto_shepherd # config gate honored by every automatic seam
100
113
  ```
101
114
 
102
- Both leave the manual `forge shepherd` surface usable; they only stop the automatic daemon fire.
115
+ CI/test (`NODE_ENV=test`, `BUN_ENV=test`, `CI`, `GITHUB_ACTIONS`, or
116
+ `GITLAB_CI`), dry-run, uninitialized repositories, and disabled paths return
117
+ before lease, Kernel-state, or process work. All leave the manual
118
+ `forge shepherd` surface usable; they only stop automatic daemon fire.
103
119
 
104
120
  ## State
105
121
 
106
- Progress is durable in GitHub (PR comments, labels, `git`). The one local store is the per-PR journal under `.forge/pr-monitor/<repo>-<pr>/` (append-only `events.ndjson` + snapshot/consumer cursors) — the replay surface for `events --since`. The bounded one-shot pass keeps no separate local state.
122
+ Public Memory is the durable monitor authority and public Flow reducers restore
123
+ its bounded event and watcher-process checkpoints after restart. The per-PR
124
+ journal under `.forge/pr-monitor/<repo>-<pr>/` remains a compatibility delivery
125
+ surface for `events --since`, not authority. Merged/closed evidence produces one
126
+ idempotent terminal MonitorReceipt; conflicting or incomplete replay fails
127
+ closed. For 0.1 no receipt grants continuing lease authority: live ownership is
128
+ re-probed at consequential boundaries, and canonical LeaseReceipt epoch/scope
129
+ plus the same-actor/session ABA fix remain explicitly deferred.
@@ -3,9 +3,9 @@
3
3
  "fixtures": "present",
4
4
  "static": {
5
5
  "token_cost": {
6
- "desc_chars": 997,
7
- "body_lines": 86,
8
- "score": 43
6
+ "desc_chars": 987,
7
+ "body_lines": 109,
8
+ "score": 41
9
9
  },
10
10
  "caps": {
11
11
  "desc_within": true,
@@ -37,5 +37,5 @@
37
37
  "variance": null,
38
38
  "note": "behavioral — W5 (LLM judge): semantic recall/precision/chain/outcome/variance, not deterministic"
39
39
  },
40
- "composite": 83
40
+ "composite": 82
41
41
  }
@@ -1,18 +1,10 @@
1
1
  ---
2
2
  name: ship
3
+ invocation: user
3
4
  description: >
4
- Forge SHIP stage: push the validated feature branch and open a PR populated from the
5
- project's OWN PR template (design-doc link, Forge issue IDs, real test/commit data), then
6
- hand off for MANUAL merge; never merges or auto-merges. Use once /validate passes and you
7
- want a PR on the board. Triggers: "ship it", "ship this branch", "open the PR", "push and
8
- open a PR", "gh pr create", "checks passed, now cut the PR". Runs branch-freshness +
9
- parallel-PR merge-sim checks, force-with-lease push, records the ship->review handoff, then
10
- stops. One stage only; not for: the whole plan->dev->validate->ship->review pipeline or
11
- drive-to-done (smith); type-check/lint/tests/security first (validate); addressing PR
12
- comments or resolving Greptile/SonarCloud/CodeRabbit threads on an existing PR (review);
13
- babysitting an open PR toward merge (shepherd); post-merge CI health check + closing issues
14
- (verify); reverting an already-shipped change (rollback). If the PR already exists, this is
15
- not the skill.
5
+ Push a validated feature branch and open its PR from the project's template, then stop for
6
+ manual merge. Use only when the user asks to ship or open the PR after validation; never
7
+ merges, auto-merges, reviews an existing PR, or replaces end-to-end Smith.
16
8
  allowed-tools: Bash, Read, Edit, Grep, Glob
17
9
  next: review
18
10
  terminal: false
@@ -3,9 +3,9 @@
3
3
  "fixtures": "present",
4
4
  "static": {
5
5
  "token_cost": {
6
- "desc_chars": 993,
6
+ "desc_chars": 254,
7
7
  "body_lines": 237,
8
- "score": 28
8
+ "score": 64
9
9
  },
10
10
  "caps": {
11
11
  "desc_within": true,
@@ -37,5 +37,5 @@
37
37
  "variance": null,
38
38
  "note": "behavioral — W5 (LLM judge): semantic recall/precision/chain/outcome/variance, not deterministic"
39
39
  },
40
- "composite": 78
40
+ "composite": 89
41
41
  }
@@ -105,6 +105,9 @@ bun run lint # or: npm run lint, eslint ., etc.
105
105
  - Best practices compliance
106
106
 
107
107
  ### Step 3: Code Review (if available)
108
+
109
+ Read `CODING_STANDARDS.md` from the repository root before invoking the reviewer so the review applies the repository's diff-level contract.
110
+
108
111
  ```bash
109
112
  /code-review:code-review
110
113
  ```
@@ -4,7 +4,7 @@
4
4
  "static": {
5
5
  "token_cost": {
6
6
  "desc_chars": 995,
7
- "body_lines": 300,
7
+ "body_lines": 303,
8
8
  "score": 21
9
9
  },
10
10
  "caps": {
@@ -71,7 +71,12 @@ forge clean # remove worktrees whose branches merged; FF th
71
71
  forge clean --dry-run # show what would be removed, change nothing
72
72
  ```
73
73
 
74
- `forge clean` is **squash-aware** — it detects branches that merged via squash, not just fast-forward merges.
74
+ `forge clean` is **squash-aware** — it detects branches that merged via squash, not just fast-forward merges. Removing a merged worktree also closes the kernel issue the branch was linked to, citing the merge as evidence.
75
+
76
+ Two things it will never touch, because closing an issue is irreversible (`done` is terminal):
77
+
78
+ - **A branch with no commits of its own.** A freshly created worktree points at a default-branch commit, which git alone reads as "merged". That is unstarted work — it is kept, and its issue stays open.
79
+ - **A worktree it skipped.** Uncommitted changes hold a worktree back, and a held-back worktree never has its issue closed.
75
80
 
76
81
  ### `forge clean` footguns
77
82
 
@@ -4,8 +4,8 @@
4
4
  "static": {
5
5
  "token_cost": {
6
6
  "desc_chars": 1013,
7
- "body_lines": 70,
8
- "score": 44
7
+ "body_lines": 75,
8
+ "score": 43
9
9
  },
10
10
  "caps": {
11
11
  "desc_within": true,