claude-dev-env 2.7.1 → 2.9.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.
Files changed (127) hide show
  1. package/CLAUDE.md +7 -1
  2. package/_shared/CLAUDE.md +1 -0
  3. package/_shared/advisor/advisor-protocol.md +19 -9
  4. package/_shared/pr-loop/audit-contract.md +4 -4
  5. package/_shared/pr-loop/precatch-rubric.md +2 -2
  6. package/_shared/process-tree/CLAUDE.md +41 -0
  7. package/_shared/process-tree/scripts/config/process_tree_scripts_constants/__init__.py +1 -0
  8. package/_shared/process-tree/scripts/config/process_tree_scripts_constants/process_tree_kill_constants.py +27 -0
  9. package/_shared/process-tree/scripts/process_tree_kill.py +141 -0
  10. package/_shared/process-tree/scripts/pyproject.toml +16 -0
  11. package/_shared/process-tree/scripts/test_process_tree_kill.py +278 -0
  12. package/agents/clean-coder.md +9 -19
  13. package/agents/code-quality-agent.md +6 -5
  14. package/agents/deep-research.md +7 -24
  15. package/agents/docs-agent.md +1 -27
  16. package/agents/issue-tracker.md +1 -7
  17. package/agents/skill-writer-agent.md +1 -2
  18. package/agents/test_agent_frontmatter.py +335 -12
  19. package/docs/CODE_RULES.md +4 -2
  20. package/docs/references/CLAUDE.md +2 -2
  21. package/docs/references/advisor-tool.md +44 -6
  22. package/docs/references/team-advisor-skill.md +14 -8
  23. package/hooks/blocking/CLAUDE.md +2 -0
  24. package/hooks/blocking/fable_spawn_gate.py +187 -0
  25. package/hooks/blocking/piped_pytest_blocker.py +1223 -0
  26. package/hooks/blocking/plain_language_blocker.py +287 -15
  27. package/hooks/blocking/test_fable_spawn_gate.py +374 -0
  28. package/hooks/blocking/test_piped_pytest_blocker.py +587 -0
  29. package/hooks/blocking/test_plain_language_blocker.py +277 -2
  30. package/hooks/blocking/test_pre_tool_use_dispatcher.py +34 -2
  31. package/hooks/git-hooks/CLAUDE.md +2 -2
  32. package/hooks/git-hooks/git_hooks_constants/__init__.py +28 -0
  33. package/hooks/git-hooks/pre_push.py +343 -54
  34. package/hooks/git-hooks/test_pre_push.py +852 -6
  35. package/hooks/hooks.json +9 -19
  36. package/hooks/hooks_constants/CLAUDE.md +2 -0
  37. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -0
  38. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
  39. package/hooks/hooks_constants/fable_spawn_gate_constants.py +62 -0
  40. package/hooks/hooks_constants/piped_pytest_blocker_constants.py +360 -0
  41. package/hooks/hooks_constants/plain_language_blocker_constants.py +64 -1
  42. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -0
  43. package/hooks/hooks_constants/shell_command_segments.py +1 -1
  44. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -0
  45. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +27 -0
  46. package/hooks/hooks_constants/test_prose_metrics_parity.py +124 -0
  47. package/output-styles/CLAUDE.md +17 -0
  48. package/output-styles/caveman-agent.md +37 -0
  49. package/package.json +2 -1
  50. package/rules/CLAUDE.md +1 -0
  51. package/rules/ask-user-question-required.md +26 -0
  52. package/rules/claims-as-quotes.md +65 -0
  53. package/rules/code-standards.md +33 -7
  54. package/rules/eli11-replies.md +1 -1
  55. package/scripts/CLAUDE.md +3 -3
  56. package/scripts/_code_review_test_support.py +6 -0
  57. package/scripts/check.ps1 +18 -5
  58. package/scripts/claude_chain_runner.py +203 -31
  59. package/scripts/codec_forwarding_test_support.py +2 -0
  60. package/scripts/dev_env_scripts_constants/CLAUDE.md +4 -4
  61. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +38 -0
  62. package/scripts/dev_env_scripts_constants/code_review_constants.py +403 -2
  63. package/scripts/dev_env_scripts_constants/grok_run_ledger_constants.py +50 -0
  64. package/scripts/dev_env_scripts_constants/grok_worker_constants.py +132 -24
  65. package/scripts/grok_headless_runner.py +16 -83
  66. package/scripts/grok_patch_artifacts.py +123 -0
  67. package/scripts/grok_run_ledger.py +318 -0
  68. package/scripts/spawn_grok_batch.py +591 -10
  69. package/scripts/test_claude_chain_runner.py +358 -0
  70. package/scripts/test_grok_headless_runner.py +18 -63
  71. package/scripts/test_grok_patch_artifacts.py +82 -0
  72. package/scripts/test_grok_run_ledger.py +116 -0
  73. package/scripts/test_invoke_code_review.py +298 -0
  74. package/scripts/test_resolve_worker_spawn.py +6 -0
  75. package/scripts/test_spawn_grok_batch.py +396 -0
  76. package/scripts/tests/CLAUDE.md +1 -0
  77. package/scripts/tests/test_grok_worker_constants.py +59 -0
  78. package/skills/CLAUDE.md +4 -2
  79. package/skills/_shared/CLAUDE.md +37 -4
  80. package/skills/_shared/advisor/CLAUDE.md +9 -0
  81. package/skills/_shared/advisor/advisor-protocol.md +5 -0
  82. package/skills/_shared/advisor/scripts/README.md +9 -0
  83. package/skills/_shared/end-of-run-gotcha-recommendations.md +156 -0
  84. package/skills/_shared/pr-loop/CLAUDE.md +18 -1
  85. package/skills/_shared/pr-loop/audit-contract.md +5 -0
  86. package/skills/_shared/pr-loop/audit-reply-template.md +5 -0
  87. package/skills/_shared/pr-loop/code-rules-gate.md +5 -0
  88. package/skills/_shared/pr-loop/fix-protocol.md +5 -0
  89. package/skills/_shared/pr-loop/gh-payloads.md +5 -0
  90. package/skills/_shared/pr-loop/post-audit-thread-contract.md +5 -0
  91. package/skills/_shared/pr-loop/precatch-rubric.md +5 -0
  92. package/skills/_shared/pr-loop/scripts/CLAUDE.md +8 -1
  93. package/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +29 -0
  94. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +46 -0
  95. package/skills/_shared/pr-loop/state-schema.md +5 -0
  96. package/skills/_shared/pr-loop/worker-spawn.md +5 -0
  97. package/skills/autoconverge/workflow/converge.contract.test.mjs +105 -2
  98. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +34 -1
  99. package/skills/autoconverge/workflow/converge.mjs +66 -33
  100. package/skills/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +0 -4
  101. package/skills/codex-review/scripts/codex_usage_probe.py +20 -33
  102. package/skills/codex-review/scripts/run_codex_review.py +16 -64
  103. package/skills/codex-review/scripts/test_codex_usage_probe.py +46 -41
  104. package/skills/codex-review/scripts/test_run_codex_review.py +1 -33
  105. package/skills/e-code-review/SKILL.md +15 -9
  106. package/skills/e-code-review/reference/fix.md +29 -7
  107. package/skills/e-code-review/reference/loop.md +230 -14
  108. package/skills/e-code-review/reference/low.md +33 -15
  109. package/skills/e-code-review/reference/medium.md +55 -21
  110. package/skills/e-code-review/reference/runner-selection.md +40 -0
  111. package/skills/e-code-review/reference/xhigh.md +30 -12
  112. package/skills/e-code-review/scripts/e_code_review_scripts_constants/__init__.py +1 -0
  113. package/skills/e-code-review/scripts/e_code_review_scripts_constants/grok_code_review_constants.py +55 -0
  114. package/skills/e-code-review/scripts/grok_code_review.py +221 -0
  115. package/skills/e-code-review/scripts/test_grok_code_review.py +212 -0
  116. package/skills/fresh-branch/CLAUDE.md +5 -5
  117. package/skills/fresh-branch/SKILL.md +14 -6
  118. package/skills/fresh-branch/scripts/create_fresh_branch.py +122 -39
  119. package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +10 -3
  120. package/skills/fresh-branch/scripts/test_create_fresh_branch.py +251 -0
  121. package/skills/grok-spawn/SKILL.md +10 -0
  122. package/skills/orchestrator/SKILL.md +9 -1
  123. package/skills/orchestrator-refresh/SKILL.md +5 -1
  124. package/skills/task-build/reference/tool-routing.md +3 -0
  125. package/skills/team-advisor/SKILL.md +23 -41
  126. package/system-prompts/software-engineer.xml +6 -3
  127. package/skills/test_markdown_link_integrity.py +0 -107
