claude-dev-env 1.47.0 → 1.49.0

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.
@@ -0,0 +1,295 @@
1
+ """Configuration constants for the plain_language_blocker PreToolUse hook."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+
7
+ REPLACEMENT_BY_TERM: dict[str, str] = {
8
+ "addressees are requested": "(omit), please",
9
+ "under the provisions of": "under",
10
+ "interpose no objection": "don't object",
11
+ "afford an opportunity": "allow, let",
12
+ "has a requirement for": "needs",
13
+ "is in consonance with": "agrees with, follows",
14
+ "not later than 10 may": "by 10 May, before 11 May",
15
+ "provides guidance for": "guides",
16
+ "successfully complete": "complete, pass",
17
+ "with the exception of": "except for",
18
+ "due to the fact that": "due to, since",
19
+ "effect modifications": "make changes",
20
+ "in view of the above": "so",
21
+ "adversely impact on": "hurt, set back",
22
+ "at the present time": "at present, now",
23
+ "not later than 1600": "by 1600",
24
+ "combat environment": "combat",
25
+ "in a timely manner": "on time, promptly",
26
+ "in accordance with": "by, following, per, under",
27
+ "in the near future": "shortly, soon",
28
+ "is responsible for": "(omit) handles",
29
+ "on a regular basis": "(omit)",
30
+ "until such time as": "until",
31
+ "during the period": "during",
32
+ "in the process of": "(omit)",
33
+ "with reference to": "about",
34
+ "as prescribed by": "in, under",
35
+ "in the amount of": "for",
36
+ "is applicable to": "applies to",
37
+ "is authorized to": "may",
38
+ "state-of-the-art": "latest",
39
+ "close proximity": "near",
40
+ "for a period of": "for",
41
+ "in an effort to": "to",
42
+ "in the event of": "if",
43
+ "it is essential": "must, need to",
44
+ "it is requested": "please, we request, I request",
45
+ "notwithstanding": "inspite of, still",
46
+ "the undersigned": "I",
47
+ "arrive onboard": "arrive",
48
+ "in relation to": "about, with, to",
49
+ "incumbent upon": "must",
50
+ "limited number": "limits",
51
+ "take action to": "(omit)",
52
+ "as a means of": "to",
53
+ "in order that": "for, so",
54
+ "pertaining to": "about, of, on",
55
+ "provided that": "if",
56
+ "this activity": "us, we",
57
+ "advantageous": "helpful",
58
+ "consequently": "so",
59
+ "in regard to": "about, concerning, on",
60
+ "remuneration": "pay, payment",
61
+ "set forth in": "in",
62
+ "subsequently": "after, later, then",
63
+ "the month of": "(omit)",
64
+ "a number of": "some",
65
+ "accordingly": "so",
66
+ "adjacent to": "next to",
67
+ "appreciable": "many",
68
+ "appropriate": "(omit), proper, right",
69
+ "approximate": "about",
70
+ "by means of": "by, with",
71
+ "comply with": "follow",
72
+ "consolidate": "combine, join, merge",
73
+ "constitutes": "is, forms, makes up",
74
+ "demonstrate": "prove, show",
75
+ "discontinue": "drop, stop",
76
+ "disseminate": "give, issue, pass, send",
77
+ "expeditious": "fast, quick",
78
+ "immediately": "at once",
79
+ "in addition": "also, besides, too",
80
+ "in order to": "to",
81
+ "inasmuch as": "since",
82
+ "methodology": "method",
83
+ "necessitate": "cause, need",
84
+ "participate": "take part",
85
+ "practicable": "practical",
86
+ "proficiency": "skill",
87
+ "pursuant to": "by, following, per, under",
88
+ "relative to": "about, on",
89
+ "requirement": "need",
90
+ "substantial": "large, much",
91
+ "time period": "(either one)",
92
+ "utilization": "use",
93
+ "your office": "you",
94
+ "a and/or b": "a or b or both",
95
+ "accomplish": "carry out, do",
96
+ "additional": "added, more, other",
97
+ "addressees": "you",
98
+ "anticipate": "expect",
99
+ "assistance": "aid, help",
100
+ "be advised": "(omit)",
101
+ "capability": "ability",
102
+ "concerning": "about, on",
103
+ "equipments": "equipment",
104
+ "expiration": "end",
105
+ "facilitate": "ease, help",
106
+ "frequently": "often",
107
+ "heretofore": "until now",
108
+ "in lieu of": "instead",
109
+ "in view of": "since",
110
+ "indication": "sign",
111
+ "inter alia": "(omit)",
112
+ "it appears": "seems",
113
+ "parameters": "limits",
114
+ "previously": "before",
115
+ "prioritize": "rank",
116
+ "promulgate": "issue, publish",
117
+ "represents": "is",
118
+ "similar to": "like",
119
+ "subsequent": "later, next",
120
+ "sufficient": "enough",
121
+ "the use of": "(omit)",
122
+ "accompany": "go with",
123
+ "ascertain": "find out, learn",
124
+ "component": "part",
125
+ "currently": "(omit), now",
126
+ "designate": "appoint, choose, name",
127
+ "determine": "decide, figure, find",
128
+ "eliminate": "cut, drop, end",
129
+ "encounter": "meet",
130
+ "enumerate": "count",
131
+ "equitable": "fair",
132
+ "establish": "set up, prove, show",
133
+ "evidenced": "showed",
134
+ "expertise": "ability",
135
+ "failed to": "didn't",
136
+ "identical": "same",
137
+ "implement": "carry out, start",
138
+ "inception": "start",
139
+ "interface": "meet, work with",
140
+ "magnitude": "size",
141
+ "objective": "aim, goal",
142
+ "regarding": "about, of, on",
143
+ "remainder": "rest",
144
+ "selection": "choice",
145
+ "terminate": "end, stop",
146
+ "there are": "(omit)",
147
+ "therefore": "so",
148
+ "witnessed": "saw",
149
+ "accorded": "given",
150
+ "accurate": "correct, exact, right",
151
+ "aircraft": "plane",
152
+ "allocate": "divide",
153
+ "apparent": "clear, plain",
154
+ "combined": "joint",
155
+ "commence": "begin, start",
156
+ "comprise": "form, include, make up",
157
+ "contains": "has",
158
+ "disclose": "show",
159
+ "endeavor": "try",
160
+ "expedite": "hasten, speed up",
161
+ "feasible": "can be done, workable",
162
+ "finalize": "complete, finish",
163
+ "function": "act, role, work",
164
+ "herewith": "below, here",
165
+ "identify": "find, name, show",
166
+ "impacted": "affected, changed",
167
+ "indicate": "show, write down",
168
+ "initiate": "start",
169
+ "maintain": "keep, support",
170
+ "minimize": "decrease, method",
171
+ "numerous": "many",
172
+ "obligate": "bind, compel",
173
+ "preclude": "prevent",
174
+ "previous": "earlier",
175
+ "prior to": "before",
176
+ "purchase": "buy",
177
+ "relocate": "move",
178
+ "there is": "(omit)",
179
+ "transmit": "send",
180
+ "validate": "confirm",
181
+ "address": "discuss",
182
+ "attempt": "try",
183
+ "benefit": "help",
184
+ "command": "us, we",
185
+ "convene": "meet",
186
+ "evident": "clear",
187
+ "exhibit": "show",
188
+ "females": "women",
189
+ "forfeit": "give up, lose",
190
+ "forward": "send",
191
+ "furnish": "give, send",
192
+ "however": "but",
193
+ "initial": "first",
194
+ "liaison": "discussion",
195
+ "maximum": "greatest, largest, most",
196
+ "minimum": "least, smallest",
197
+ "monitor": "check, watch",
198
+ "observe": "see",
199
+ "operate": "run, use, work",
200
+ "optimum": "best, greatest, most",
201
+ "perform": "do",
202
+ "portion": "part",
203
+ "possess": "have, own",
204
+ "proceed": "do, go ahead, try",
205
+ "procure": "(omit)",
206
+ "provide": "give, offer, say",
207
+ "reflect": "say, show",
208
+ "request": "ask",
209
+ "require": "must, need",
210
+ "solicit": "ask for, request",
211
+ "subject": "the, this, your",
212
+ "therein": "there",
213
+ "thereof": "its, their",
214
+ "utilize": "use",
215
+ "warrant": "call for, permit",
216
+ "whereas": "because, since",
217
+ "accrue": "add, gain",
218
+ "advise": "recommend, tell",
219
+ "assist": "aid, help",
220
+ "attain": "meet",
221
+ "caveat": "warning",
222
+ "delete": "cut, drop",
223
+ "depart": "leave",
224
+ "desire": "want, wish",
225
+ "employ": "use",
226
+ "ensure": "make sure",
227
+ "expend": "spend",
228
+ "herein": "here",
229
+ "modify": "change",
230
+ "notify": "let know, tell",
231
+ "option": "choice, way",
232
+ "permit": "let",
233
+ "remain": "stay",
234
+ "render": "give, make",
235
+ "reside": "live",
236
+ "retain": "keep",
237
+ "submit": "give, send",
238
+ "timely": "prompt",
239
+ "viable": "practical, workable",
240
+ "elect": "choose, pick",
241
+ "it is": "(omit)",
242
+ "deem": "believe, consider, think",
243
+ "said": "the, this, that",
244
+ "same": "the, this, that",
245
+ "such": "the, this, that",
246
+ "type": "(omit)",
247
+ "vice": "instead of, versus",
248
+ }
249
+
250
+ ALL_TERM_PATTERNS: list[tuple[re.Pattern[str], str]] = [
251
+ (re.compile(r"\b" + re.escape(each_term) + r"\b", re.IGNORECASE), each_replacement)
252
+ for each_term, each_replacement in REPLACEMENT_BY_TERM.items()
253
+ ]
254
+
255
+ ALL_SOFTWARE_TERMS: frozenset[str] = frozenset(
256
+ {
257
+ "command",
258
+ "function",
259
+ "address",
260
+ "parameters",
261
+ "interface",
262
+ "component",
263
+ "monitor",
264
+ "request",
265
+ "validate",
266
+ "however",
267
+ "forward",
268
+ "subject",
269
+ "same",
270
+ "such",
271
+ "said",
272
+ "type",
273
+ "it is",
274
+ "there is",
275
+ "there are",
276
+ }
277
+ )
278
+
279
+ FENCED_CODE_BLOCK_PATTERN: re.Pattern[str] = re.compile(r"```[\s\S]*?```", re.MULTILINE)
280
+ INLINE_CODE_PATTERN: re.Pattern[str] = re.compile(r"`[^`]+`")
281
+ BLOCKQUOTE_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\s*>.*$", re.MULTILINE)
282
+ URL_PATTERN: re.Pattern[str] = re.compile(r"https?://\S+", re.IGNORECASE)
283
+ FILE_PATH_PATTERN: re.Pattern[str] = re.compile(
284
+ r"(?<![\w/\\])(?:[A-Za-z]:[\\/]|~?[\\/]|\.{1,2}[\\/])(?:[\w.\-]+[\\/])*[\w.\-]+"
285
+ r"|(?:[\w.\-]+[\\/])+[\w.\-]+\.[A-Za-z0-9]+"
286
+ )
287
+
288
+ MARKDOWN_EXTENSION: str = ".md"
289
+ ASK_USER_QUESTION_TOOL_NAME: str = "AskUserQuestion"
290
+ ALL_WRITE_EDIT_TOOL_NAMES: frozenset[str] = frozenset({"Write", "Edit", "MultiEdit"})
291
+
292
+ USER_FACING_PLAIN_LANGUAGE_NOTICE: str = (
293
+ "Plain-language check: replace each flagged formal word with the simpler "
294
+ "word named in the reason."
295
+ )
@@ -19,6 +19,8 @@ HEADING_LINE_PATTERN: re.Pattern[str] = re.compile(r"^#+[ \t].*$", re.MULTILINE)
19
19
  BOLD_PAIR_PATTERN: re.Pattern[str] = re.compile(r"\*\*([^*]+?)\*\*")
20
20
  BULLET_MARKER_PATTERN: re.Pattern[str] = re.compile(r"^\s*[-*+]\s+", re.MULTILINE)
21
21
  BLOCKQUOTE_MARKER_PATTERN: re.Pattern[str] = re.compile(r"^\s*>\s+", re.MULTILINE)
22
+ BLOCKQUOTE_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\s*>.*$", re.MULTILINE)
23
+ TABLE_ROW_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\s*\|.*\|.*$", re.MULTILINE)
22
24
  LINK_TEXT_PATTERN: re.Pattern[str] = re.compile(r"\[([^\]]+)\]\([^)]+\)")
23
25
  WHITESPACE_RUN_PATTERN: re.Pattern[str] = re.compile(r"\s+")
24
26
 
@@ -115,6 +117,7 @@ __all__ = [
115
117
  "ALL_HEAVY_TESTING_HEADERS",
116
118
  "ALL_READABILITY_CLI_FLAG_TOKENS",
117
119
  "ATOMIC_WRITE_TEMP_SUFFIX",
120
+ "BLOCKQUOTE_LINE_PATTERN",
118
121
  "BLOCKQUOTE_MARKER_PATTERN",
119
122
  "BOLD_PAIR_PATTERN",
120
123
  "BULLET_MARKER_PATTERN",
@@ -147,6 +150,7 @@ __all__ = [
147
150
  "SELF_CLOSING_REFERENCE_MESSAGE_SUFFIX",
148
151
  "SELF_REFERENCE_PATTERN_TEMPLATE",
149
152
  "STANDARD_SHAPE",
153
+ "TABLE_ROW_LINE_PATTERN",
150
154
  "THIS_PR_OPENING_PATTERN",
151
155
  "TRIVIAL_BODY_CHAR_THRESHOLD",
152
156
  "TRIVIAL_SHAPE",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "1.47.0",
3
+ "version": "1.49.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,48 @@
1
+ # Confirm Implementation Forks
2
+
3
+ **When this applies:** During planning or implementation, whenever two or more viable paths would satisfy the goal and the choice changes the deliverable — its scope, completeness, the work it defers, the dependencies it adds, or a contract that is hard to reverse.
4
+
5
+ ## Rule
6
+
7
+ At a material fork, stop and ask the user which path to take through `AskUserQuestion`. Do not silently pick one path and proceed. Present each path as an option whose description states its tradeoff: what it delivers, what it defers, the follow-up cost it creates, and how reversible it is. Begin implementing only after the user chooses.
8
+
9
+ A fork is **material** when any of these hold:
10
+
11
+ - The paths produce different deliverables, scope, or completeness against the stated target.
12
+ - One path defers work — a stub, placeholder, or partial wiring — that creates a follow-up task or hidden debt, while another path completes the work in the same change.
13
+ - The paths diverge on something hard to reverse: architecture, a public API or contract, a data schema, or a newly added dependency.
14
+ - The choice trades off something the user has a stake in: speed against completeness, a scope cut against full coverage, or a shortcut against the original plan's target.
15
+
16
+ When one path quietly drops part of the requested outcome or leaves work for later, that gap is itself the fork — surface it rather than choosing the smaller deliverable on the user's behalf.
17
+
18
+ ## Not a fork — just proceed
19
+
20
+ - Trivially reversible, internal-only choices with no deliverable impact (a local variable name, the layout of a private helper, one of two equivalent standard-library calls).
21
+ - The codebase, the user's stated goal, or an existing rule already determines the answer — follow it (see `verify-before-asking`), and do not manufacture a choice.
22
+ - Only one path is actually viable — implement it; a false choice wastes a round-trip.
23
+
24
+ ## How to ask
25
+
26
+ - Write the question and every option in plain language — short, common words and concrete phrasing a non-expert grasps on first read. Spell out or drop jargon, internal names, and acronyms the user has not already used.
27
+ - Give just enough to decide (progressive disclosure): state each path's outcome and its main tradeoff in a sentence or two, and hold deeper detail in reserve for when the user asks. Do not paste code, long file lists, or background the choice does not need — extra information raises the reader's effort without improving the decision.
28
+ - One option per path. Keep each `label` short; put the tradeoff in the `description`.
29
+ - Recommend the path that best meets the user's stated target and list it first, flagged as recommended (per the AskUserQuestion directive in `CLAUDE.md`).
30
+ - Hold all edits to the forked area until the answer arrives. Continue unrelated, unambiguous work if it helps.
31
+
32
+ ## Examples
33
+
34
+ **Wrong:** Reach a point where the feature can be completed or partially wired with a placeholder, pick the placeholder, and move on — leaving the real implementation as an unrequested follow-up.
35
+ **Right:** Ask: "Complete the feature in this change, or land a placeholder and track the rest as a follow-up?" with each option's cost stated, and wait for the choice.
36
+
37
+ **Wrong:** Add a third-party dependency to solve a problem a few lines of existing code could handle, without flagging it.
38
+ **Right:** Ask whether to add the dependency or hand-roll the small helper, naming the maintenance and footprint tradeoff.
39
+
40
+ ## Why
41
+
42
+ A fork is a scope-or-direction decision the user holds a stake in. Choosing silently commits their effort and tokens to a path they may not want, and a deferred-work path can hide a follow-up the user never agreed to. Surfacing the fork once, with the tradeoffs visible, costs one round-trip and avoids rework.
43
+
44
+ ## Relationship to other rules
45
+
46
+ - **verify-before-asking** gates *whether* a question belongs to the user; a material fork is a judgment or scope call that always does. Resolve anything the codebase can answer first, then ask only about the genuine choice.
47
+ - **conservative-action** governs *whether* to act when intent is ambiguous; this rule names a specific trigger — divergent viable paths — that demands a choice before acting.
48
+ - **ask-user-question-required** governs *how* to ask: route the fork through `AskUserQuestion`, never a plain-text question.
@@ -0,0 +1,44 @@
1
+ # Plain Language
2
+
3
+ **When this applies:** All prose you write — chat responses, `AskUserQuestion` questions and options, documentation and Markdown, PR and issue bodies, and commit messages. Anything a person reads.
4
+
5
+ **Hook enforcement:** `plain_language_blocker` (PreToolUse on `AskUserQuestion` and on Write|Edit|MultiEdit of `.md` targets) blocks a heavy word and names the everyday word to swap in. Code fences, inline code, blockquotes, URLs, and file paths are skipped so exact identifiers stay untouched. See `hooks.json` for registration.
6
+
7
+ ## Rule
8
+
9
+ Write so the reader understands it on the first pass, without hunting for extra context and without wading through more than the point requires. Favor everyday words, short sentences, and concrete phrasing. This is **plain language** (ISO 24495-1:2023; U.S. Plain Writing Act of 2010) — clear writing, not dumbed-down writing.
10
+
11
+ Plain language does not mean dropping technical terms. It means:
12
+
13
+ - **Common word first.** Reach for the plain word when one carries the meaning (`use` over `utilize`, `start` over `initiate`, `enough` over `sufficient`). Keep a technical term when it is the precise name for the thing.
14
+ - **Define jargon and acronyms on first use** — unless the reader has already used them or they are core to the domain you share.
15
+ - **Short sentences, active voice.** One idea per sentence. Name the actor (`the hook blocks the write`, not `the write is blocked by the hook`).
16
+ - **Lead with the answer.** State the conclusion or recommendation first; supporting detail follows.
17
+
18
+ ## Give only what's needed (progressive disclosure)
19
+
20
+ Match the amount of information to what the reader needs to act, and hold the rest in reserve until they ask. Surplus detail raises the reader's **cognitive load** without improving the decision.
21
+
22
+ - Answer the question that was asked; do not also explain three adjacent things.
23
+ - Put the essential point in the first sentence or two; offer or link depth rather than front-loading it.
24
+ - In an `AskUserQuestion`, state each option's outcome and main tradeoff in a sentence; skip code dumps and long file lists.
25
+ - Cut preamble and recap. Do not restate the task back before answering it.
26
+
27
+ ## Readability check
28
+
29
+ Before sending, reread as the recipient: does every sentence land on first read, with no term they must look up and no detail they did not need? If a sentence only makes sense to someone who already knows the backstory, rewrite or cut it. Aim for wording a non-specialist in that area can follow (roughly an 8th–10th grade reading level for general prose; technical reference may sit higher where the terms are unavoidable).
30
+
31
+ ## Not in scope
32
+
33
+ - **Necessary technical precision.** Exact identifiers, file paths, API names, and domain terms stay exact — plain language sharpens the words around them, it does not blur the terms themselves.
34
+ - **Code.** Naming and structure follow the code standards; this rule governs prose.
35
+
36
+ ## Why
37
+
38
+ The reader is short on time and attention, and the first pass is often the only pass. Plain wording and right-sized detail carry the point across in that one pass, while dense or padded text forces the reader to do work the writer should have done. Clear writing also exposes unclear thinking: if an idea is hard to say plainly, it may not be settled yet.
39
+
40
+ ## Relationship to other rules
41
+
42
+ - **confirm-implementation-forks** ("How to ask") applies this rule to fork questions: plain wording, only the detail needed to choose.
43
+ - **self-contained-docs** and **no-historical-clutter** keep a document understandable without outside context; plain language keeps the sentences themselves easy to read.
44
+ - **ask-user-question-required** routes questions through `AskUserQuestion`; this rule governs how those questions are worded.
@@ -10,7 +10,7 @@ An Obsidian vault stores session reports, decisions, and research documents acro
10
10
 
11
11
  ## Vault Structure
12
12
 
13
- - `sessions/` -- session reports with frontmatter: `type: session-report`, `project`, `session`, `date`, `status`, `blocked`, `vault_context_retrieved`, `tags`
13
+ - `sessions/` -- session reports with frontmatter: `type: session-report`, `project`, `session`, `session_id`, `date`, `status`, `blocked`, `vault_context_retrieved`, `tags`
14
14
  - `decisions/` -- decision notes with frontmatter: `type: decision|procedural|fact|gotcha`, `project`, `date`, `status: Active|Superseded`, `tags`
15
15
  - `Research/` -- deep research documents
16
16
 
@@ -31,4 +31,6 @@ At the end of substantive sessions, offer to run `/session-log` if not already i
31
31
 
32
32
  When running `/session-log`, include `vault_context_retrieved: true|false` in frontmatter based on whether vault MCP tools were used this session.
33
33
 
34
+ Also include `session_id` in frontmatter — the session ID of the agent authoring the log, read from the `CLAUDE_CODE_SESSION_ID` environment variable. This UUID names the authoring agent's own transcript file (`<session-id>.jsonl`), so the report points back to the session that produced it; use the literal `unknown` when the variable is unset.
35
+
34
36
  After writing a session log, ALWAYS output a `/rename` command with a descriptive session name based on the session's primary outcome. Format: `/rename [Project] - [Primary Outcome]`. This is a mandatory output requirement, not optional.
@@ -2,9 +2,10 @@
2
2
  name: pr-converge
3
3
  description: >-
4
4
  Drives the current PR to convergence by looping Cursor Bugbot, a
5
- second-opinion bug audit, and Copilot — applying TDD fixes, posting
6
- inline replies, and re-triggering reviewers each tick until all three
7
- reviewers are clean on the same HEAD. Use when the user says
5
+ code-review pass, a second-opinion bug audit, and Copilot — applying
6
+ TDD fixes, posting inline replies, and re-triggering reviewers each
7
+ tick until all reviewers are clean on the same HEAD. Use when the user
8
+ says
8
9
  '/pr-converge', 'drive PR to convergence', 'loop bugbot and bugteam',
9
10
  'babysit bugbot and bugteam', 'until both are clean', or 'converge this
10
11
  PR'.
@@ -12,8 +13,8 @@ description: >-
12
13
 
13
14
  # PR Converge
14
15
 
15
- One tick per invocation. Bugbot ↔ bugteam ↔ Copilot loop on a draft PR
16
- until all three are clean on the same `HEAD` and mergeable.
16
+ One tick per invocation. Bugbot ↔ code-review ↔ bugteam ↔ Copilot loop on
17
+ a draft PR until all are clean on the same `HEAD` and mergeable.
17
18
 
18
19
  ## Pre-flight
19
20
 
@@ -37,9 +38,10 @@ On tick entry, read this file if it exists to restore phase, tick_count, and
37
38
  clean-at SHAs. On tick exit, write updated state before calling ScheduleWakeup
38
39
  so the next tick resumes with accurate state.
39
40
 
40
- Fields: `phase`, `tick_count`, `bugbot_clean_at`, `bugteam_clean_at`,
41
- `copilot_clean_at`, `current_head`, `bugbot_acknowledged_at`, `bugbot_down`,
42
- `bugteam_skill_invoked_at_head`, `bugteam_skill_invoked_at_tick`.
41
+ Fields: `phase`, `tick_count`, `bugbot_clean_at`, `code_review_clean_at`,
42
+ `bugteam_clean_at`, `copilot_clean_at`, `current_head`,
43
+ `bugbot_acknowledged_at`, `bugbot_down`, `bugteam_skill_invoked_at_head`,
44
+ `bugteam_skill_invoked_at_tick`.
43
45
 
44
46
  ## Gotchas
45
47
 
@@ -85,7 +87,8 @@ post a fresh PR in a fresh branch based on origin main to the user.
85
87
 
86
88
  ## Progress checklist
87
89
 
88
- State variables (`phase`, `bugbot_clean_at`, `copilot_clean_at`, counters) are
90
+ State variables (`phase`, `bugbot_clean_at`, `code_review_clean_at`,
91
+ `copilot_clean_at`, counters) are
89
92
  defined in [`reference/state-schema.md`](reference/state-schema.md). Ground rules
90
93
  in [`reference/ground-rules.md`](reference/ground-rules.md).
91
94
 
@@ -127,7 +130,7 @@ no longer applies.
127
130
 
128
131
  - [ ] **Opt-out gate (runs first, every BUGBOT entry).**
129
132
  `python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer bugbot`
130
- - [ ] Exit 0 (`CLAUDE_REVIEWS_DISABLED` lists `bugbot`) → set `bugbot_down = true`, `phase = BUGTEAM`, advance to Step 5 (bypass). Cursor Bugbot is skipped for the entire run.
133
+ - [ ] Exit 0 (`CLAUDE_REVIEWS_DISABLED` lists `bugbot`) → set `bugbot_down = true`, `phase = CODE_REVIEW`, advance to Step 5 (bypass). Cursor Bugbot is skipped for the entire run.
131
134
  - [ ] Exit 1 → continue below.
132
135
 
133
136
  Fetch bugbot reviews + inline comments on `current_head`.
@@ -140,23 +143,45 @@ no longer applies.
140
143
  - [ ] **clean** (no findings on `current_head`) →
141
144
  - [ ] Count ALL unresolved threads on PR (`is_resolved == false`) → zero? advance; >0? fix + resolve first
142
145
  - [ ] `bugbot_clean_at = current_head`
146
+ - [ ] `phase = CODE_REVIEW`
143
147
  - [ ] Advance to Step 5
144
148
  - [ ] **no review yet / commit_id mismatch** →
145
149
  - [ ] Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --owner <O> --repo <R> --check-clean --sha <current_head>`
146
- - [ ] Exit 0 (bugbot CI completed with success/neutral conclusion and no review = silent pass) → `bugbot_clean_at = current_head` → advance to Step 5
150
+ - [ ] Exit 0 (bugbot CI completed with success/neutral conclusion and no review = silent pass) → `bugbot_clean_at = current_head` → `phase = CODE_REVIEW` → advance to Step 5
147
151
  - [ ] Exit 1 (not a silent pass) or Exit 2 (gh CLI error — silent pass not confirmable) → Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --owner <O> --repo <R> --check-active --sha <current_head>`
148
152
  - [ ] Exit 0 (already queued) → schedule 360s wakeup → return to Step 4 next tick
149
153
  - [ ] Exit 1 → post exactly `bugbot run` via `add_issue_comment` (no `@cursor[bot]` mention, no other text), wait 8s
150
154
  - [ ] Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --owner <O> --repo <R> --sha <current_head>`
151
- - [ ] Exit non-zero → `bugbot_down = true` → advance to Step 5 (bypass)
155
+ - [ ] Exit non-zero → `bugbot_down = true` → `phase = CODE_REVIEW` → advance to Step 5 (bypass)
152
156
  - [ ] Exit 0 → record `bugbot_acknowledged_at`, schedule 360s wakeup → return to Step 4
153
- - [ ] **Step 5: BUGTEAM — run, decide, fix, reply, resolve**
157
+ - [ ] **Step 5: CODE-REVIEW — run, fix, reset, advance**
158
+ See: [`reference/per-tick.md` § Step 2 CODE_REVIEW](reference/per-tick.md)
159
+
160
+ Pre-condition: `bugbot_clean_at == current_head` (or `bugbot_down == true`).
161
+
162
+ Run Claude Code's built-in `/code-review --fix` on the current diff —
163
+ the [local diff review](https://code.claude.com/docs/en/code-review#review-a-diff-locally)
164
+ — so it reviews the diff and applies its findings to the working
165
+ tree. Pass no effort argument, so the review uses the session's
166
+ current effort.
167
+
168
+ - [ ] **fixes applied** (working tree changed) →
169
+ - [ ] Commit the applied fixes (one commit) → push
170
+ - [ ] reset `bugbot_clean_at = null`, `code_review_clean_at = null`
171
+ - [ ] Re-trigger bugbot (Step 4 "no review yet" checklist)
172
+ - [ ] `phase = BUGBOT` → schedule 360s wakeup → return to Step 4
173
+ - [ ] **clean** (no changes applied) →
174
+ - [ ] Count ALL unresolved threads on PR (`is_resolved == false`) → zero? advance; >0? fix + resolve first
175
+ - [ ] `code_review_clean_at = current_head`
176
+ - [ ] `phase = BUGTEAM` → advance to Step 6
177
+
178
+ - [ ] **Step 6: BUGTEAM — run, decide, fix, reply, resolve**
154
179
  See: [`reference/per-tick.md` § Step 2 BUGTEAM](reference/per-tick.md);
155
180
  [`../../bugteam/SKILL.md`](../../bugteam/SKILL.md)
156
181
 
157
- Pre-condition: `bugbot_clean_at == current_head` (or `bugbot_down == true`).
182
+ Pre-condition: `code_review_clean_at == current_head`.
158
183
 
159
- Step 5 advances ONLY after `Skill({skill: "bugteam", args: "<PR URL>"})`
184
+ Step 6 advances ONLY after `Skill({skill: "bugteam", args: "<PR URL>"})`
160
185
  fires this tick. Substituting an `Agent({subagent_type: "clean-coder"})`
161
186
  audit call for the formal Skill invocation is a protocol violation — the
162
187
  `pr_converge_bugteam_enforcer` hook blocks it. `qbug` is NOT an accepted
@@ -170,7 +195,7 @@ no longer applies.
170
195
  - [ ] `phase = BUGBOT` → schedule 360s wakeup → return to Step 4
171
196
  - [ ] **converged (zero findings) + `bugbot_clean_at == current_head`** →
172
197
  - [ ] Count ALL unresolved threads on PR (`is_resolved == false`) → zero? advance; >0? fix + resolve first
173
- - [ ] Advance to Step 6
198
+ - [ ] Advance to Step 7
174
199
  - [ ] **converged + `bugbot_clean_at ≠ current_head`** →
175
200
  `phase = BUGBOT` → schedule 360s wakeup → return to Step 4
176
201
  - [ ] **findings without committed fixes** →
@@ -179,10 +204,10 @@ no longer applies.
179
204
  - [ ] Resolve each addressed thread via `pull_request_review_write(method="resolve_thread")`
180
205
  - [ ] Push → `phase = BUGBOT` → return to Step 4
181
206
 
182
- - [ ] **Step 6: Convergence gates**
207
+ - [ ] **Step 7: Convergence gates**
183
208
  See: [`reference/convergence-gates.md`](reference/convergence-gates.md)
184
209
 
185
- Pre-condition: Step 5 converged AND `bugbot_clean_at == current_head`.
210
+ Pre-condition: Step 6 converged AND `bugbot_clean_at == current_head`.
186
211
  Count unresolved threads before each gate.
187
212
 
188
213
  **(a) Universal unresolved-thread sweep**
@@ -221,7 +246,7 @@ no longer applies.
221
246
  gh api --method POST repos/<O>/<R>/pulls/<N>/requested_reviewers \
222
247
  -f 'reviewers[]=copilot-pull-request-reviewer[bot]'
223
248
  ```
224
- - [ ] `phase = COPILOT_WAIT` → schedule 360s wakeup → return to Step 6a next tick
249
+ - [ ] `phase = COPILOT_WAIT` → schedule 360s wakeup → return to Step 7a next tick
225
250
 
226
251
  **(d) Thread resolution — author-agnostic, outdated-agnostic**
227
252
  ```
@@ -240,17 +265,17 @@ no longer applies.
240
265
  python $HOME/.claude/skills/pr-converge/scripts/check_convergence.py \
241
266
  --owner <O> --repo <R> --pr-number <N>
242
267
  ```
243
- - [ ] Exit 0 (all pass) → `update_pull_request(draft=false)` → advance to Step 7
268
+ - [ ] Exit 0 (all pass) → `update_pull_request(draft=false)` → advance to Step 8
244
269
  - [ ] Exit 1 (FAIL lines) → address each failure → return to Step 4
245
270
  - [ ] Exit 2 (gh error) → retry once; persistent → stop
246
271
 
247
- - [ ] **Step 6a: COPILOT_WAIT — fetch Copilot, decide**
272
+ - [ ] **Step 7a: COPILOT_WAIT — fetch Copilot, decide**
248
273
  See: [`reference/per-tick.md` § Step 2 COPILOT_WAIT](reference/per-tick.md)
249
274
 
250
275
  Fetch Copilot reviews + inline comments on `current_head`.
251
276
 
252
277
  - [ ] **clean (no findings)** →
253
- `copilot_clean_at = current_head` → return to Step 6 (re-validate gates b, d, e)
278
+ `copilot_clean_at = current_head` → return to Step 7 (re-validate gates b, d, e)
254
279
  - [ ] **dirty (findings present)** →
255
280
  - [ ] Fix each finding (spawn `clean-coder`)
256
281
  - [ ] Reply to each finding comment via `python ~/.claude/skills/pr-converge/scripts/post_fix_reply.py`
@@ -258,18 +283,18 @@ no longer applies.
258
283
  - [ ] Push → `phase = BUGBOT` → return to Step 4
259
284
  - [ ] **no review yet** →
260
285
  increment `copilot_wait_count` → ≥ 3 = hard blocker → stop
261
- schedule 360s wakeup → return to Step 6a next tick
286
+ schedule 360s wakeup → return to Step 7a next tick
262
287
 
263
- - [ ] **Step 7: Clean working tree**
288
+ - [ ] **Step 8: Clean working tree**
264
289
  See: [`bugteam/reference/teardown-publish-permissions.md` § Step 4](../../bugteam/reference/teardown-publish-permissions.md)
265
290
 
266
- - [ ] **Step 8: Rewrite PR description**
291
+ - [ ] **Step 9: Rewrite PR description**
267
292
  See: [`bugteam/reference/teardown-publish-permissions.md` § Step 4.5](../../bugteam/reference/teardown-publish-permissions.md)
268
293
 
269
- - [ ] **Step 9: Revoke project permissions**
294
+ - [ ] **Step 10: Revoke project permissions**
270
295
  `python "$HOME/.claude/skills/bugteam/scripts/revoke_project_claude_permissions.py"`
271
296
 
272
- - [ ] **Step 10: Print final report**
297
+ - [ ] **Step 11: Print final report**
273
298
  ```
274
299
  /pr-converge exit: converged
275
300
  Loops: <N>
@@ -20,8 +20,19 @@ convergence or stop]
20
20
  </example>
21
21
 
22
22
  <example> BUGBOT tick, bugbot clean against HEAD. Claude: [sets
23
- `bugbot_clean_at = HEAD`, `phase = BUGTEAM`, runs `Skill({skill: "bugteam",
24
- ...})` in same tick]
23
+ `bugbot_clean_at = HEAD`, `phase = CODE_REVIEW`, runs `/code-review --fix`
24
+ in same tick]
25
+ </example>
26
+
27
+ <example> CODE_REVIEW tick, `/code-review --fix` applies fixes to the
28
+ working tree. Claude: [commits the applied fixes in one commit, pushes,
29
+ resets `bugbot_clean_at = null` and `code_review_clean_at = null`, posts
30
+ `bugbot run`, `phase = BUGBOT`, Step 4 at 270s, returns]
31
+ </example>
32
+
33
+ <example> CODE_REVIEW tick, `/code-review --fix` clean (no changes
34
+ applied). Claude: [sets `code_review_clean_at = HEAD`, `phase = BUGTEAM`,
35
+ runs `Skill({skill: "bugteam", ...})` in same tick]
25
36
  </example>
26
37
 
27
38
  <example> BUGTEAM phase, bugteam reports convergence and `bugbot_clean_at