@kiwidata/grimoire 0.1.1

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 (215) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/AGENTS.md +217 -0
  3. package/README.md +748 -0
  4. package/bin/grimoire.js +2 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +42 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/commands/archive.d.ts +3 -0
  10. package/dist/commands/archive.d.ts.map +1 -0
  11. package/dist/commands/archive.js +22 -0
  12. package/dist/commands/archive.js.map +1 -0
  13. package/dist/commands/branch-check.d.ts +3 -0
  14. package/dist/commands/branch-check.d.ts.map +1 -0
  15. package/dist/commands/branch-check.js +16 -0
  16. package/dist/commands/branch-check.js.map +1 -0
  17. package/dist/commands/check.d.ts +3 -0
  18. package/dist/commands/check.d.ts.map +1 -0
  19. package/dist/commands/check.js +22 -0
  20. package/dist/commands/check.js.map +1 -0
  21. package/dist/commands/ci.d.ts +3 -0
  22. package/dist/commands/ci.d.ts.map +1 -0
  23. package/dist/commands/ci.js +18 -0
  24. package/dist/commands/ci.js.map +1 -0
  25. package/dist/commands/diff.d.ts +3 -0
  26. package/dist/commands/diff.d.ts.map +1 -0
  27. package/dist/commands/diff.js +10 -0
  28. package/dist/commands/diff.js.map +1 -0
  29. package/dist/commands/docs.d.ts +3 -0
  30. package/dist/commands/docs.d.ts.map +1 -0
  31. package/dist/commands/docs.js +11 -0
  32. package/dist/commands/docs.js.map +1 -0
  33. package/dist/commands/health.d.ts +3 -0
  34. package/dist/commands/health.d.ts.map +1 -0
  35. package/dist/commands/health.js +13 -0
  36. package/dist/commands/health.js.map +1 -0
  37. package/dist/commands/init.d.ts +3 -0
  38. package/dist/commands/init.d.ts.map +1 -0
  39. package/dist/commands/init.js +21 -0
  40. package/dist/commands/init.js.map +1 -0
  41. package/dist/commands/list.d.ts +3 -0
  42. package/dist/commands/list.d.ts.map +1 -0
  43. package/dist/commands/list.js +22 -0
  44. package/dist/commands/list.js.map +1 -0
  45. package/dist/commands/log.d.ts +3 -0
  46. package/dist/commands/log.d.ts.map +1 -0
  47. package/dist/commands/log.js +15 -0
  48. package/dist/commands/log.js.map +1 -0
  49. package/dist/commands/map.d.ts +3 -0
  50. package/dist/commands/map.d.ts.map +1 -0
  51. package/dist/commands/map.js +17 -0
  52. package/dist/commands/map.js.map +1 -0
  53. package/dist/commands/pr.d.ts +3 -0
  54. package/dist/commands/pr.d.ts.map +1 -0
  55. package/dist/commands/pr.js +17 -0
  56. package/dist/commands/pr.js.map +1 -0
  57. package/dist/commands/status.d.ts +3 -0
  58. package/dist/commands/status.d.ts.map +1 -0
  59. package/dist/commands/status.js +12 -0
  60. package/dist/commands/status.js.map +1 -0
  61. package/dist/commands/test-quality.d.ts +3 -0
  62. package/dist/commands/test-quality.d.ts.map +1 -0
  63. package/dist/commands/test-quality.js +37 -0
  64. package/dist/commands/test-quality.js.map +1 -0
  65. package/dist/commands/trace.d.ts +3 -0
  66. package/dist/commands/trace.d.ts.map +1 -0
  67. package/dist/commands/trace.js +12 -0
  68. package/dist/commands/trace.js.map +1 -0
  69. package/dist/commands/update.d.ts +3 -0
  70. package/dist/commands/update.d.ts.map +1 -0
  71. package/dist/commands/update.js +22 -0
  72. package/dist/commands/update.js.map +1 -0
  73. package/dist/commands/validate.d.ts +3 -0
  74. package/dist/commands/validate.d.ts.map +1 -0
  75. package/dist/commands/validate.js +17 -0
  76. package/dist/commands/validate.js.map +1 -0
  77. package/dist/core/archive.d.ts +9 -0
  78. package/dist/core/archive.d.ts.map +1 -0
  79. package/dist/core/archive.js +92 -0
  80. package/dist/core/archive.js.map +1 -0
  81. package/dist/core/branch-check.d.ts +27 -0
  82. package/dist/core/branch-check.d.ts.map +1 -0
  83. package/dist/core/branch-check.js +205 -0
  84. package/dist/core/branch-check.js.map +1 -0
  85. package/dist/core/check.d.ts +24 -0
  86. package/dist/core/check.d.ts.map +1 -0
  87. package/dist/core/check.js +372 -0
  88. package/dist/core/check.js.map +1 -0
  89. package/dist/core/ci.d.ts +24 -0
  90. package/dist/core/ci.d.ts.map +1 -0
  91. package/dist/core/ci.js +162 -0
  92. package/dist/core/ci.js.map +1 -0
  93. package/dist/core/detect.d.ts +10 -0
  94. package/dist/core/detect.d.ts.map +1 -0
  95. package/dist/core/detect.js +368 -0
  96. package/dist/core/detect.js.map +1 -0
  97. package/dist/core/diff.d.ts +29 -0
  98. package/dist/core/diff.d.ts.map +1 -0
  99. package/dist/core/diff.js +197 -0
  100. package/dist/core/diff.js.map +1 -0
  101. package/dist/core/doc-style.d.ts +16 -0
  102. package/dist/core/doc-style.d.ts.map +1 -0
  103. package/dist/core/doc-style.js +192 -0
  104. package/dist/core/doc-style.js.map +1 -0
  105. package/dist/core/docs.d.ts +6 -0
  106. package/dist/core/docs.d.ts.map +1 -0
  107. package/dist/core/docs.js +478 -0
  108. package/dist/core/docs.js.map +1 -0
  109. package/dist/core/health.d.ts +7 -0
  110. package/dist/core/health.d.ts.map +1 -0
  111. package/dist/core/health.js +489 -0
  112. package/dist/core/health.js.map +1 -0
  113. package/dist/core/hooks.d.ts +5 -0
  114. package/dist/core/hooks.d.ts.map +1 -0
  115. package/dist/core/hooks.js +168 -0
  116. package/dist/core/hooks.js.map +1 -0
  117. package/dist/core/init.d.ts +9 -0
  118. package/dist/core/init.d.ts.map +1 -0
  119. package/dist/core/init.js +563 -0
  120. package/dist/core/init.js.map +1 -0
  121. package/dist/core/list.d.ts +4 -0
  122. package/dist/core/list.d.ts.map +1 -0
  123. package/dist/core/list.js +170 -0
  124. package/dist/core/list.js.map +1 -0
  125. package/dist/core/log.d.ts +8 -0
  126. package/dist/core/log.d.ts.map +1 -0
  127. package/dist/core/log.js +150 -0
  128. package/dist/core/log.js.map +1 -0
  129. package/dist/core/map.d.ts +9 -0
  130. package/dist/core/map.d.ts.map +1 -0
  131. package/dist/core/map.js +302 -0
  132. package/dist/core/map.js.map +1 -0
  133. package/dist/core/pr.d.ts +9 -0
  134. package/dist/core/pr.d.ts.map +1 -0
  135. package/dist/core/pr.js +273 -0
  136. package/dist/core/pr.js.map +1 -0
  137. package/dist/core/shared-setup.d.ts +52 -0
  138. package/dist/core/shared-setup.d.ts.map +1 -0
  139. package/dist/core/shared-setup.js +221 -0
  140. package/dist/core/shared-setup.js.map +1 -0
  141. package/dist/core/status.d.ts +6 -0
  142. package/dist/core/status.d.ts.map +1 -0
  143. package/dist/core/status.js +114 -0
  144. package/dist/core/status.js.map +1 -0
  145. package/dist/core/test-quality.d.ts +33 -0
  146. package/dist/core/test-quality.d.ts.map +1 -0
  147. package/dist/core/test-quality.js +378 -0
  148. package/dist/core/test-quality.js.map +1 -0
  149. package/dist/core/trace.d.ts +6 -0
  150. package/dist/core/trace.d.ts.map +1 -0
  151. package/dist/core/trace.js +211 -0
  152. package/dist/core/trace.js.map +1 -0
  153. package/dist/core/update.d.ts +10 -0
  154. package/dist/core/update.d.ts.map +1 -0
  155. package/dist/core/update.js +149 -0
  156. package/dist/core/update.js.map +1 -0
  157. package/dist/core/validate.d.ts +20 -0
  158. package/dist/core/validate.d.ts.map +1 -0
  159. package/dist/core/validate.js +275 -0
  160. package/dist/core/validate.js.map +1 -0
  161. package/dist/index.d.ts +19 -0
  162. package/dist/index.d.ts.map +1 -0
  163. package/dist/index.js +20 -0
  164. package/dist/index.js.map +1 -0
  165. package/dist/utils/config.d.ts +61 -0
  166. package/dist/utils/config.d.ts.map +1 -0
  167. package/dist/utils/config.js +172 -0
  168. package/dist/utils/config.js.map +1 -0
  169. package/dist/utils/fs.d.ts +17 -0
  170. package/dist/utils/fs.d.ts.map +1 -0
  171. package/dist/utils/fs.js +38 -0
  172. package/dist/utils/fs.js.map +1 -0
  173. package/dist/utils/paths.d.ts +10 -0
  174. package/dist/utils/paths.d.ts.map +1 -0
  175. package/dist/utils/paths.js +35 -0
  176. package/dist/utils/paths.js.map +1 -0
  177. package/dist/utils/spawn.d.ts +5 -0
  178. package/dist/utils/spawn.d.ts.map +1 -0
  179. package/dist/utils/spawn.js +34 -0
  180. package/dist/utils/spawn.js.map +1 -0
  181. package/package.json +68 -0
  182. package/skills/grimoire-apply/SKILL.md +274 -0
  183. package/skills/grimoire-audit/SKILL.md +129 -0
  184. package/skills/grimoire-branch-guard/SKILL.md +111 -0
  185. package/skills/grimoire-bug/SKILL.md +160 -0
  186. package/skills/grimoire-bug-explore/SKILL.md +242 -0
  187. package/skills/grimoire-bug-report/SKILL.md +237 -0
  188. package/skills/grimoire-bug-session/SKILL.md +222 -0
  189. package/skills/grimoire-bug-triage/SKILL.md +274 -0
  190. package/skills/grimoire-commit/SKILL.md +150 -0
  191. package/skills/grimoire-discover/SKILL.md +297 -0
  192. package/skills/grimoire-draft/SKILL.md +202 -0
  193. package/skills/grimoire-plan/SKILL.md +329 -0
  194. package/skills/grimoire-pr/SKILL.md +134 -0
  195. package/skills/grimoire-pr-review/SKILL.md +240 -0
  196. package/skills/grimoire-refactor/SKILL.md +251 -0
  197. package/skills/grimoire-remove/SKILL.md +112 -0
  198. package/skills/grimoire-review/SKILL.md +247 -0
  199. package/skills/grimoire-verify/SKILL.md +223 -0
  200. package/skills/references/bug-classification.md +154 -0
  201. package/skills/references/build-vs-buy.md +77 -0
  202. package/skills/references/elicitation-personas.md +118 -0
  203. package/skills/references/refactor-register-format.md +88 -0
  204. package/skills/references/refactor-scan-categories.md +102 -0
  205. package/skills/references/schema-format.md +68 -0
  206. package/skills/references/security-compliance.md +110 -0
  207. package/skills/references/testing-contracts.md +93 -0
  208. package/templates/context.yml +110 -0
  209. package/templates/debt-exceptions.yml +61 -0
  210. package/templates/decision.md +50 -0
  211. package/templates/dupignore +93 -0
  212. package/templates/example.feature +24 -0
  213. package/templates/manifest.md +29 -0
  214. package/templates/mapignore +58 -0
  215. package/templates/mapkeys +65 -0