@@ -0,0 +1,124 @@
1
+ """Parity checks across the duplicated prose-metric copies.
2
+
3
+ ``plain_language_blocker_constants`` and ``eli11_reply_enforcer_constants``
4
+ each carry their own copy of the metrics that read a reply's prose, so a
5
+ tuning landed in one copy alone drifts the two gates apart. These checks fail
6
+ loud on that drift::
7
+
8
+ COUNTABLE_WORD_PATTERN ok: byte-equal across both copies
9
+ table-row pattern ok: byte-equal across both copies
10
+ "- Run the migration" ok: both copies read a list marker
11
+ "1.5% of hosts still fail." ok: neither copy reads a list marker
12
+ "**1.** Run the migration" flag: the eli11 copy alone reads a marker
13
+
14
+ The list-marker copies hold two different shapes — one combined regex against
15
+ a bullet/numbered split — so they are pinned by the lines they agree on plus
16
+ the one line they read differently.
17
+
18
+ Row 2 of ``~/.claude/orchestrator-runs/falsify-first/parked-items.md`` carries
19
+ the shared home that retires these copies.
20
+ """
21
+
22
+ import pathlib
23
+ import re
24
+ import sys
25
+
26
+ _HOOKS_ROOT = pathlib.Path(__file__).resolve().parent.parent
27
+ if str(_HOOKS_ROOT) not in sys.path:
28
+ sys.path.insert(0, str(_HOOKS_ROOT))
29
+
30
+ from hooks_constants.eli11_reply_enforcer_constants import (
31
+ BULLET_LINE_PATTERN,
32
+ NUMBERED_STEP_PATTERN,
33
+ TABLE_ROW_PATTERN,
34
+ )
35
+ from hooks_constants.eli11_reply_enforcer_constants import (
36
+ COUNTABLE_WORD_PATTERN as ELI11_COUNTABLE_WORD_PATTERN,
37
+ )
38
+ from hooks_constants.plain_language_blocker_constants import ALL_CHAT_DETAIL_MARKERS
39
+ from hooks_constants.plain_language_blocker_constants import (
40
+ COUNTABLE_WORD_PATTERN as PLAIN_LANGUAGE_COUNTABLE_WORD_PATTERN,
41
+ )
42
+
43
+ _TABLE_ROW_MARKER_LABEL = "a table row"
44
+ _LIST_MARKER_LABEL = "a bullet or numbered list marker"
45
+ _BOLD_NUMBERED_STEP_LINE = "**1.** Run the migration"
46
+
47
+ _ALL_SHARED_LIST_MARKER_LINES = (
48
+ "- Run the migration",
49
+ "* Run the migration",
50
+ "+ Run the migration",
51
+ "1. Run the migration",
52
+ "2) Run the migration",
53
+ " - Run the migration",
54
+ " 1. Run the migration",
55
+ )
56
+
57
+ _ALL_NON_LIST_MARKER_LINES = (
58
+ "Run the migration",
59
+ "1.5% of hosts still fail.",
60
+ "|table|row|",
61
+ "-no space after the dash",
62
+ )
63
+
64
+
65
+ def _chat_detail_marker_named(marker_label: str) -> re.Pattern[str]:
66
+ """Return the plain-language chat-detail pattern carrying one label.
67
+
68
+ Args:
69
+ marker_label: The label the chat-detail marker table gives a pattern.
70
+
71
+ Returns:
72
+ The compiled pattern registered under that label.
73
+ """
74
+ for each_pattern, each_label in ALL_CHAT_DETAIL_MARKERS:
75
+ if each_label == marker_label:
76
+ return each_pattern
77
+ raise AssertionError(f"no chat-detail marker labeled {marker_label!r}")
78
+
79
+
80
+ def _eli11_copy_reads_a_list_marker(reply_line: str) -> bool:
81
+ """Report whether the eli11 bullet/numbered split reads a list marker.
82
+
83
+ Args:
84
+ reply_line: One line of reply text.
85
+
86
+ Returns:
87
+ True when either half of the split matches the line.
88
+ """
89
+ if BULLET_LINE_PATTERN.search(reply_line):
90
+ return True
91
+ return bool(NUMBERED_STEP_PATTERN.search(reply_line))
92
+
93
+
94
+ def test_countable_word_pattern_copies_stay_byte_equal() -> None:
95
+ assert (
96
+ PLAIN_LANGUAGE_COUNTABLE_WORD_PATTERN.pattern
97
+ == ELI11_COUNTABLE_WORD_PATTERN.pattern
98
+ )
99
+ assert (
100
+ PLAIN_LANGUAGE_COUNTABLE_WORD_PATTERN.flags
101
+ == ELI11_COUNTABLE_WORD_PATTERN.flags
102
+ )
103
+
104
+
105
+ def test_table_row_pattern_copies_stay_byte_equal() -> None:
106
+ plain_language_table_row = _chat_detail_marker_named(_TABLE_ROW_MARKER_LABEL)
107
+ assert plain_language_table_row.pattern == TABLE_ROW_PATTERN.pattern
108
+ assert plain_language_table_row.flags == TABLE_ROW_PATTERN.flags
109
+
110
+
111
+ def test_list_marker_copies_agree_on_every_shared_line() -> None:
112
+ combined_marker = _chat_detail_marker_named(_LIST_MARKER_LABEL)
113
+ for each_line in _ALL_SHARED_LIST_MARKER_LINES:
114
+ assert combined_marker.search(each_line)
115
+ assert _eli11_copy_reads_a_list_marker(each_line)
116
+ for each_line in _ALL_NON_LIST_MARKER_LINES:
117
+ assert not combined_marker.search(each_line)
118
+ assert not _eli11_copy_reads_a_list_marker(each_line)
119
+
120
+
121
+ def test_bold_numbered_step_reads_as_a_list_marker_in_the_eli11_copy_alone() -> None:
122
+ combined_marker = _chat_detail_marker_named(_LIST_MARKER_LABEL)
123
+ assert not combined_marker.search(_BOLD_NUMBERED_STEP_LINE)
124
+ assert _eli11_copy_reads_a_list_marker(_BOLD_NUMBERED_STEP_LINE)
@@ -0,0 +1,17 @@
1
+ # output-styles
2
+
3
+ Output-style instruction files installed into `~/.claude/output-styles/` by `bin/install.mjs`. Each file instructs an agent or session to respond in a specific voice or format.
4
+
5
+ ## Files
6
+
7
+ | File | Style | Effect |
8
+ |---|---|---|
9
+ | `caveman-agent.md` | Caveman Agent | Terse fragments, lead with answer, smallest artifact that solves the stated problem, question premise before building |
10
+
11
+ ## Format
12
+
13
+ Each file uses YAML frontmatter (`name`, `description`, optional `keep-coding-instructions`) followed by Markdown instructions. The `keep-coding-instructions: true` flag tells Claude Code to keep the session's coding rules even when this style is active.
14
+
15
+ ## Adding a style
16
+
17
+ Create a `.md` file with frontmatter and behavioral instructions, then run `bin/install.mjs` to copy it to `~/.claude/output-styles/`.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: Caveman Agent
3
+ description: Caveman voice + caveman work. Terse replies, minimum viable artifacts, pushback before build.
4
+ keep-coding-instructions: true
5
+ ---
6
+
7
+ Caveman voice. Caveman work.
8
+
9
+ ## Voice
10
+
11
+ Lead with answer. Drop articles, filler, hedging, preamble, recap.
12
+ Fragments OK. Pattern: `[thing] [action] [reason]. [next step].`
13
+ Keep code, paths, commands, errors, JSON unchanged.
14
+ Bullets/tables only when scan beats prose.
15
+
16
+ ## Work ethos
17
+
18
+ Smallest artifact that solves stated problem. Nothing more.
19
+ One file beats three. Functions beat classes. Concrete beats abstract.
20
+ No planning docs, no speculative tests, no future-proof params, no README unless asked.
21
+ Question premise before building — if existing tool covers it, say so and stop.
22
+
23
+ ## Pushback rule
24
+
25
+ Before any new file, ask:
26
+ - Does existing tool already do this? If yes → say so, stop.
27
+ - Is the scaffolding earning its keep right now? If no → drop it.
28
+ - One file or many? → one, unless many is forced.
29
+
30
+ ## Escape hatch
31
+
32
+ Normal language and normal care for:
33
+ - Safety, destructive ops, irreversible actions
34
+ - Money, credentials, production systems
35
+ - Genuine confusion risk
36
+
37
+ Caveman voice is for speed, not for hazards.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "2.7.1",
3
+ "version": "2.9.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,6 +16,7 @@
16
16
  "docs/",
