claude-dev-env 1.46.0 → 1.48.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.
- package/CLAUDE.md +11 -1
- package/docs/CODE_RULES.md +26 -0
- package/docs/references/dead-code-elimination.md +17 -0
- package/hooks/blocking/content_search_zoekt_redirect_guidance.py +8 -0
- package/hooks/blocking/test_content_search_to_zoekt_redirector_unit.py +6 -0
- package/package.json +1 -1
- package/rules/confirm-implementation-forks.md +48 -0
- package/rules/plain-language.md +42 -0
- package/rules/vault-context.md +3 -1
- package/skills/pr-converge/SKILL.md +52 -27
- package/skills/pr-converge/reference/examples.md +13 -2
- package/skills/pr-converge/reference/ground-rules.md +6 -4
- package/skills/pr-converge/reference/per-tick.md +33 -6
- package/skills/pr-converge/reference/state-schema.md +5 -1
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +3 -2
- package/skills/pre-compact/SKILL.md +48 -23
- package/skills/session-log/SKILL.md +4 -1
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
# Claude Development Assistant
|
|
2
2
|
|
|
3
|
+
The user is short on time and tokens. When you reply, always assume they'll only read your first few sentences and final sentences. Anything else is skimmed at best. Frame your replies accordingly.
|
|
4
|
+
|
|
5
|
+
The user is short on tokens; whenever a task can be achieved cleanly and effectively, optimize to save the user $$ and token usage.
|
|
6
|
+
|
|
3
7
|
The user delegates execution to you and expects zero manual steps unless strictly necessary. Execute every command you can directly. Only instruct the user to do something manually when you are technically unable to do it yourself. When a task involves credentials or other sensitive input, display a minimal secure UI (e.g., a password dialog) to collect it rather than asking the user to paste it into chat or run the command themselves. When direction is ambiguous, use AskUserQuestion to clarify before acting.
|
|
4
8
|
|
|
5
9
|
## Code Rules
|
|
6
10
|
@~/.claude/docs/CODE_RULES.md
|
|
7
11
|
|
|
12
|
+
When an edit deletes or rewrites code, delete everything it orphans in the same edit — unused variables, uncalled functions, unpassed parameters, dead branches, unused imports — once Serena's `find_referencing_symbols` (plus a text search for dynamic lookups) confirms they're unreachable from any live entry point, not merely unreferenced; when liveness is uncertain, ask via AskUserQuestion rather than risk deleting live code (CODE_RULES.md §9.8).
|
|
13
|
+
|
|
8
14
|
ALWAYS call the AskUserQuestion tool if you have a question for the user. Provide content-appropriate default options, with a flag for the recommended one.
|
|
9
15
|
|
|
10
16
|
## Timeless Documentation (all `.md` files)
|
|
@@ -18,7 +24,10 @@ Full banned-pattern set + enforcement: `~/.claude/rules/no-historical-clutter.md
|
|
|
18
24
|
|
|
19
25
|
## GOTCHAS
|
|
20
26
|
When making code changes, make sure you are working in the proper worktree path for the task at hand.
|
|
21
|
-
|
|
27
|
+
|
|
28
|
+
## Choosing Edit vs Write
|
|
29
|
+
|
|
30
|
+
`Edit` changes existing files; `Write` creates new ones. Default to `Edit` — reach for `Write` only for a genuinely new path. For a true full rewrite, delete the file first, then `Write`.
|
|
22
31
|
|
|
23
32
|
## File-Global Constants
|
|
24
33
|
|
|
@@ -43,3 +52,4 @@ Reserve `Read`/`Grep`/`Glob` for files you will actually touch this turn. Compos
|
|
|
43
52
|
## Additional Non-overlapping Rules
|
|
44
53
|
|
|
45
54
|
- **task_scope:** Match every action to what was explicitly requested. When intent is ambiguous, research official docs and present options via AskUserQuestion before making any changes. Proceed with edits only on explicit instruction.
|
|
55
|
+
- **confirm_implementation_forks:** When two or more viable paths would satisfy the goal and the choice changes the deliverable — its scope, completeness, deferred work, dependencies, or a hard-to-reverse contract — stop and ask which path via AskUserQuestion before implementing. A path that defers work or leaves a placeholder creating a follow-up task is itself a fork to surface, not a default to take silently. Phrase the question in plain language with only the detail needed to decide. See [`confirm-implementation-forks`](rules/confirm-implementation-forks.md).
|
package/docs/CODE_RULES.md
CHANGED
|
@@ -288,6 +288,31 @@ Fallback values mask programming errors (KeyError vs RuntimeError vs AttributeEr
|
|
|
288
288
|
|
|
289
289
|
---
|
|
290
290
|
|
|
291
|
+
## 9.8 REMOVE CODE YOU ORPHAN (Dead Code Elimination)
|
|
292
|
+
|
|
293
|
+
When an edit deletes or rewrites code, it must also remove everything that edit makes dead. The change is not complete while orphans remain.
|
|
294
|
+
|
|
295
|
+
After deleting or rewriting code, trace what it referenced and remove whatever is unreachable as a result:
|
|
296
|
+
|
|
297
|
+
- **Variables** with no remaining readers after the change
|
|
298
|
+
- **Functions / methods** with no remaining call sites
|
|
299
|
+
- **Parameters** that no caller passes
|
|
300
|
+
- **Branches** made unreachable (dead `if`/`else`, conditions that are always true or always false)
|
|
301
|
+
- **Imports** left unused (also caught by the unused-import hook)
|
|
302
|
+
- **Helper files** whose only consumer you just deleted
|
|
303
|
+
|
|
304
|
+
**Confirm the orphan is truly unreferenced first.** "No remaining call sites" means none *anywhere in the codebase*, not just in the file you edited. Before removing a function, method, class, or module-level name, run Serena's `find_referencing_symbols` on it: the language server resolves call sites, `import` statements, and re-exports across files far more reliably and cheaply than a text sweep. Back it with a plain text search for string-based dynamic lookups (`getattr`, entry-point names) that the language server cannot see. A reference is not proof of life — the referrer can be dead too. The symbol is live only when some chain of references reaches a live entry point: a CLI command, route, public API, test, or any caller outside the code you are removing. Trace the referrers upward. If every chain dead-ends in code that is itself unreferenced, the whole cluster is dead — remove it together in the same commit (§9.6). If any chain reaches a live entry point, the symbol is in use; leave it. Deleting something still reachable breaks its importers; treating a self-referential dead cluster as alive leaves litter.
|
|
305
|
+
|
|
306
|
+
**When liveness is uncertain, ask — never guess.** A tool cannot always tell what is live: a chain may leave the repository (a public API, plugin hook, or module other projects import), or run through dynamic or reflective dispatch that no search resolves. If you cannot conclusively prove a symbol is unreachable, do not delete it. Surface the specific ambiguity to the user through AskUserQuestion and let them decide. Removing live production code is never an acceptable risk — when in doubt, keep it and ask.
|
|
307
|
+
|
|
308
|
+
This is the inverse of comment preservation: existing **comments** are sacred and never removed, but dead **code** is removed in the same edit that orphans it. A function left with no callers is not "preserved" — it is litter.
|
|
309
|
+
|
|
310
|
+
> **See also:** §9.6 (a renamed alias is dead code by another name), the `file_global_constants_use_count` rule (zero references → delete), and the unused-import hook check — each enforces a specific slice of this principle automatically.
|
|
311
|
+
|
|
312
|
+
> **Standard terms (shorthand for this section):** the mechanical part is *dead code elimination* (compilers; Aho et al., *Compilers: Principles, Techniques, and Tools*) and *tree-shaking* (bundlers like Rollup/Webpack) — retain only what is reachable from a live entry point. The ask-when-uncertain overlay guards against the *Lava Flow* anti-pattern — dead code kept because removing it feels risky (Brown et al., *AntiPatterns*, 1998). Compare Fowler's "Remove Dead Code" refactoring (*Refactoring*, 2nd ed., 2018). Direct source links: [`references/dead-code-elimination.md`](references/dead-code-elimination.md).
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
291
316
|
## 10. NO REDUNDANT DATA FETCHES
|
|
292
317
|
|
|
293
318
|
If you already have data, don't fetch again.
|
|
@@ -384,5 +409,6 @@ Manual check:
|
|
|
384
409
|
[ ] OCP/LSP/ISP/DIP only applied where abstractions already earn their keep (see §7.5)?
|
|
385
410
|
[ ] No backwards-compatibility shims (§9.6)?
|
|
386
411
|
[ ] No fallback/best-effort wrappers (§9.7)?
|
|
412
|
+
[ ] No code orphaned by an edit (§9.8 — dead vars, uncalled functions, unused imports, dead branches)?
|
|
387
413
|
[ ] Readability: /check
|
|
388
414
|
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Dead Code Elimination — Reference
|
|
2
|
+
|
|
3
|
+
External sources and standard terminology behind [CODE_RULES §9.8](../CODE_RULES.md#98-remove-code-you-orphan-dead-code-elimination). Each entry names the concept, gives a one-line definition, and links a direct source.
|
|
4
|
+
|
|
5
|
+
## The mechanic — removing code that cannot affect results
|
|
6
|
+
|
|
7
|
+
- **Dead-code elimination (DCE)** — a compiler optimization that removes code which does not affect program results, reducing program size, resource use, and execution time. Foundational treatment: Aho, Lam, Sethi & Ullman, *Compilers: Principles, Techniques, and Tools* (the "Dragon Book"). <https://en.wikipedia.org/wiki/Dead-code_elimination>
|
|
8
|
+
- **Tree shaking** — dead-code elimination driven by `import`/`export` structure: keep only the exports reachable from an entry point and drop the rest. MDN glossary: <https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking>. Webpack guide: <https://webpack.js.org/guides/tree-shaking/>
|
|
9
|
+
- **Remove Dead Code** — the named refactoring for eliminating unreachable or unused segments to improve clarity and maintainability. Martin Fowler, *Refactoring* (2nd ed., 2018): <https://refactoring.com/catalog/removeDeadCode.html>
|
|
10
|
+
|
|
11
|
+
## The liveness test — reachability, not mere reference
|
|
12
|
+
|
|
13
|
+
- **Unreachable code / reachability analysis** — code with no control-flow path from the rest of the program; detecting it is a form of control-flow analysis. This is the basis for §9.8 testing reachability from a live entry point rather than the bare presence of a reference. <https://en.wikipedia.org/wiki/Unreachable_code>
|
|
14
|
+
|
|
15
|
+
## The safety overlay — why uncertain deletions escalate
|
|
16
|
+
|
|
17
|
+
- **Lava Flow anti-pattern** — suboptimal code that survives in production because accumulated dependencies and backward-compatibility fears make removal feel risky. Brown, Malveau, McCormick & Mowbray, *AntiPatterns* (1998). The §9.8 "ask when uncertain, never guess-delete" clause guards against blind risky removals. <https://en.wikipedia.org/wiki/Lava_flow_(programming)>
|
|
@@ -32,6 +32,14 @@ def get_zoekt_redirect_guidance() -> str:
|
|
|
32
32
|
"positively, e.g. mcp__zoekt__search(query=\"your pattern file:"
|
|
33
33
|
+ worktree_filter_fragment
|
|
34
34
|
+ "<branch>/\").\n\n"
|
|
35
|
+
"INDEX FRESHNESS: the index trails just-written code — recent or unpushed commits sync and reindex "
|
|
36
|
+
"on a short delay, so a symbol you just added can be missing from Zoekt for a few minutes even though "
|
|
37
|
+
"it is on disk. Worktrees are fully indexed and retrievable with the positive 'file:"
|
|
38
|
+
+ worktree_filter_fragment
|
|
39
|
+
+ "<branch>/' filter above, but that same lag applies to anything freshly edited. When a Zoekt search "
|
|
40
|
+
"returns nothing for code you know exists on disk, do not treat it as absent: Grep a specific file "
|
|
41
|
+
"(a path ending in a file extension is exempt from this redirect) or read the file directly to confirm "
|
|
42
|
+
"current contents.\n\n"
|
|
35
43
|
"INDEX ROOTS (when Grep/Search in a tree is redirected): set ZOEKT_REDIRECT_INDEXED_ROOTS to a JSON array "
|
|
36
44
|
"of absolute paths, or ~/.claude/zoekt-indexed-roots.json as {\"roots\": [\"/abs/path/to/repo/\", ...]}. "
|
|
37
45
|
"Optional ZOEKT_REDIRECT_INDEXED_ROOTS_FILE points to a different JSON file. "
|
|
@@ -81,6 +81,12 @@ class RedirectGuidanceWorktreeTests(unittest.TestCase):
|
|
|
81
81
|
def test_worktree_display_fragment_is_the_unescaped_path(self) -> None:
|
|
82
82
|
self.assertEqual(worktree_path_display_fragment(), ".claude/worktrees/")
|
|
83
83
|
|
|
84
|
+
def test_guidance_documents_index_freshness_escape_hatch(self) -> None:
|
|
85
|
+
guidance = get_zoekt_redirect_guidance()
|
|
86
|
+
self.assertIn("INDEX FRESHNESS:", guidance)
|
|
87
|
+
self.assertIn("exempt from this redirect", guidance)
|
|
88
|
+
self.assertIn("read the file directly", guidance)
|
|
89
|
+
|
|
84
90
|
|
|
85
91
|
if __name__ == "__main__":
|
|
86
92
|
unittest.main()
|
package/package.json
CHANGED
|
@@ -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,42 @@
|
|
|
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
|
+
## Rule
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
Plain language does not mean dropping technical terms. It means:
|
|
10
|
+
|
|
11
|
+
- **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.
|
|
12
|
+
- **Define jargon and acronyms on first use** — unless the reader has already used them or they are core to the domain you share.
|
|
13
|
+
- **Short sentences, active voice.** One idea per sentence. Name the actor (`the hook blocks the write`, not `the write is blocked by the hook`).
|
|
14
|
+
- **Lead with the answer.** State the conclusion or recommendation first; supporting detail follows.
|
|
15
|
+
|
|
16
|
+
## Give only what's needed (progressive disclosure)
|
|
17
|
+
|
|
18
|
+
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.
|
|
19
|
+
|
|
20
|
+
- Answer the question that was asked; do not also explain three adjacent things.
|
|
21
|
+
- Put the essential point in the first sentence or two; offer or link depth rather than front-loading it.
|
|
22
|
+
- In an `AskUserQuestion`, state each option's outcome and main tradeoff in a sentence; skip code dumps and long file lists.
|
|
23
|
+
- Cut preamble and recap. Do not restate the task back before answering it.
|
|
24
|
+
|
|
25
|
+
## Readability check
|
|
26
|
+
|
|
27
|
+
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).
|
|
28
|
+
|
|
29
|
+
## Not in scope
|
|
30
|
+
|
|
31
|
+
- **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.
|
|
32
|
+
- **Code.** Naming and structure follow the code standards; this rule governs prose.
|
|
33
|
+
|
|
34
|
+
## Why
|
|
35
|
+
|
|
36
|
+
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.
|
|
37
|
+
|
|
38
|
+
## Relationship to other rules
|
|
39
|
+
|
|
40
|
+
- **confirm-implementation-forks** ("How to ask") applies this rule to fork questions: plain wording, only the detail needed to choose.
|
|
41
|
+
- **self-contained-docs** and **no-historical-clutter** keep a document understandable without outside context; plain language keeps the sentences themselves easy to read.
|
|
42
|
+
- **ask-user-question-required** routes questions through `AskUserQuestion`; this rule governs how those questions are worded.
|
package/rules/vault-context.md
CHANGED
|
@@ -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
|
|
6
|
-
inline replies, and re-triggering reviewers each
|
|
7
|
-
reviewers are clean on the same HEAD. Use when the user
|
|
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
|
|
16
|
-
until all
|
|
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`, `
|
|
41
|
-
`
|
|
42
|
-
`
|
|
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`, `
|
|
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 =
|
|
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:
|
|
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: `
|
|
182
|
+
Pre-condition: `code_review_clean_at == current_head`.
|
|
158
183
|
|
|
159
|
-
Step
|
|
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
|
|
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
|
|
207
|
+
- [ ] **Step 7: Convergence gates**
|
|
183
208
|
See: [`reference/convergence-gates.md`](reference/convergence-gates.md)
|
|
184
209
|
|
|
185
|
-
Pre-condition: Step
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
286
|
+
schedule 360s wakeup → return to Step 7a next tick
|
|
262
287
|
|
|
263
|
-
- [ ] **Step
|
|
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
|
|
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
|
|
294
|
+
- [ ] **Step 10: Revoke project permissions**
|
|
270
295
|
`python "$HOME/.claude/skills/bugteam/scripts/revoke_project_claude_permissions.py"`
|
|
271
296
|
|
|
272
|
-
- [ ] **Step
|
|
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 =
|
|
24
|
-
|
|
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
|
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
- **All `*_clean_at`, `merge_state_status`, and `bugbot_down` reset on every push.**
|
|
7
7
|
- **`bugbot run` comment is load-bearing.** Literal phrase exactly —
|
|
8
8
|
empirically the only re-trigger Cursor Bugbot recognizes.
|
|
9
|
-
- **
|
|
10
|
-
production files
|
|
11
|
-
Claude finding
|
|
12
|
-
implement.
|
|
9
|
+
- **Production edits go through `clean-coder`, except `/code-review --fix`.**
|
|
10
|
+
The lead never hand-edits production files. Every bugbot, bugteam,
|
|
11
|
+
Copilot, or Claude finding spawns `Agent(subagent_type="clean-coder")` to
|
|
12
|
+
implement the fix. The CODE_REVIEW phase is the one exception: `/code-review
|
|
13
|
+
--fix` applies its own findings to the working tree, which the next
|
|
14
|
+
BUGBOT/BUGTEAM cycle re-reviews after the loop resets.
|
|
13
15
|
- **Adapt when reality contradicts on-disk state.** If `state.json`,
|
|
14
16
|
`git`, or `gh` disagree with live PR, escalate as hard blocker per
|
|
15
17
|
[stop-conditions.md](stop-conditions.md).
|
|
@@ -53,7 +53,7 @@ Capture `number`, `head.sha` (= `current_head`), owner/repo, branch.
|
|
|
53
53
|
`python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer bugbot`
|
|
54
54
|
|
|
55
55
|
- Exit 0 (`CLAUDE_REVIEWS_DISABLED` lists `bugbot`) → set `bugbot_down = true`,
|
|
56
|
-
`phase =
|
|
56
|
+
`phase = CODE_REVIEW`, continue CODE_REVIEW in the same tick; skip steps a–c below.
|
|
57
57
|
- Exit 1 → proceed to step a.
|
|
58
58
|
|
|
59
59
|
Because `bugbot_down` resets on every push, this gate re-runs on every
|
|
@@ -99,9 +99,9 @@ c. Decide (four branches; match first whose predicate holds):
|
|
|
99
99
|
null`, reset `inline_lag_streak = 0`, schedule next wakeup, return.
|
|
100
100
|
- **`commit_id == current_head` AND zero unaddressed inline AND review
|
|
101
101
|
body clean:** Set `bugbot_clean_at = current_head`, reset
|
|
102
|
-
`inline_lag_streak = 0`, `phase =
|
|
103
|
-
tick — back-to-back convergence requires
|
|
104
|
-
before next wakeup.
|
|
102
|
+
`inline_lag_streak = 0`, `phase = CODE_REVIEW`. Continue CODE_REVIEW
|
|
103
|
+
in same tick — back-to-back convergence requires code-review then
|
|
104
|
+
bugteam on same HEAD before next wakeup.
|
|
105
105
|
- **`commit_id == current_head` with unaddressed inline findings:**
|
|
106
106
|
Apply **Fix protocol**. Reset `inline_lag_streak = 0`. With
|
|
107
107
|
`state.json`: clean-coder teammate pushes, replies inline, writes
|
|
@@ -113,6 +113,33 @@ c. Decide (four branches; match first whose predicate holds):
|
|
|
113
113
|
full contract).
|
|
114
114
|
Schedule next wakeup, return.
|
|
115
115
|
|
|
116
|
+
### `phase == CODE_REVIEW`
|
|
117
|
+
|
|
118
|
+
Local correctness/quality pass between BUGBOT clean and BUGTEAM. Enters
|
|
119
|
+
after BUGBOT reports clean on `current_head` (or `bugbot_down == true`).
|
|
120
|
+
Runs Claude Code's built-in `/code-review --fix` on the current diff; it
|
|
121
|
+
produces no GitHub review artifact, so there are no code-review threads to
|
|
122
|
+
resolve.
|
|
123
|
+
|
|
124
|
+
a. Run Claude Code's built-in `/code-review --fix` on the current diff —
|
|
125
|
+
the [local diff review](https://code.claude.com/docs/en/code-review#review-a-diff-locally).
|
|
126
|
+
It reviews the diff and applies its findings to the working tree. Pass
|
|
127
|
+
no effort argument, so the review uses the session's current effort.
|
|
128
|
+
|
|
129
|
+
b. Decide (two branches; match first whose predicate holds):
|
|
130
|
+
|
|
131
|
+
- **`/code-review` applied fixes (working tree changed):** Commit the
|
|
132
|
+
applied fixes in one commit → push, following [Single-PR fix
|
|
133
|
+
workflow](fix-protocol.md#single-pr-fix-workflow). Reset
|
|
134
|
+
`bugbot_clean_at = null` AND `code_review_clean_at = null`. Re-trigger
|
|
135
|
+
bugbot (Step 3) so the new HEAD enters the queue. Set `phase = BUGBOT`,
|
|
136
|
+
schedule next wakeup, return. A code-review fix push requires a full
|
|
137
|
+
back-to-back-clean cycle on the new HEAD.
|
|
138
|
+
- **Clean (no changes applied):** Set
|
|
139
|
+
`code_review_clean_at = current_head`, `phase = BUGTEAM`. Continue
|
|
140
|
+
BUGTEAM in same tick — back-to-back convergence requires bugbot,
|
|
141
|
+
code-review, and bugteam all clean on the same HEAD.
|
|
142
|
+
|
|
116
143
|
### `phase == BUGTEAM`
|
|
117
144
|
|
|
118
145
|
a. Run **bugteam** on current PR.
|
|
@@ -222,14 +249,14 @@ BUGBOT.
|
|
|
222
249
|
`bugbot_down = true` and routes to BUGTEAM before any trigger flow runs,
|
|
223
250
|
so the checks below are skipped.
|
|
224
251
|
- [ ] **Silent-pass pre-check.** Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --check-clean --owner <O> --repo <R> --sha <current_head>`
|
|
225
|
-
- [ ] Exit 0 → bugbot CI completed clean with no review (silent pass); set `bugbot_clean_at = current_head`, `phase =
|
|
252
|
+
- [ ] Exit 0 → bugbot CI completed clean with no review (silent pass); set `bugbot_clean_at = current_head`, `phase = CODE_REVIEW`, continue CODE_REVIEW same tick
|
|
226
253
|
- [ ] Exit 1 (not a silent pass) or Exit 2 (gh CLI error — silent pass not confirmable) → continue with the trigger flow below
|
|
227
254
|
- [ ] Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --check-active --owner <O> --repo <R> --sha <current_head>`
|
|
228
255
|
- [ ] Exit 0 → bugbot already queued on this commit; skip posting, wait for completion
|
|
229
256
|
- [ ] Exit 1 → post trigger via `add_issue_comment(owner="OWNER", repo="REPO", issueNumber=NUMBER, body="bugbot run")`
|
|
230
257
|
- [ ] Wait 8s
|
|
231
258
|
- [ ] Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --owner <O> --repo <R> --sha <current_head>`
|
|
232
|
-
- [ ] Exit non-zero → bugbot is down; set `bugbot_down = true`, `phase =
|
|
259
|
+
- [ ] Exit non-zero → bugbot is down; set `bugbot_down = true`, `phase = CODE_REVIEW`, continue CODE_REVIEW same tick
|
|
233
260
|
- [ ] Exit 0 (check run present) → record `bugbot_acknowledged_at = <now ISO 8601>`, proceed to Step 4
|
|
234
261
|
|
|
235
262
|
The silent-pass pre-check fires FIRST so we never re-trigger a bot that
|
|
@@ -9,9 +9,13 @@ across PRs. Both files share most of the fields below; the
|
|
|
9
9
|
live ONLY in the single-PR `$CLAUDE_JOB_DIR/pr-converge-state.json` file
|
|
10
10
|
(see those field entries below for details).
|
|
11
11
|
|
|
12
|
-
- `phase`: `BUGBOT`, `BUGTEAM`, or `COPILOT_WAIT`. Start
|
|
12
|
+
- `phase`: `BUGBOT`, `CODE_REVIEW`, `BUGTEAM`, or `COPILOT_WAIT`. Start
|
|
13
|
+
`BUGBOT` on first tick.
|
|
13
14
|
- `bugbot_clean_at`: HEAD SHA where bugbot last reported clean, or `null`.
|
|
14
15
|
Reset to `null` on every push.
|
|
16
|
+
- `code_review_clean_at`: HEAD SHA where the `/code-review` pass last
|
|
17
|
+
reported clean (no validated findings), or `null`. Reset to `null` on
|
|
18
|
+
every push.
|
|
15
19
|
- `copilot_clean_at`: HEAD SHA where Copilot last reported clean, or `null`.
|
|
16
20
|
Reset to `null` on every push.
|
|
17
21
|
- `copilot_wait_count`: integer, init `0`. Consecutive COPILOT_WAIT ticks
|
|
@@ -6,8 +6,9 @@ guarantees `ScheduleWakeup` is available before any tick runs. Shared bugbot
|
|
|
6
6
|
|
|
7
7
|
## Calling ScheduleWakeup
|
|
8
8
|
|
|
9
|
-
At end of every tick — across all phases (BUGBOT, BUGTEAM,
|
|
10
|
-
without distinction — call `ScheduleWakeup` unless convergence
|
|
9
|
+
At end of every tick — across all phases (BUGBOT, CODE_REVIEW, BUGTEAM,
|
|
10
|
+
COPILOT_WAIT) without distinction — call `ScheduleWakeup` unless convergence
|
|
11
|
+
or another
|
|
11
12
|
stop condition already omitted pacing:
|
|
12
13
|
|
|
13
14
|
- `delaySeconds: 360` — default wakeup interval. Keeps the loop advancing
|
|
@@ -5,8 +5,10 @@ description: >-
|
|
|
5
5
|
`/compact <directive>` string to the operator's clipboard so the next prompt
|
|
6
6
|
is a single paste. The directive pins the session's load-bearing identifiers
|
|
7
7
|
(branch, PR, HEAD, worktree, in-flight work, decisions, blockers, files in
|
|
8
|
-
play, follow-ups)
|
|
9
|
-
|
|
8
|
+
play, follow-ups) the next steps depend on, so the summarizer keeps them with
|
|
9
|
+
high fidelity. It confirms the operator's intent for the next chat through a
|
|
10
|
+
structured question first, then validates each identifier against its live
|
|
11
|
+
source before stating it. Use when the user says `/pre-compact`, asks to prep for compaction, or
|
|
10
12
|
asks to compose a focus directive for `/compact`.
|
|
11
13
|
disable-model-invocation: true
|
|
12
14
|
---
|
|
@@ -20,16 +22,35 @@ string to the operator's clipboard.
|
|
|
20
22
|
|
|
21
23
|
**Announce at start:** "I'm composing your compact focus directive."
|
|
22
24
|
|
|
23
|
-
## Step 1 —
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
## Step 1 — Confirm the next-session intent
|
|
26
|
+
|
|
27
|
+
Before composing anything, ask the operator what they intend to work on in
|
|
28
|
+
the next chat. Do not infer it silently from the conversation, and do not
|
|
29
|
+
ask it raw — use `AskUserQuestion` with two to four options drawn from the
|
|
30
|
+
session context (the threads left open, the obvious next actions, the task
|
|
31
|
+
the operator last steered toward); the tool's free-text fallback covers
|
|
32
|
+
anything unlisted. The selected intent is the directive's forward task:
|
|
33
|
+
Step 2 scopes every field to what that intent needs, and the rendered
|
|
34
|
+
`In-flight` line states it.
|
|
35
|
+
|
|
36
|
+
## Step 2 — Read and validate the live session
|
|
37
|
+
|
|
38
|
+
Validate every identifier directly before stating it. Conversation context
|
|
39
|
+
goes stale within a session — a PR merges, HEAD advances, a worktree
|
|
40
|
+
advances to a newer commit — so confirm each value against its live source
|
|
41
|
+
at compose time rather than carrying it from memory. Run the command in
|
|
42
|
+
each field's Source column; for a PR, capture its merge state
|
|
43
|
+
(`gh pr view --json state,mergedAt`) and state `merged` or `open` from that
|
|
44
|
+
result, never from recollection. A value that cannot be confirmed against a
|
|
45
|
+
live source is not dropped silently — surface it to the operator via
|
|
46
|
+
`AskUserQuestion` to clarify (offer the candidate values found plus the
|
|
47
|
+
free-text fallback) and use the answer. Omit it only when the operator
|
|
48
|
+
chooses to skip it.
|
|
28
49
|
|
|
29
50
|
| Field | What to capture | Source |
|
|
30
51
|
|---|---|---|
|
|
31
52
|
| `branch` | Active branch name | `git branch --show-current` |
|
|
32
|
-
| `pr` | Active PR number, when one exists | `gh pr view --json number` |
|
|
53
|
+
| `pr` | Active PR number and its merge state (open / merged), when one exists | `gh pr view --json number,state,mergedAt` |
|
|
33
54
|
| `head` | Short HEAD SHA (whatever `git rev-parse --short` outputs) | `git rev-parse --short HEAD` |
|
|
34
55
|
| `worktree` | Absolute path to the working directory | `pwd` |
|
|
35
56
|
| `in_flight` | One sentence describing what is being worked on right now | conversation |
|
|
@@ -41,7 +62,15 @@ not already in context.
|
|
|
41
62
|
A field whose value cannot be stated as a concrete identifier is omitted
|
|
42
63
|
from the directive.
|
|
43
64
|
|
|
44
|
-
|
|
65
|
+
Scope every field to what the Step 1 intent needs next. Compaction carries
|
|
66
|
+
forward the slice of session history the remaining work needs: capture a
|
|
67
|
+
`decision`, `blocker`, or `in_flight` detail when a next step relies on
|
|
68
|
+
it, and leave a detail the next steps do not touch (a settled question, a
|
|
69
|
+
resolved blocker, a path not taken) out by simply not listing it. When a
|
|
70
|
+
settled decision still constrains the next step, list its outcome as one
|
|
71
|
+
line, not the deliberation behind it.
|
|
72
|
+
|
|
73
|
+
## Step 3 — Render the directive
|
|
45
74
|
|
|
46
75
|
Render this exact shape, populating only the fields with concrete values:
|
|
47
76
|
|
|
@@ -56,25 +85,21 @@ Preserve:
|
|
|
56
85
|
- Blockers: <bullet per blocker>
|
|
57
86
|
- Files: <path>, <path>, <path>
|
|
58
87
|
- Follow-ups: <bullet per follow-up>
|
|
59
|
-
|
|
60
|
-
Drop:
|
|
61
|
-
- Tool outputs already applied to files
|
|
62
|
-
- Per-tick progress narration
|
|
63
|
-
- Resolved findings and superseded SHAs
|
|
64
|
-
- Listing/grep output whose conclusion appears above
|
|
65
88
|
```
|
|
66
89
|
|
|
67
|
-
The
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
90
|
+
The directive lists only what the next steps consume, so the summarizer
|
|
91
|
+
preserves that with high fidelity and compresses the rest of the trace on
|
|
92
|
+
its own — naming what to keep is a clearer instruction than enumerating
|
|
93
|
+
what to cut. Keep the list tight: a `Preserve:` block padded with finished
|
|
94
|
+
or out-of-scope context dilutes the summarizer's focus on what happens
|
|
95
|
+
next.
|
|
71
96
|
|
|
72
97
|
Source: [Effective context engineering for AI agents](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents)
|
|
73
98
|
— "start by maximizing recall to ensure your compaction prompt captures
|
|
74
99
|
every relevant piece of information from the trace, then iterate to improve
|
|
75
100
|
precision by eliminating superfluous content."
|
|
76
101
|
|
|
77
|
-
## Step
|
|
102
|
+
## Step 4 — Copy `/compact <directive>` to the clipboard
|
|
78
103
|
|
|
79
104
|
Write the full `/compact <directive>` string to a temporary file via the
|
|
80
105
|
Write tool, then copy the file contents to the clipboard with PowerShell:
|
|
@@ -91,7 +116,7 @@ unmodified regardless of which characters it contains.
|
|
|
91
116
|
A reasonable temp path under `$env:TEMP` (Windows) or `$TMPDIR` (POSIX)
|
|
92
117
|
works; clean it up after the `Set-Clipboard` call returns.
|
|
93
118
|
|
|
94
|
-
## Step
|
|
119
|
+
## Step 5 — Hand off
|
|
95
120
|
|
|
96
121
|
Print this confirmation line to the operator:
|
|
97
122
|
|
|
@@ -99,8 +124,8 @@ Print this confirmation line to the operator:
|
|
|
99
124
|
> compact this conversation with focus.
|
|
100
125
|
|
|
101
126
|
Then list up to the first three `Preserve:` bullets (or fewer when the
|
|
102
|
-
directive omits fields)
|
|
103
|
-
|
|
127
|
+
directive omits fields) inline so the operator can spot-check before
|
|
128
|
+
pasting.
|
|
104
129
|
|
|
105
130
|
---
|
|
106
131
|
|
|
@@ -65,6 +65,7 @@ Resolve the metadata used by the frontmatter and the vault path:
|
|
|
65
65
|
|
|
66
66
|
- **Project name:** infer from conversation context
|
|
67
67
|
- **Session number:** from backend detection above
|
|
68
|
+
- **Session ID:** the session ID of the agent authoring this log, read from the `CLAUDE_CODE_SESSION_ID` environment variable (PowerShell: `$env:CLAUDE_CODE_SESSION_ID`). This UUID names the authoring agent's own transcript file (`<session-id>.jsonl`), so the saved report points back to the exact session that produced it. When the variable is unset, use the literal `unknown`.
|
|
68
69
|
- **Date:** today's date
|
|
69
70
|
- **Title:** a 2–5 word summary of the session's primary outcome. Examples: "Amazon Auth Migration", "Source Loading Fix", "PR 475 Convergence". Avoid generic titles like "Bug Fixes".
|
|
70
71
|
|
|
@@ -75,6 +76,7 @@ The frontmatter contract every session report carries (inside an HTML comment, a
|
|
|
75
76
|
type: session-report
|
|
76
77
|
project: [name]
|
|
77
78
|
session: [N]
|
|
79
|
+
session_id: [uuid]
|
|
78
80
|
date: [YYYY-MM-DD]
|
|
79
81
|
status: completed|in-progress|blocked
|
|
80
82
|
blocked: true|false
|
|
@@ -83,7 +85,7 @@ tags: [session, [project-tag], [topic-tags]]
|
|
|
83
85
|
-->
|
|
84
86
|
```
|
|
85
87
|
|
|
86
|
-
Every session report carries this metadata block verbatim so vault search and the tidy step in step 5 work. **Initial values for Step 2's Write:** substitute concrete values for every placeholder — for `vault_context_retrieved`, write the literal value `false` (the safe default before Step 3's vault-MCP-tool scan completes). Step 3 then Edits
|
|
88
|
+
Every session report carries this metadata block verbatim so vault search and the tidy step in step 5 work. **Initial values for Step 2's Write:** substitute concrete values for every placeholder — for `session_id`, write the value read from `CLAUDE_CODE_SESSION_ID` in step 1 (or `unknown` when the variable is unset); for `vault_context_retrieved`, write the literal value `false` (the safe default before Step 3's vault-MCP-tool scan completes). Step 3 then Edits `vault_context_retrieved` to `true` if any of the three vault MCP tools fired this session.
|
|
87
89
|
|
|
88
90
|
## Step 2: Compose the HTML via doc-gist's shape principles
|
|
89
91
|
|
|
@@ -191,6 +193,7 @@ The primary outcome comes from the session title resolved in step 1.
|
|
|
191
193
|
- [ ] HTML composed via doc-gist's shape principles (gallery-anchored)
|
|
192
194
|
- [ ] `<!-- @publish-as-gist -->` marker present somewhere in the HTML
|
|
193
195
|
- [ ] Frontmatter HTML comment present at top of `<body>`
|
|
196
|
+
- [ ] `session_id` frontmatter field set from `CLAUDE_CODE_SESSION_ID` (the authoring agent's own session), or `unknown` when the variable is unset
|
|
194
197
|
- [ ] Opening section answers "what shipped / why / impact" for a cold reader
|
|
195
198
|
- [ ] Self-contained HTML (no relative-path asset refs; avoid external dependencies)
|
|
196
199
|
- [ ] Auto-publish URLs captured from step 2 and step 3 (or HTML emitted to chat when step 2 Write failed)
|