@@ -0,0 +1,240 @@
1
+ ---
2
+ name: grimoire-pr-review
3
+ description: Review a teammate's pull request using the same multi-persona lens as pre-commit review, but against the actual diff. Fetches the PR, loads linked grimoire artifacts via the Change trailer, and produces structured findings suitable for PR comments.
4
+ compatibility: Designed for Claude Code (or similar products)
5
+ metadata:
6
+ author: kiwi-data
7
+ version: "0.1"
8
+ ---
9
+
10
+ # grimoire-pr-review
11
+
12
+ Review a pull request authored by someone else. Applies the same persona lens as `grimoire-review` (product, engineer, security, QA, data) to the real diff, cross-referenced with the PR's linked grimoire change (if any).
13
+
14
+ ## Triggers
15
+ - User asks to review a teammate's PR / MR
16
+ - User supplies a PR number, URL, or branch and asks for review
17
+ - Loose match: "review this PR", "look at PR #123", "review <url>", "review teammate's branch", "code review"
18
+
19
+ ## Routing
20
+ - Reviewing your own pre-merge change you just built → `grimoire-pr` (has optional post-impl review)
21
+ - Reviewing a design before any code exists → `grimoire-review`
22
+ - Verifying scenarios pass after merge → `grimoire-verify`
23
+ - Writing a bug report against merged behavior → `grimoire-bug-report`
24
+
25
+ ## Prerequisites
26
+ - `gh` (GitHub) or `glab` (GitLab) CLI installed and authenticated, OR the PR's branch fetched locally
27
+ - Working directory is the repo the PR targets
28
+ - Optional: `.grimoire/` directory with baseline features/decisions for linked-change context
29
+
30
+ ## Inputs
31
+ Accept any of:
32
+ - PR number: `123`
33
+ - PR URL: `https://github.com/org/repo/pull/123`
34
+ - Branch name: `feat/add-2fa-login`
35
+ - Base/head refs: `main...feat/add-2fa-login`
36
+
37
+ If nothing supplied, ask the user for one.
38
+
39
+ ## Workflow
40
+
41
+ ### 1. Fetch PR Metadata
42
+ Resolve the input to concrete refs.
43
+
44
+ - GitHub: `gh pr view <id> --json number,title,body,author,baseRefName,headRefName,files,commits,url`
45
+ - GitLab: `glab mr view <id> --output json`
46
+ - Branch only: derive base from default branch (`git remote show origin | grep 'HEAD branch'`) and head = supplied branch
47
+
48
+ Record: PR title, body, author, base branch, head branch, URL, file list, commit count.
49
+
50
+ ### 2. Fetch the Diff
51
+ - GitHub: `gh pr diff <id>` (or `git fetch origin pull/<id>/head && git diff <base>...FETCH_HEAD`)
52
+ - GitLab: `glab mr diff <id>`
53
+ - Branch: `git fetch origin <head> && git diff origin/<base>...origin/<head>`
54
+
55
+ If the diff is very large (>2000 lines changed), ask the user whether to review the full diff, focus on a subset of files, or review commit-by-commit.
56
+
57
+ ### 3. Find Linked Grimoire Change
58
+ Look for a `Change:` trailer in the PR commits:
59
+
60
+ ```
61
+ git log <base>..<head> --format="%B" | grep -E "^Change:"
62
+ ```
63
+
64
+ If present:
65
+ - Change ID = trailer value
66
+ - Load artifacts: first check `.grimoire/changes/<change-id>/` (in-progress), then `.grimoire/archive/*<change-id>*/` (archived). Try the PR's head branch checked out locally if needed.
67
+ - Read `manifest.md`, all `.feature` files in the change, decision records, `tasks.md`, `data.yml`
68
+ - Also grep for `Scenarios:` and `Decisions:` trailers to scope review to the named items
69
+
70
+ If no `Change:` trailer exists, that's itself a finding for a grimoire-managed repo: flag as **suggestion** ("commits missing audit trailer — `grimoire trace` won't find this PR") unless the project clearly doesn't use grimoire.
71
+
72
+ ### 4. Gather Project Context
73
+ - `.grimoire/config.yaml` — language, tools, `commit_style`, `project.compliance`, `dep_audit`
74
+ - `.grimoire/docs/context.yml` — deployment environment, related services
75
+ - `.grimoire/docs/data/schema.yml` — current data baseline
76
+ - Relevant `.grimoire/docs/<area>.md` for the directories touched by the diff
77
+
78
+ ### 5. Complexity-Gated Depth
79
+ Read `complexity` from the linked manifest frontmatter if available. Fall back to heuristics on the diff:
80
+
81
+ | Signal | Depth |
82
+ |---|---|
83
+ | Docs only, ≤50 lines | Senior engineer skim only |
84
+ | Linked manifest complexity 1-2, diff <200 lines, no security tags | Senior engineer + security quick scan |
85
+ | Linked manifest complexity 3, OR diff touches auth/data/API | All relevant personas (skip data if no schema change, skip QA if no user-facing change) |
86
+ | Linked manifest complexity 4, OR diff >500 lines, OR touches multiple domains | All personas mandatory |
87
+
88
+ User can override: "full review", "just security", "just engineer", etc.
89
+
90
+ ### 6. Product Manager Review
91
+ *(Skip if PR is pure internal refactor with no user-facing change.)*
92
+
93
+ Evaluate against the linked feature files (if any) or the PR body:
94
+
95
+ - **Scenario coverage**: If a feature file exists in the change, does the diff implement every scenario? Any scenario with no matching code change?
96
+ - **Non-goals**: Does the diff touch anything the manifest's Non-goals section excludes?
97
+ - **Acceptance**: From the diff alone, could a PM validate this meets the feature's acceptance criteria?
98
+ - **Clarity**: Does the PR body (or linked manifest) make the user-visible outcome clear?
99
+
100
+ Flag as **blocker** or **suggestion**.
101
+
102
+ ### 7. Senior Engineer Review
103
+ Review the actual code:
104
+
105
+ - **Simplicity**: Is this the simplest implementation? Any unnecessary abstraction, indirection, or config that could be inlined?
106
+ - **Conventions**: Does the new code match the file layout, naming, and patterns already in the touched areas? Check `.grimoire/docs/<area>.md` if present.
107
+ - **Reuse**: Are there existing utilities/functions that were re-implemented? `grep` for similar names or check the area doc's reusable-code list.
108
+ - **Dead code**: Functions added but not called, imports unused, commented-out code, stubs with no implementation.
109
+ - **Scope creep**: Files changed outside the scope implied by the change-id or manifest. Formatting-only changes to unrelated files = noise.
110
+ - **Error handling**: Are errors handled at boundaries? Internal code shouldn't be littered with defensive checks; external inputs must be validated.
111
+ - **Tests**: Do new behaviors have tests? Do the tests make real assertions (not just `assert true` / mock everything)? Check `../references/testing-contracts.md` if the framework matches.
112
+ - **Contract compatibility**: If `data.yml` / `schema.yml` exists, does the diff change request/response shape for a documented API? If yes, where's the contract test update?
113
+ - **Dependencies**: Any new packages in `package.json` / `requirements.txt` / `Cargo.toml` etc. not mentioned in tasks? Any version bumps that aren't noted?
114
+ - **Task alignment**: If `tasks.md` exists for the change, does the diff complete the tasks as written? Any task that was "done" but has no corresponding code?
115
+
116
+ Flag as **blocker** or **suggestion**.
117
+
118
+ ### 8. Security Engineer Review
119
+ Apply `../references/security-compliance.md`.
120
+
121
+ #### 8a. STRIDE on the diff
122
+ For every new entry point, data flow, or trust boundary introduced by the diff:
123
+
124
+ | Threat | Question |
125
+ |---|---|
126
+ | **S**poofing | Auth check at every new route/handler? |
127
+ | **T**ampering | Input/message integrity validated? CSRF on state-changing requests? |
128
+ | **R**epudiation | Security-relevant actions logged? |
129
+ | **I**nfo disclosure | Error responses, logs, stack traces leaking PII/tokens/secrets? |
130
+ | **D**oS | Unbounded loops, unlimited file uploads, expensive queries on user input, no rate limit? |
131
+ | **E**oP | Role/permission checks at the right layer? Any bypass via missing middleware? |
132
+
133
+ Skip categories that don't apply.
134
+
135
+ #### 8b. Code-level scan
136
+ - **Secrets**: Grep the diff for hardcoded keys, tokens, passwords, cloud credentials, JWT secrets. Flag any hit as **blocker**.
137
+ - **Injection**: Raw SQL with string concatenation, shell-exec with user input, `eval`/`exec`, unsafe deserialization. Tag with OWASP + CWE.
138
+ - **Input validation**: New endpoints without schema validation, file uploads without size/type limits, path params used directly in filesystem calls (path traversal).
139
+ - **Auth**: New routes/handlers missing auth decorators / middleware. Compare against neighbors in the same file.
140
+ - **Dependencies**: New packages in lockfile — check the name is real (typosquat risk), check project's `dep_audit` tool output if committed. Flag packages with zero downloads or suspicious maintainers.
141
+ - **PII**: New logging statements that could emit PII; new storage of personal data without encryption.
142
+ - **Cross-service auth**: If `context.yml` lists related services, are service-to-service calls authenticated?
143
+
144
+ #### 8c. Compliance
145
+ If `project.compliance` configured, verify per `../references/security-compliance.md` section "Compliance Framework Verification". Any security-tagged scenario in the linked change with no corresponding verification in the diff = **blocker**.
146
+
147
+ #### 8d. Tag findings
148
+ Every security finding gets OWASP 2021 + CWE tags. See the CWE quick-reference in `../references/security-compliance.md`.
149
+
150
+ ### 9. QA Engineer Review (optional)
151
+ Skip if PR is purely internal.
152
+
153
+ - **Test presence**: Every new user-facing behavior has a test? Every scenario from the linked feature file has step definitions?
154
+ - **Test quality**: Are tests asserting outputs, or just that code "ran"? Over-mocked tests are a red flag.
155
+ - **Negative paths**: For each happy path in the diff, is there a failure-path test?
156
+ - **Observability**: New feature — how will it be debugged in prod? Structured logs / metrics / error surfaces?
157
+ - **Regression risk**: Which existing tests cover the touched code? Were any tests removed or weakened in the diff?
158
+ - **Accessibility**: New UI — keyboard nav, aria labels, contrast?
159
+
160
+ ### 10. Data Engineer Review (optional)
161
+ Skip unless diff touches migrations, models, schema files, or external API clients.
162
+
163
+ - **Migrations**: Safe to run on a live DB? Adding a NOT NULL without default on a large table = **blocker**. Renames without a two-step migration = **blocker**.
164
+ - **Indexes**: New foreign keys with no index? New query patterns against unindexed columns?
165
+ - **Naming**: New fields follow existing schema conventions?
166
+ - **Breaking contract**: Compare `data.yml` vs `schema.yml` — removed/renamed/retyped response fields or new required request fields = **blocker** unless a migration path is documented.
167
+ - **Transactions**: Multi-step writes wrapped in a transaction?
168
+
169
+ ### 11. Present Findings
170
+ Compile into a single report structured for PR comments:
171
+
172
+ ```markdown
173
+ # PR Review: <PR title> (#<number>)
174
+
175
+ **Author:** <author> **Base:** <base> **Head:** <head>
176
+ **Linked change:** <change-id or "none — missing Change: trailer">
177
+ **Complexity:** <1-4 or "inferred: moderate">
178
+ **Files changed:** <N> **Lines:** +<add> / -<del>
179
+
180
+ ## Product Manager
181
+ - **[blocker]** Scenario "Login with expired TOTP code" is in the feature file but no corresponding code path in `auth/verify.py`
182
+ - **[suggestion]** PR body doesn't mention the rate-limit change — add it
183
+
184
+ ## Senior Engineer
185
+ - **[blocker]** `utils/hash_helpers.py` duplicates `security/crypto.py::hash_password` — reuse instead
186
+ - **[suggestion]** New abstraction `AuthProviderFactory` has one caller; inline it
187
+
188
+ ## Security Engineer
189
+ ### STRIDE
190
+ - Spoofing: N/A
191
+ - Tampering: new `/api/profile` PATCH has no CSRF token check
192
+ - Info disclosure: `logger.info(f"login attempt for {email}")` emits PII
193
+
194
+ ### Findings
195
+ - **[blocker]** [A01:2021 / CWE-352] Missing CSRF check on `/api/profile` PATCH (`views/profile.py:42`)
196
+ - **[blocker]** [A09:2021 / CWE-532] Email logged in plaintext (`auth/login.py:88`)
197
+ - **[suggestion]** [A07:2021 / CWE-307] No rate limiting on login handler
198
+
199
+ ## QA Engineer
200
+ - **[blocker]** New TOTP verification path has no test (`auth/totp.py:15-48`)
201
+ - **[suggestion]** Add negative test for malformed TOTP string
202
+
203
+ ## Data Engineer
204
+ - **[blocker]** Migration `0042_add_2fa.py` adds NOT NULL `totp_secret` on existing `users` table — will fail on deploy
205
+ (or: "No schema changes — skipped.")
206
+
207
+ ## Summary
208
+ - **5 blockers** — must be addressed before merge
209
+ - **3 suggestions** — consider addressing
210
+
211
+ Recommendation: Request changes.
212
+ ```
213
+
214
+ ### 12. Post to PR (optional)
215
+ Offer three modes:
216
+
217
+ - **Print only** (default) — just show the report
218
+ - **Post single review comment**:
219
+ - GitHub: `gh pr review <id> --comment --body "<report>"` or `--request-changes` if there are blockers
220
+ - GitLab: `glab mr note <id> --message "<report>"`
221
+ - **Post inline comments** — for each finding with a file:line, post a line comment:
222
+ - GitHub: `gh api repos/<org>/<repo>/pulls/<id>/comments -f body=... -f path=... -f line=... -f commit_id=...`
223
+ - This requires the commit SHA — get it from `gh pr view --json commits`
224
+
225
+ Ask the user which mode before posting. Never post without confirmation — PR comments are visible to the whole team.
226
+
227
+ ### 13. Link Back
228
+ If a linked grimoire change was found and the review surfaced blockers that need spec changes (not just code changes), suggest the author run `grimoire-draft` or `grimoire-plan` on that change to update the artifacts before pushing fixes.
229
+
230
+ ## Important
231
+ - This is a code review against a real diff — reference specific files and line numbers for every finding.
232
+ - Be direct. Don't pad with praise. Blockers are things that should stop the merge; suggestions are things the author should consider.
233
+ - Respect the author. Findings describe the code, not the person. "This query is vulnerable to injection" not "you wrote an injection".
234
+ - A PR without a `Change:` trailer in a grimoire repo is a soft finding, not a hard blocker — the team may have reasons.
235
+ - Don't re-derive tasks or specs. If the linked change's artifacts are wrong, that's a separate `grimoire-draft` / `grimoire-plan` cycle.
236
+ - If the diff is too large or too sprawling to review meaningfully, say so — offer to focus on a subset rather than producing a shallow full-pass review.
237
+ - Never post to the PR without explicit user confirmation.
238
+
239
+ ## Done
240
+ When the report is presented (and optionally posted), the workflow is complete. If blockers exist, suggest the author address them; if not, suggest approving via `gh pr review <id> --approve`.
@@ -0,0 +1,251 @@
1
+ ---
2
+ name: grimoire-refactor
3
+ description: Systematically find, prioritize, and plan tech debt reduction. Use when the user wants to identify and address code quality issues, complexity, or duplication.
4
+ compatibility: Designed for Claude Code (or similar products)
5
+ metadata:
6
+ author: kiwi-data
7
+ version: "0.1"
8
+ ---
9
+
10
+ # grimoire-refactor
11
+
12
+ Systematically find, prioritize, and plan tech debt reduction. Combines automated scanning with LLM analysis to produce a prioritized debt register, then feeds approved items into the standard grimoire pipeline (draft → plan → apply).
13
+
14
+ ## Triggers
15
+ - User asks about tech debt, code quality, refactoring opportunities, or simplification
16
+ - User wants to reduce complexity, lines of code, or structural bloat
17
+ - User asks "what should we clean up?" or "where's the tech debt?"
18
+ - Loose match: "refactor", "tech debt", "simplify", "clean up", "reduce complexity", "code smells"
19
+
20
+ ## Routing
21
+ - Behavior change needed (not just code quality) → `grimoire-draft`
22
+ - Removing a feature → `grimoire-remove`
23
+ - Fixing a bug → `grimoire-bug`
24
+ - Documenting existing code → `grimoire-discover`
25
+
26
+ ## Prerequisites
27
+ - A grimoire-initialized project (`.grimoire/` exists)
28
+ - Git history available (hotspot analysis needs `git log`)
29
+ - Ideally: `grimoire map` + `/grimoire:discover` already run (area docs help contextualize findings)
30
+
31
+ ## Debt Item Format
32
+
33
+ Each debt item in the register follows a structured format influenced by the CodeClimate issue spec (categories, severity, remediation effort, fingerprint) and the SEI/CMU Technical Debt Item classification (consequences, causes, evidence of accumulation).
34
+
35
+ **Required fields:**
36
+ - `id` — unique identifier (debt-NNN, monotonically increasing)
37
+ - `category` — one of: `hotspot`, `structural_bloat`, `data_structure`, `circular_dependency`, `dependency_staleness`, `broken_promise`, `duplication`, `dead_code`, `test_debt`
38
+ - `severity` — `high`, `medium`, or `low`
39
+ - `location` — file path (with optional `:line`), or `path ↔ path` for relationships
40
+ - `title` — short human-readable summary
41
+ - `detail` — evidence: what was measured, what threshold was exceeded, what the consequences are
42
+ - `fingerprint` — stable hash of category + location for dedup across scans (so re-scans update existing items rather than creating duplicates)
43
+ - `status` — `open` | `triaged` | `in-progress` | `resolved` | `accepted`
44
+
45
+ **Optional fields:**
46
+ - `metrics` — numeric measurements (churn count, complexity score, line count, field count, age in days, etc.)
47
+ - `suggestion` — recommended refactoring approach
48
+ - `effort` — `small` (<1 hour), `medium` (1-4 hours), `large` (>4 hours)
49
+ - `consequences` — what happens if this debt is NOT addressed (SEI/CMU field — forces articulation of impact)
50
+ - `causes` — how this debt was introduced: `evolution` (grew over time), `deadline` (time pressure), `knowledge` (didn't know better), `dependency` (forced by external constraint)
51
+ - `quadrant` — Fowler's classification: `deliberate-prudent`, `deliberate-reckless`, `inadvertent-prudent`, `inadvertent-reckless`
52
+ - `change_id` — grimoire change created to address this item
53
+ - `first_detected` — date the scanner first found this item (set once, never updated)
54
+ - `last_detected` — date of most recent scan that confirmed this item still exists
55
+
56
+ ## Debt Exceptions
57
+
58
+ The scanner respects `.grimoire/debt-exceptions.yml` — a file where the team explicitly accepts known debt. This is modeled on `.snyk`/`.trivyignore` policy files: accept specific items with a reason, an owner, and an optional expiry date.
59
+
60
+ **Exception matching (checked before any item is added to the register):**
61
+
62
+ 1. **By item ID** — matches a specific debt register entry:
63
+ ```yaml
64
+ - id: debt-003
65
+ reason: "Splitting config types would break the plugin API."
66
+ quadrant: deliberate-prudent
67
+ owner: fred
68
+ accepted: 2026-04-06
69
+ expires: 2026-10-01
70
+ ```
71
+
72
+ 2. **By pattern + category** — matches any finding in files matching the glob:
73
+ ```yaml
74
+ - pattern: "src/vendor/**"
75
+ category: "*" # or a specific category
76
+ reason: "Vendored code — we don't own it"
77
+ quadrant: deliberate-prudent
78
+ owner: fred
79
+ accepted: 2026-04-06
80
+ ```
81
+
82
+ **Exception rules:**
83
+ - Every exception MUST have `reason`, `quadrant`, `owner`, and `accepted` fields. Exceptions without a reason are rejected — the point is to force articulation of the trade-off.
84
+ - `expires` is optional. If set, the scanner re-flags the item after the expiry date and notes it as "exception expired" in the register.
85
+ - `quadrant` uses Fowler's Technical Debt Quadrant to classify the *intent* behind accepting the debt. This isn't just documentation — it helps the team spot patterns (too many `deliberate-reckless` exceptions = systemic problem).
86
+ - When the scanner finds a matching exception, the item is still recorded in the register but with `status: accepted` and a reference to the exception. This means the debt is visible and tracked, just not flagged for action.
87
+ - Expired exceptions cause the item's status to revert to `open` with a note: `"Exception expired YYYY-MM-DD — re-evaluate"`.
88
+ - When a user marks an item as "accept" during the triage flow (step 4), the skill writes the exception to `debt-exceptions.yml` automatically — the user provides the reason, quadrant, and optional expiry interactively.
89
+
90
+ **Scanner behavior:** For each finding, compute fingerprint → check exceptions (by id, then pattern+category) → check if expired → check existing register by fingerprint → add/update item.
91
+
92
+ ## Workflow
93
+
94
+ ### 1. Determine Scope
95
+ Ask the user what to scan:
96
+ - **Full scan** — all categories across the whole codebase (default for first run)
97
+ - **Category scan** — specific debt category (e.g., "just hotspots" or "just structural bloat")
98
+ - **Area scan** — specific directory or module (e.g., "just the API layer")
99
+ - **Refresh** — re-scan and update an existing debt register
100
+
101
+ Check if `.grimoire/docs/debt-register.yml` already exists — don't redo work unless refreshing.
102
+
103
+ ### 2. Run Scans
104
+
105
+ Run applicable scans in parallel. Each scan produces a list of findings with a category, location, severity, and suggested action.
106
+
107
+ Run applicable scans from the categories in `../references/refactor-scan-categories.md`. Each category has specific signals, thresholds, severity levels, and scan commands referencing `config.tools.*` entries.
108
+
109
+ **Key categories** (details in reference):
110
+ - **Hotspots** (churn x complexity) — highest ROI, uses `git log` + `config.tools.complexity`
111
+ - **Structural bloat** — oversized files/functions/classes
112
+ - **Data structure complexity** — over-engineered models, deep nesting
113
+ - **Circular dependencies** — tight coupling between modules
114
+ - **Dependency staleness** — uses `config.tools.dep_audit` or package manager outdated commands
115
+ - **Broken promises** — aged TODO/FIXME/HACK comments via `grep` + `git blame`
116
+ - **Duplication** — uses `.snapshot.json` duplicates or `config.tools.duplicates`
117
+ - **Dead code** — uses `config.tools.dead_code` or `codebase-memory-mcp` graph queries
118
+ - **Test debt** — high complexity + low coverage
119
+
120
+ ### 3. Load Exceptions
121
+
122
+ Before generating the register, read `.grimoire/debt-exceptions.yml`. Parse all exceptions and build a lookup:
123
+ - Index by `id` for direct item matches
124
+ - Index by `pattern` + `category` for glob matches
125
+ - Check `expires` dates — any exception past its expiry date is treated as not matching (the item will be flagged as `open` with a note)
126
+
127
+ If the exceptions file doesn't exist, proceed with no exceptions (all findings are flagged).
128
+
129
+ ### 4. Generate Debt Register
130
+
131
+ Produce `.grimoire/docs/debt-register.yml`. This is the persistent record of known debt, what's been triaged, and what's been addressed.
132
+
133
+ For each finding from the scans:
134
+ 1. Compute a fingerprint: `sha256(category + normalized_location)` — this is the stable identifier for dedup across scans
135
+ 2. Check against exceptions (by id, then by pattern+category)
136
+ 3. Check against existing register (by fingerprint) — preserve status and metadata for known items
137
+ 4. Add or update the item in the register
138
+
139
+ See `../references/refactor-register-format.md` for the full field specification and example items.
140
+
141
+ **Register rules:**
142
+ - Each item has a unique `id` (debt-NNN, monotonically increasing) and a stable `fingerprint` for dedup
143
+ - `status` tracks lifecycle: `open` → `triaged` → `in-progress` → `resolved` (or `accepted` via exception)
144
+ - `first_detected` and `last_detected` track how long debt has been known — debt that persists across many scans is aging and may need escalation
145
+ - Items matched by an exception get `status: accepted` with `quadrant` and `exception_reason` copied from the exception file
146
+ - Items whose exception has expired revert to `status: open` with a note in `detail`: "Exception expired YYYY-MM-DD — re-evaluate"
147
+ - `consequences` should articulate what happens if this debt is NOT addressed — this forces the scanner (and the user) to think about real impact, not just code aesthetics
148
+ - `causes` classifies how the debt was introduced: `evolution` (grew incrementally), `deadline` (time pressure), `knowledge` (didn't know better at the time), `dependency` (forced by external constraint)
149
+ - `change_id` links to the grimoire change created to address it (populated when the user approves a refactoring)
150
+ - `effort` is a rough estimate: `small` (<1 hour), `medium` (1-4 hours), `large` (>4 hours / multiple sessions)
151
+ - On refresh: match by fingerprint, preserve status and first_detected for known items, update last_detected and metrics, add new items, mark items no longer detected as `resolved` automatically
152
+ - Sort by severity (high first), then by hotspot score within severity
153
+
154
+ ### 5. Prioritize and Present
155
+
156
+ Present findings to the user grouped by severity, with recommended action order. Only show items with `status: open` — accepted items are tracked but not flagged.
157
+
158
+ **Prioritization heuristic (automated):**
159
+ 1. **High-severity hotspots first** — highest ROI, every future change benefits
160
+ 2. **High-severity structural bloat** — simplification unlocks everything else
161
+ 3. **High-severity data structure complexity** — foundational, affects many layers
162
+ 4. **Circular dependencies** — blocks clean architecture
163
+ 5. **Everything else by severity**
164
+
165
+ **Present in batches** (same pattern as grimoire-audit — don't dump):
166
+ - Show top 5 items first with their category, location, suggestion, and consequences
167
+ - For each item, ask the user to choose one of:
168
+ - **fix** — create a grimoire change to address it (status → `in-progress`)
169
+ - **defer** — acknowledge but not now (status → `triaged`, revisit next scan)
170
+ - **accept** — the cost of fixing exceeds the benefit (status → `accepted`)
171
+
172
+ **When the user chooses "accept"**, collect exception details interactively:
173
+ 1. Ask for a **reason** (required) — why is this debt acceptable? What's the trade-off?
174
+ 2. Ask for the **Fowler quadrant** (required) — present the four options:
175
+ - `deliberate-prudent`: "We know, and it's the right trade-off for now"
176
+ - `deliberate-reckless`: "We know, and we're cutting corners"
177
+ - `inadvertent-prudent`: "We didn't know then, and fixing isn't worth it now"
178
+ - `inadvertent-reckless`: "We didn't know, and the cost to fix is too high right now"
179
+ 3. Ask for an **expiry date** (optional) — when should this be re-evaluated? If set, the scanner re-flags after this date.
180
+ 4. Write the exception to `.grimoire/debt-exceptions.yml` automatically
181
+ 5. Update the register item: `status: accepted`, `quadrant`, `exception_reason`
182
+
183
+ **If the user chooses "accept" with quadrant `deliberate-reckless`**, flag it gently: "Noted. Just a heads-up — too many deliberate-reckless exceptions may indicate systemic time pressure. You might want to discuss capacity with the team." Don't block, just inform.
184
+
185
+ After the first batch, ask if the user wants to see more or start working on the approved items.
186
+
187
+ **Present a summary of existing exceptions** if any exist:
188
+ - "You have 5 accepted items in debt-exceptions.yml. 1 expires next month."
189
+ - This keeps the team aware of debt they've acknowledged but not resolved.
190
+
191
+ **When presenting, frame simplification opportunities concretely:**
192
+ - "This 847-line file could become 3 files of ~250 lines each"
193
+ - "This 34-method class has 5 distinct responsibilities — extracting them would make each class testable independently"
194
+ - "This 28-field config type is used in 3 contexts — splitting it eliminates 22 optional fields and makes each usage self-documenting"
195
+ - "Flattening this 4-level nested structure into 2 normalized types would eliminate the deep property chains throughout the codebase"
196
+
197
+ ### 6. Create Grimoire Changes
198
+
199
+ For each item the user approves to fix:
200
+
201
+ 1. Create a grimoire change: `refactor-<debt-id>` (e.g., `refactor-debt-001`)
202
+ 2. Update the debt register item: set `status: in-progress`, set `change_id`
203
+ 3. Draft the change using the standard grimoire format:
204
+ - **Manifest** with the refactoring rationale (what the debt is, why it matters, what "done" looks like)
205
+ - **Feature files** if the refactoring changes behavior boundaries (rare for pure refactors, but splitting a module may change its public API)
206
+ - **Decision record** if the refactoring involves an architectural choice (e.g., "extract event system to decouple orders and inventory")
207
+ 4. Hand off to `/grimoire:plan` for task generation, then `/grimoire:apply` for implementation
208
+
209
+ **Refactoring-specific guidance for the plan/apply stages:**
210
+ - **All existing tests must keep passing.** A refactoring that breaks tests is not a refactoring.
211
+ - **Prefer incremental moves over big-bang rewrites.** Move one function at a time, run tests after each move.
212
+ - **Add tests before refactoring if test debt is part of the item.** You need a safety net before restructuring.
213
+ - **Update imports incrementally.** When moving code to a new module, re-export from the old location first, then update consumers, then remove the re-export.
214
+ - **Update area docs after refactoring.** File paths and reusable code locations will have changed.
215
+
216
+ ### 7. Track Progress
217
+
218
+ After refactoring is complete (grimoire apply finishes):
219
+ 1. Update the debt register item: set `status: resolved`
220
+ 2. Update metrics if a re-scan shows improvement
221
+ 3. Present a before/after summary:
222
+ - Lines of code: before → after
223
+ - Complexity: before → after
224
+ - Number of files/classes/functions: before → after
225
+ - Test coverage: before → after (if measurable)
226
+
227
+ ### 8. Ongoing Maintenance
228
+
229
+ The debt register is a living document. Recommend:
230
+ - **Monthly re-scan** to catch new debt and verify resolved items stay resolved
231
+ - **Per-sprint planning** — pick 1-2 high-severity items each sprint alongside feature work
232
+ - **Gate new debt** — the existing grimoire check pipeline (complexity, duplication, best practices) catches debt at commit time. The refactor skill handles accumulated debt.
233
+
234
+ ## Integration with Other Skills
235
+
236
+ - **grimoire-health** — the health score reflects some debt dimensions (coverage, complexity, duplicates). Refactoring should improve health scores.
237
+ - **grimoire-audit** — audit finds undocumented features/decisions. Refactor finds code quality issues. They're complementary — run audit first to understand what the code does, then refactor to improve how it does it.
238
+ - **grimoire-discover** — area docs provide context for refactoring. After refactoring, run discover to update docs.
239
+ - **grimoire-review** — the senior engineer persona already checks for simplicity and reuse. Refactor findings can inform review criteria.
240
+ - **grimoire-check** — the commit-time checks prevent new debt. Refactor addresses existing debt.
241
+
242
+ ## Important
243
+ - **Don't boil the ocean.** Tech debt reduction is incremental. Pick the highest-impact items and make measurable progress. A codebase with zero debt is not the goal — a codebase where debt doesn't slow you down is.
244
+ - **Respect wont-fix.** Some debt is cheaper to live with than to fix. A 500-line file that changes once a year is not worth splitting. Acknowledge this and move on.
245
+ - **Simplification is the primary goal.** Every refactoring should make the codebase smaller, simpler, or more focused. If a refactoring adds complexity (more files, more abstractions, more indirection) without reducing something else, question whether it's actually an improvement.
246
+ - **Measure before and after.** A refactoring without measurable improvement is just code churn. Track lines, complexity, coverage, and file count.
247
+ - **Existing tests are your safety net.** Never refactor without tests. If tests don't exist, write them first (that's test debt — address it before or alongside the structural refactoring).
248
+ - **Present findings collaboratively** — same interview pattern as grimoire-audit. Batches of 3-5, let the user drive priority. Don't dump a 50-item list.
249
+
250
+ ## Done
251
+ When debt items are triaged (fixed, deferred, or accepted) and grimoire changes are created for approved fixes, the workflow is complete. Each approved fix flows through the standard pipeline: `grimoire-plan` → `grimoire-apply`.
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: grimoire-remove
3
+ description: Remove a feature or deprecate a decision through a tracked, deliberate change. Use when the user wants to decommission functionality with full impact assessment.
4
+ compatibility: Designed for Claude Code (or similar products)
5
+ metadata:
6
+ author: kiwi-data
7
+ version: "0.1"
8
+ ---
9
+
10
+ # grimoire-remove
11
+
12
+ Remove a feature or deprecate a decision through a tracked, deliberate change.
13
+
14
+ ## Triggers
15
+ - User wants to remove, deprecate, or sunset a feature
16
+ - User wants to supersede or retire an architecture decision
17
+ - Loose match: "remove", "delete", "deprecate", "sunset", "retire" with feature/decision reference
18
+
19
+ ## Routing
20
+ - Feature was never documented → `grimoire-audit` first to establish baseline
21
+ - Want to change behavior (not remove it) → `grimoire-draft`
22
+ - Want to clean up code quality → `grimoire-refactor`
23
+
24
+ ## Workflow
25
+
26
+ ### 1. Identify What's Being Removed
27
+ - Ask the user what they want to remove and why
28
+ - Read the existing `.feature` file(s) or ADR(s) being targeted
29
+ - Confirm scope: removing an entire feature? Specific scenarios? A decision?
30
+
31
+ ### 2. Assess Impact
32
+ Before creating the change:
33
+ - **Search the codebase** for code implementing the feature/decision
34
+ - **Check other features** — does anything depend on the behavior being removed?
35
+ - **Check decisions** — does removing this feature invalidate any ADRs?
36
+ - **Check step definitions** — what test code will need to be removed?
37
+
38
+ Present the impact summary to the user:
39
+ > "Removing the document overview tab will affect: `document_review/views.py`, `templates/review/overview.html`, 3 step definitions in `test_document_review.py`, and the 'Document Overview Tab' requirement in `features/documents/review.feature`. The 'Error Detail Modal' feature in the same file is independent and won't be affected."
40
+
41
+ ### 3. Create Removal Change
42
+ Scaffold `.grimoire/changes/<change-id>/`:
43
+ - Change ID: verb-led with `remove-` prefix (e.g., `remove-legacy-export`)
44
+
45
+ **Manifest** must include:
46
+ ```markdown
47
+ # Change: Remove <feature/decision>
48
+
49
+ ## Why
50
+ [Clear rationale for removal]
51
+
52
+ ## Migration
53
+ [How users/systems should handle this going away]
54
+ [What replaces it, if anything]
55
+ [Timeline if gradual deprecation]
56
+
57
+ ## Feature Changes
58
+ - **REMOVED** `<capability>/<name>.feature` — [or specific scenarios]
59
+
60
+ ## Decisions
61
+ - **SUPERSEDED** `NNNN-title.md` — [if applicable]
62
+ ```
63
+
64
+ **Proposed feature files:**
65
+ - Copy the current baseline `.feature` file
66
+ - Remove the targeted Feature/Scenarios
67
+ - If removing specific scenarios from a feature, the proposed file is the feature WITHOUT those scenarios
68
+ - If removing an entire feature file, note it in manifest (no proposed file needed — absence is the proposal)
69
+
70
+ ### 4. Generate Tasks
71
+ Create `tasks.md` covering:
72
+
73
+ ```markdown
74
+ ## 1. Remove Production Code
75
+ - [ ] 1.1 Remove <specific code implementing the feature>
76
+ - [ ] 1.2 Remove <related templates/components>
77
+ - [ ] 1.3 Clean up imports and dead references
78
+
79
+ ## 2. Remove Tests
80
+ - [ ] 2.1 Remove step definitions for removed scenarios
81
+ - [ ] 2.2 Remove any unit/integration tests specific to this feature
82
+ - [ ] 2.3 Update shared steps if affected
83
+
84
+ ## 3. Update Related Artifacts
85
+ - [ ] 3.1 Update ADR status to superseded (if applicable)
86
+ - [ ] 3.2 Update any features that referenced removed behavior
87
+
88
+ ## 4. Verification
89
+ - [ ] 4.1 Remaining feature files still pass
90
+ - [ ] 4.2 No dead code / unused imports left behind
91
+ - [ ] 4.3 No broken references in other features
92
+ ```
93
+
94
+ ### 5. Review
95
+ Present the full removal plan to the user:
96
+ - What's being removed (features, scenarios, decisions)
97
+ - What code will be deleted
98
+ - What remains untouched
99
+ - Migration path
100
+
101
+ Do NOT proceed without user approval. Removal is destructive.
102
+
103
+ ## Important
104
+ - Removal is a first-class operation, not a hack. It gets the same rigor as adding a feature.
105
+ - The manifest MUST document WHY something is being removed and what the migration path is.
106
+ - Always check for dependencies before removing. Don't orphan related features or break shared steps.
107
+ - When removing scenarios from a feature (not the whole feature), the proposed `.feature` file represents the desired end state — the feature minus the removed scenarios.
108
+ - After removal, remaining features must still pass. This is verified in the apply stage.
109
+ - Archive preserves the removal rationale forever — future developers can understand why something was removed.
110
+
111
+ ## Done
112
+ When the removal plan is approved and ready for implementation, the workflow is complete. Proceed to `grimoire-apply` to execute the removal tasks.