17
17
  "commands/",
18
18
  "agents/",
19
+ "output-styles/",
19
20
  "skills/",
20
21
  "hooks/",
21
22
  "system-prompts/",
package/rules/CLAUDE.md CHANGED
@@ -15,6 +15,7 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. A rule withou
15
15
  | `anti-corollary-tests.md` | Tests must carry information: no corollary matrices over canonical reductions, no suite that only matches a dead-implementation default, stated mutation in the audit lane |
16
16
  | `ask-user-question-required.md` | Every user-directed question goes through the `AskUserQuestion` tool — no plain-text questions |
17
17
  | `bdd.md` | BDD discovery-driven development workflow and Example Mapping reference |
18
+ | `claims-as-quotes.md` | On agent reports, hand-offs, review verdicts, and PR or commit prose, a design-gating claim travels with its quoted lines and `path:line` reference; chat keeps research-mode compact citations; a claim without its quote is a lead to check |
18
19
  | `cleanup-temp-files.md` | Remove temporary files created during a task when the task is complete |
19
20
  | `code-standards.md` | Pointer to `CODE_RULES.md` as the single source of truth, including §8 (TDD) and §7 (right-sizing); BDD is the outer process and TDD the inner loop |
20
21
  | `confirm-implementation-forks.md` | Stop and ask when two or more workable implementation paths change the deliverable |
@@ -3,3 +3,29 @@
3
3
  Route every user-directed question through the `AskUserQuestion` tool — never a plain-text question in a response's final paragraph. Structure: concise `question`, `header` of 12 chars or fewer, 2-4 options (the UI adds the "Other" fallback), `multiSelect` only when choices genuinely combine.
4
4
 
5
5
  The `question_to_user_enforcer` Stop hook blocks a response whose final paragraph (after stripping code fences, inline code, and blockquotes) ends in a question mark or contains ask-phrases ("would you like", "should I", "let me know if", ...). Rhetorical questions answered in the same paragraph, and questions inside code or blockquotes, pass. `verify-before-asking` gates whether the question belongs to the user at all.
6
+
7
+ ## The question block stays lean
8
+
9
+ `AskUserQuestion` renders as one plain unformatted text block. Detail — plans, counts, tradeoffs, background — goes in chat text before the call. The block itself carries a lean question and short choices. When a choice needs formatting, an inline visualizer tool carries it.
10
+
11
+ The `plain_language_blocker` PreToolUse hook denies an `AskUserQuestion` call whose `question` text or whose `description` under any of the `options` carries chat detail:
12
+
13
+ | What the block carries | Cap |
14
+ |---|---|
15
+ | Fenced code block | none |
16
+ | Heading | none |
17
+ | Table row | none |
18
+ | Bullet or numbered list marker | none |
19
+ | Paragraphs | 1 — a blank line splits the block in two |
20
+ | `question` sentences | 2 |
21
+ | `question` words | 40 |
22
+ | `description` sentences | 1 |
23
+ | `description` words | 15 |
24
+
25
+ Two fields are counted, and each one gets the same treatment: the `question` text, and the `description` under every entry of `options`. The four structure markers apply to both. The paragraph cap applies to both. The sentence and word caps differ by field, as the table shows.
26
+
27
+ Structure is read at block level on the raw text: a marker counts when it opens a line, so a fence written on a single line still reads as a fence. Line endings fold to one spelling first, so a blank line counts whichever way it is written.
28
+
29
+ An inline code span — a path, a flag, a command the reader needs verbatim — weighs one word against either word cap on both fields, so a question naming `--dry-run` and a choice naming `C:\dev\gate.py` both pass. A span sits inside a line, so it never opens one with a marker.
30
+
31
+ A sentence closes on `.`, `!`, or `?` followed by a capitalized word or by the end of the text. A word is any whitespace-separated token carrying a letter or a digit. The denial names each cap the block broke and sends the detail back to chat text.
@@ -0,0 +1,65 @@
1
+ # Claims as Quotes
2
+
3
+ **When this applies:** Agent reports, hand-off artifacts, review verdicts, and PR or commit prose that state what existing code does. Always-on like `research-mode.md` for those durable surfaces — a commit message and a `gh` PR body have no shared path match. Chat replies use research-mode's compact citation only; the three-piece shape does not bind chat.
4
+
5
+ ## Rule
6
+
7
+ Under `research-mode.md`, a factual claim carries its source. This rule sets the shape a claim takes when it decides a design or gates an action: the `path:line` reference, the quoted lines, and the claim sentence travel together. The consumer reads those lines before acting on the claim.
8
+
9
+ In a chat reply, research-mode's compact citation stands — a linked source name or a `file:line` reference. The three-piece shape binds only agent reports, hand-off artifacts, review verdicts, and PR or commit prose.
10
+
11
+ Claims of this shape:
12
+
13
+ - "the helper already normalizes this"
14
+ - "the gate covers that path"
15
+ - "this caller handles the new shape"
16
+
17
+ On the surfaces the three-piece shape binds, each one settles a design question for whoever reads it and carries its quote; a claim without its quote decides nothing: it is a lead to check, not a fact to build on.
18
+
19
+ ## The failure shape
20
+
21
+ A paraphrase of code behavior, accepted without the source lines, ships a design premise nobody checked. The error surfaces when the built code meets the real behavior, with the design that rests on the premise already written.
22
+
23
+ ## What a claim carries
24
+
25
+ | Piece | Shape |
26
+ |---|---|
27
+ | Reference | `payments/refund.py:88-90` — the path with the line span |
28
+ | Quote | The lines word for word, in a fenced block |
29
+ | Claim | One sentence naming what those lines settle |
30
+
31
+ ## Examples
32
+
33
+ **A lead:** "`build_refund` already clamps the refund to the order total, so the new path needs no bound check."
34
+
35
+ **A fact:** the reference, the lines, and the claim together.
36
+
37
+ `payments/refund.py:88-90`
38
+
39
+ ```python
40
+ def build_refund(order, requested_amount):
41
+ refund_amount = min(requested_amount, order.total)
42
+ return Refund(order_id=order.id, amount=refund_amount)
43
+ ```
44
+
45
+ `build_refund` clamps to `order.total` on its one path, so a caller downstream of it needs no bound check.
46
+
47
+ ## What the consumer does
48
+
49
+ - Read the quoted lines before the sentence that summarizes them.
50
+ - On the surfaces the three-piece shape binds, treat a claim that arrives without its quote as a lead: pull the lines yourself, or ask the sender for them, before any design rests on it.
51
+ - When the quoted lines say something other than the claim, the lines win.
52
+
53
+ ## Enforcement
54
+
55
+ This rule binds as prose discipline: a reviewer applies it to the claims a report, a verdict, or a PR body makes about existing code. No hook backs it, because telling a design-deciding claim from background prose needs meaning a regex cannot read.
56
+
57
+ ## Sibling rules
58
+
59
+ | Rule | Role |
60
+ |---|---|
61
+ | `research-mode.md` | Names what counts as a citation and grounds a factual claim in word-for-word quotes |
62
+ | `hedging-claims.md` | Catches a hedge word standing in for evidence on a claim; this rule catches a claim missing its quote |
63
+ | `verify-runtime-state.md` | A verdict about what runs rests on a live probe from this session |
64
+ | `falsify-before-green.md` | A check's green counts once the check has been shown red |
65
+ | `measurement-denominators.md` | Every count names what it scanned |
@@ -1,13 +1,39 @@
1
1
  # Code Standards
2
2
 
3
- > **MANDATORY REFERENCE:** CODE_RULES.md - Load for ALL code generation.
4
- > This is the single source of truth for code standards. Non-negotiable.
3
+ > **Canonical policy:** repository-root [`AGENTS.md`](../../../AGENTS.md) the human and AI review contract for code quality.
4
+ > **Compact projection:** [`CODE_RULES.md`](../docs/CODE_RULES.md) validated summary for generation load.
5
+ > **Production enforcement:** `hooks/blocking/code_rules_enforcer.py` — hand-maintained Write/Edit gates; each mechanical rule carries a synchronization test.
5
6
 
6
- `CODE_RULES.md` (`~/.claude/docs/CODE_RULES.md`) is the compact reference for every standard: self-documenting names, centralized configuration, constant reuse, no magic literals, full words, complete type hints, required-vs-optional parameters, construction logic in the model, temporary-code `TODO:` markers, behavior-first component names, and TDD.
7
+ ## Policy surface map
7
8
 
8
- Two standards live there in full and nowhere else:
9
+ | Layer | Path | Role |
10
+ |---|---|---|
11
+ | Canonical | `AGENTS.md` (repo root) | Full review criteria for PR agents; BugBot sync source |
12
+ | Projection | `docs/CODE_RULES.md` | Compact always-load reference; must not diverge from AGENTS |
13
+ | Enforcer | `hooks/blocking/code_rules_enforcer.py` | Hand-maintained blockers; not generated from the docs |
14
+ | Session rules | `rules/*.md` | Runtime session policy (questions, tasks, shell) |
9
15
 
10
- - **TDD** CODE_RULES §8 is canonical: red, green, refactor, with no production code before a failing test.
11
- - **Right-sized engineering** — CODE_RULES §7 is canonical: functions over classes, concrete over abstract, an abstraction added at the commit that introduces its second concrete implementation.
16
+ Load `AGENTS.md` when reviewing a PR or resolving a policy conflict. Load `CODE_RULES.md` when generating code under the compact checklist. Prefer linking these refs over restating rules.
12
17
 
13
- BDD is the outer process and TDD is the inner loop: [`bdd.md`](bdd.md) discovers and formulates the behavior a feature needs, then each formulated behavior is built through the CODE_RULES §8 red-green-refactor cycle.
18
+ Two standards live in the canonical policy in full (and in the projection by name):
19
+
20
+ - **TDD** — CODE_RULES §8 / AGENTS Tests: red, green, refactor; no production code before a failing test.
21
+ - **Right-sized engineering** — CODE_RULES §7 / AGENTS Design: functions over classes; concrete over abstract; add an abstraction at the commit that introduces its second concrete implementation.
22
+
23
+ BDD is the outer process and TDD is the inner loop: [`bdd.md`](bdd.md) discovers and formulates the behavior a feature needs, then each formulated behavior is built through the TDD cycle.
24
+
25
+ ## Session policies (ref docs, not restated here)
26
+
27
+ | Concern | Rule file |
28
+ |---|---|
29
+ | Question routing | [`ask-user-question-required.md`](ask-user-question-required.md) |
30
+ | Task tracking / worker completion | [`workers-done-before-complete.md`](workers-done-before-complete.md) |
31
+ | Multi-step task list | skill `task-build` (see agents catalog) |
32
+
33
+ ## Synchronization
34
+
35
+ Mechanical enforcer coverage is checked by `tests/test_agents_policy_parity.py` and the existing `hooks/blocking/test_code_rules_enforcer*.py` suite. BugBot projection drift is checked with:
36
+
37
+ ```
38
+ python .github/scripts/sync_ai_rules.py --check
39
+ ```
@@ -20,7 +20,7 @@
20
20
 
21
21
  ## Rules
22
22
 
23
- - **One command per block** — a command the user runs goes in its own `bash`-tagged fenced block, so the Run button appears. That tag gives the user a Run button; [`shell-invocation-policy`](shell-invocation-policy.md) stays in charge of the agent's own Bash-tool calls, which run pwsh-only.
23
+ - **One command per block** — a command the user runs goes in its own `bash`-tagged fenced block, so the Run button appears. That tag gives the user a Run button; [`shell-invocation-policy`](shell-invocation.md) stays in charge of the agent's own Bash-tool calls, which run pwsh-only.
24
24
  - **One line per status** — each background-work update gets a single line.
25
25
  - **Cut findings first** — when a reply runs long, drop findings and keep the action steps.
26
26
  - **Skim test** — reading only the bold words tells the whole story.
package/scripts/CLAUDE.md CHANGED
@@ -6,13 +6,13 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
6
6
 
7
7
  | File | Purpose |
8
8
  |---|---|
9
- | `claude_chain_runner.py` | Runs a `claude` invocation through a usage-ranked fallback chain (`~/.claude/claude-chain.json`): probes weekly remaining once via `claude_chain_usage` / the usage-pause OAuth probe, tries the highest-remaining account first, and falls over to the next ranked binary only on a usage-limit failure; usable as an imported module (`run_claude`) or a CLI. Copy `claude-chain.example.json` to `~/.claude/claude-chain.json` and list your account binaries. Optional per-entry `credentials_path` names that account's OAuth credentials file for the usage probe |
9
+ | `claude_chain_runner.py` | Runs a `claude` invocation through a fallback chain (`~/.claude/claude-chain.json`) with `--routing-mode usage_ranked` (default: probe weekly remaining once via `claude_chain_usage` / the usage-pause OAuth probe, highest remaining first) or `ordered_account` (config list order; non-usage failures stop as `advisor_blocked`); falls over only on a usage-limit failure; returns `terminal_status` / optional `session_id` on the outcome; usable as an imported module (`run_claude`) or a CLI. Copy `claude-chain.example.json` to `~/.claude/claude-chain.json` and list your account binaries. Optional per-entry `credentials_path` names that account's OAuth credentials file for the usage probe |
10
10
  | `claude_chain_usage.py` | Reports remaining weekly usage for every account in `~/.claude/claude-chain.json` via the usage-pause OAuth probe; prints JSON (`accounts` with `weekly_remaining_percent` or null plus `error`); importable `report_chain_weekly_usage` and `rank_accounts_by_weekly_remaining` (highest remaining first, ties keep config order, unmeasurable last). The chain runner consumes this ranking for try order |
11
11
  | `gh_artifact_upload.py` | Uploads a file to a repo's durable `artifacts` prerelease under a timestamped asset name and prints the permanent download URL a GitHub post can link |
12
12
  | `grok_headless_runner.py` | Runs one worker as headless `grok`: builds argv with no turn cap (the timeout is the only bound), mints a unique leader socket, captures streams, refuses a timeout that is missing, below `MIN_WORKER_TIMEOUT_SECONDS`, or above the `MAXIMUM_WORKER_TIMEOUT_SECONDS` (5400) ceiling, kills the whole process tree on timeout with grace and retries the kill-and-drain round once, classifies ok/usage_limit/auth_failure/timeout/kill_failed/error; exports `require_timeout_within_bounds` so a dispatcher can apply the same bounds without launching; imported by `spawn_grok_batch.py` and `resolve_worker_spawn.py` |
13
13
  | `grok_worker_preflight.py` | Soft gate for the headless grok tier: binary on PATH, `grok models` auth, install manifest + role agents, opt-in cached live ping; non-zero exit is fallthrough, not failure |
14
14
  | `setup_project_paths.py` | One-time bootstrap: discovers git repos via `es.exe` (Everything) and writes `~/.claude/project-paths.json`; never hardcodes scan roots |
15
- | `spawn_grok_batch.py` | Launches a fleet of headless grok workers from a JSON batch spec: gates once through the preflight, refuses a spec whose `timeout_seconds` exceeds `MAXIMUM_WORKER_TIMEOUT_SECONDS` (5400) rather than clamping it, assembles each prompt from part files, staggers starts, runs each through `grok_headless_runner.py`, and emits one batch summary JSON |
15
+ | `spawn_grok_batch.py` | Launches a fleet of headless grok workers from a JSON batch spec: gates once through the preflight, refuses a spec whose `timeout_seconds` exceeds `MAXIMUM_WORKER_TIMEOUT_SECONDS` (5400) rather than clamping it, assembles each prompt from part files, optionally binds a unique worker advisor per role via the lead-supplied `advisor.launcher` (placeholder default in constants), injects `advisor_session_id`, requires the same session ENDORSE or bounded CORRECTION/PLAN then ENDORSE, classifies bind/verdict/timeout/missing-launcher failures as `advisor_blocked`, staggers starts, runs each through `grok_headless_runner.py`, and emits one batch summary JSON |
16
16
  | `sweep_empty_dirs.py` | Deletes empty directories older than a configurable age under a given root; runs once (`--once`) or in continuous-watch mode |
17
17
  | `sync_to_cursor.py` | Entry point for syncing Claude rules to Cursor `.mdc` files; delegates to the `sync_to_cursor/` package |
18
18
  | `resolve_worker_spawn.py` | Dispatches a worker role through grok then claude fallback tiers (preflight, headless grok, `claude_agent_required` handoff, optional claude headless); applies `require_timeout_within_bounds` before the preflight, so an out-of-bounds `--timeout-seconds` prints a `timeout_out_of_bounds` outcome and exits 3 on every tier; protocol: [`../_shared/pr-loop/worker-spawn.md`](../_shared/pr-loop/worker-spawn.md) |
@@ -33,7 +33,7 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
33
33
 
34
34
  | Entry | Description |
35
35
  |---|---|
36
- | `dev_env_scripts_constants/` | Named constants (`timing.py`) for scripts in this directory |
36
+ | `dev_env_scripts_constants/` | Named constants (`timing.py`, `grok_worker_constants.py`, …) for scripts in this directory, including worker-advisor placeholder launcher/model/effort, four verdict signals, correction cap, and advisor timeout |
37
37
  | `sync_to_cursor/` | Package that builds Cursor `.mdc` files from Claude rules and docs |
38
38
  | `tests/` | pytest suite for the Python scripts and Pester (`*.Tests.ps1`) suite for the PowerShell scripts in this directory |
39
39
 
@@ -27,6 +27,10 @@ if _SCRIPTS_DIRECTORY not in sys.path:
27
27
  import claude_chain_runner as chain_runner # noqa: E402
28
28
  import invoke_code_review as invoker # noqa: E402
29
29
  from claude_chain_runner import ChainAttempt, ChainInvocationOutcome # noqa: E402
30
+ from dev_env_scripts_constants.claude_chain_constants import ( # noqa: E402
31
+ TERMINAL_STATUS_CHAIN_EXHAUSTED,
32
+ TERMINAL_STATUS_SERVED,
33
+ )
30
34
  from dev_env_scripts_constants.code_review_constants import ( # noqa: E402
31
35
  CLI_SESSION_MODEL_FLAG,
32
36
  CODE_REVIEW_MODEL_ALIAS,
@@ -128,6 +132,7 @@ def claude_served(
128
132
  stdout=stdout,
129
133
  stderr="",
130
134
  attempts=(ChainAttempt(command=FIXTURE_SERVED_COMMAND, status="served"),),
135
+ terminal_status=TERMINAL_STATUS_SERVED,
131
136
  )
132
137
 
133
138
 
@@ -140,6 +145,7 @@ def claude_failed() -> ChainInvocationOutcome:
140
145
  attempts=(
141
146
  ChainAttempt(command=FIXTURE_SERVED_COMMAND, status="usage_limited"),
142
147
  ),
148
+ terminal_status=TERMINAL_STATUS_CHAIN_EXHAUSTED,
143
149
  )
144
150
 
145
151
 
package/scripts/check.ps1 CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env pwsh
2
2
  <#
3
3
  .SYNOPSIS
4
- One-shot quality gate — runs ruff, hooks mypy, pr-loop mypy, and the
5
- blocking pytest suite from a single entry point.
4
+ One-shot quality gate — runs ruff, hooks mypy, pr-loop mypy,
5
+ process-tree mypy, and the blocking pytest suite from a single entry point.
6
6
 
7
7
  .DESCRIPTION
8
8
  Resolves paths relative to $PSScriptRoot so the script works from any CWD
@@ -10,7 +10,8 @@
10
10
  and the installed runtime (~/.claude/scripts/check.ps1, after install.mjs
11
11
  propagates this file). Tools: ruff over hooks/, mypy over hooks blocking
12
12
  and validators, mypy-pr-loop over _shared/pr-loop/scripts production
13
- modules, and optional pytest over the blocking enforcer suite. Each tool
13
+ modules, mypy-process-tree over the shared process-tree kill helper and
14
+ its constants, and optional pytest over the blocking enforcer suite. Each tool
14
15
  runs sequentially; the first non-zero exit code is preserved as the
15
16
  script's exit code so CI/pre-commit can short-circuit on the first failure.
16
17
 
@@ -19,7 +20,7 @@
19
20
  static-analysis gates.
20
21
 
21
22
  .PARAMETER SkipMypy
22
- Skip both mypy runs (hooks mypy and mypy-pr-loop).
23
+ Skip every mypy run (hooks mypy, mypy-pr-loop, and mypy-process-tree).
23
24
 
24
25
  .PARAMETER SkipRuff
25
26
  Skip the ruff run.
@@ -27,7 +28,7 @@
27
28
  .OUTPUTS
28
29
  Per-tool status lines on stdout. Final summary line:
29
30
  CHECK: OK
30
- CHECK: FAILED tools=ruff,mypy,mypy-pr-loop,pytest
31
+ CHECK: FAILED tools=ruff,mypy,mypy-pr-loop,mypy-process-tree,pytest
31
32
  #>
32
33
  [CmdletBinding()]
33
34
  param(
@@ -41,6 +42,7 @@ $ErrorActionPreference = 'Stop'
41
42
  $hooksRoot = Resolve-Path (Join-Path $PSScriptRoot '..' 'hooks')
42
43
  $blockingRoot = Join-Path $hooksRoot 'blocking'
43
44
  $prLoopScriptsRoot = Resolve-Path (Join-Path $PSScriptRoot '..' '_shared' 'pr-loop' 'scripts')
45
+ $processTreeScriptsRoot = Resolve-Path (Join-Path $PSScriptRoot '..' '_shared' 'process-tree' 'scripts')
44
46
 
45
47
  $failedTools = @()
46
48
  $firstNonZeroExitCode = 0
@@ -108,6 +110,17 @@ if (-not $SkipMypy) {
108
110
  Pop-Location
109
111
  }
110
112
  }
113
+
114
+ Invoke-Tool -Label 'mypy-process-tree' -Action {
115
+ Push-Location $processTreeScriptsRoot
116
+ try {
117
+ mypy --config-file (Join-Path $processTreeScriptsRoot 'pyproject.toml') `
118
+ process_tree_kill.py `
119
+ config/process_tree_scripts_constants
120
+ } finally {
121
+ Pop-Location
122
+ }
123
+ }
111
124
  }
112
125
 
113
126
  if (-not $SkipTests) {