claude-dev-env 1.82.0 → 1.83.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 (67) hide show
  1. package/CLAUDE.md +16 -13
  2. package/_shared/pr-loop/scripts/CLAUDE.md +1 -0
  3. package/_shared/pr-loop/scripts/README.md +1 -0
  4. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -0
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviewer_availability_constants.py +12 -0
  6. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +0 -2
  7. package/_shared/pr-loop/scripts/reviewer_availability.py +182 -0
  8. package/_shared/pr-loop/scripts/terminology_sweep.py +9 -33
  9. package/_shared/pr-loop/scripts/tests/CLAUDE.md +2 -0
  10. package/_shared/pr-loop/scripts/tests/test_reviewer_availability.py +159 -0
  11. package/_shared/pr-loop/scripts/tests/test_reviewer_availability_constants.py +36 -0
  12. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +14 -4
  13. package/hooks/blocking/CLAUDE.md +2 -0
  14. package/hooks/blocking/code_rules_constants_config.py +159 -1
  15. package/hooks/blocking/code_rules_docstrings.py +312 -9
  16. package/hooks/blocking/code_rules_enforcer.py +29 -0
  17. package/hooks/blocking/code_rules_imports_logging.py +867 -1
  18. package/hooks/blocking/code_rules_naming_collection.py +141 -0
  19. package/hooks/blocking/code_rules_string_magic.py +68 -0
  20. package/hooks/blocking/pre_tool_use_dispatcher.py +3 -3
  21. package/hooks/blocking/reviewer_spawn_gate.py +182 -0
  22. package/hooks/blocking/stale_comment_reference_blocker.py +267 -0
  23. package/hooks/blocking/state_description_blocker.py +96 -5
  24. package/hooks/blocking/test_code_rules_config_duplicate_path_anchor.py +132 -0
  25. package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +2 -0
  26. package/hooks/blocking/test_code_rules_enforcer_docstring_delegation_summary.py +385 -0
  27. package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +67 -0
  28. package/hooks/blocking/test_code_rules_enforcer_module_docstring_roster.py +40 -0
  29. package/hooks/blocking/test_code_rules_enforcer_naive_datetime.py +213 -0
  30. package/hooks/blocking/test_code_rules_enforcer_referenced_underscore_loop.py +169 -0
  31. package/hooks/blocking/test_code_rules_js_bare_flag_return_directive.py +266 -0
  32. package/hooks/blocking/test_code_rules_js_sibling_return_object_key_drift.py +490 -0
  33. package/hooks/blocking/test_code_rules_logging_adjacent_literals.py +171 -0
  34. package/hooks/blocking/test_pre_tool_use_dispatcher.py +9 -3
  35. package/hooks/blocking/test_reviewer_spawn_gate.py +230 -0
  36. package/hooks/blocking/test_stale_comment_reference_blocker.py +236 -0
  37. package/hooks/blocking/test_state_description_blocker.py +135 -0
  38. package/hooks/hooks.json +5 -0
  39. package/hooks/hooks_constants/CLAUDE.md +3 -1
  40. package/hooks/hooks_constants/blocking_check_limits.py +43 -0
  41. package/hooks/hooks_constants/code_rules_enforcer_constants.py +41 -0
  42. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
  43. package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +41 -0
  44. package/hooks/hooks_constants/stale_comment_reference_blocker_constants.py +76 -0
  45. package/hooks/hooks_constants/state_description_blocker_constants.py +8 -0
  46. package/package.json +1 -1
  47. package/rules/CLAUDE.md +4 -1
  48. package/rules/claude-md-orphan-file.md +5 -0
  49. package/rules/docstring-prose-matches-implementation.md +10 -1
  50. package/rules/env-var-table-code-drift.md +5 -0
  51. package/rules/es-exe-file-search.md +17 -0
  52. package/rules/no-historical-clutter.md +12 -1
  53. package/rules/orphan-css-class.md +5 -0
  54. package/rules/package-inventory-stale-entry.md +10 -0
  55. package/rules/paired-test-coverage.md +5 -0
  56. package/rules/plain-illustrative-docstrings.md +5 -0
  57. package/rules/verify-before-asking.md +7 -0
  58. package/rules/verify-runtime-state.md +40 -0
  59. package/rules/windows-filesystem-safe.md +8 -0
  60. package/rules/workers-done-before-complete.md +33 -0
  61. package/rules/workflow-substitution-slots.md +5 -0
  62. package/skills/CLAUDE.md +1 -1
  63. package/skills/autoconverge/SKILL.md +10 -4
  64. package/skills/autoconverge/workflow/converge.contract.test.mjs +69 -0
  65. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +54 -18
  66. package/skills/autoconverge/workflow/converge.mjs +97 -33
  67. package/skills/everything-search/SKILL.md +5 -0
@@ -28,7 +28,20 @@ MAX_THIN_WRAPPER_ISSUES: int = 1
28
28
  MAX_ZERO_PAYLOAD_ALIAS_ISSUES: int = 3
29
29
  MAX_LOGGING_FSTRING_ISSUES: int = 3
30
30
  MAX_LOGGING_PRINTF_TOKEN_ISSUES: int = 3
31
+ MAX_LOGGING_ADJACENT_LITERAL_ISSUES: int = 3
32
+ MAX_CONFIG_DUPLICATE_PATH_ANCHOR_ISSUES: int = 3
31
33
  MAX_WINDOWS_API_NONE_ISSUES: int = 3
34
+ MAX_NAIVE_DATETIME_ISSUES: int = 3
35
+ DATETIME_CLASS_ATTRIBUTE_NAME: str = "datetime"
36
+ NAIVE_DATETIME_TIMEZONE_KEYWORD: str = "tz"
37
+ NAIVE_DATETIME_UTCNOW_CONSTRUCTOR: str = "utcnow"
38
+ NAIVE_DATETIME_UTCFROMTIMESTAMP_CONSTRUCTOR: str = "utcfromtimestamp"
39
+ NAIVE_DATETIME_FROMTIMESTAMP_CONSTRUCTOR: str = "fromtimestamp"
40
+ FROMTIMESTAMP_POSITIONAL_TIMEZONE_ARGUMENT_COUNT: int = 2
41
+ ALL_ALWAYS_NAIVE_DATETIME_CONSTRUCTORS: tuple[str, ...] = (
42
+ NAIVE_DATETIME_UTCNOW_CONSTRUCTOR,
43
+ NAIVE_DATETIME_UTCFROMTIMESTAMP_CONSTRUCTOR,
44
+ )
32
45
  MAX_E2E_TEST_NAMING_ISSUES: int = 3
33
46
  MAX_IMPORT_BLOCK_SORT_ISSUES: int = 1
34
47
  IMPORT_BLOCK_SORT_RUFF_TIMEOUT_SECONDS: int = 15
@@ -48,6 +61,11 @@ ALL_IMPORT_BLOCK_SORT_RUFF_COMMAND_PREFIX: tuple[str, ...] = (
48
61
  )
49
62
  MAX_JS_RESUME_TASK_ENUMERATION_ISSUES: int = 5
50
63
  MAX_JS_RETURNS_OBJECT_SCHEMALESS_ISSUES: int = 5
64
+ MAX_JS_SIBLING_RETURN_OBJECT_KEY_DRIFT_ISSUES: int = 5
65
+ MINIMUM_SIBLING_RETURN_OBJECT_KEYS: int = 2
66
+ SIBLING_RETURN_OBJECT_EXACT_MISSING_KEY_COUNT: int = 1
67
+ SIBLING_RETURN_OBJECT_SINGLE_AGREED_MISSING_KEY_COUNT: int = 1
68
+ MAX_JS_BARE_FLAG_RETURN_DIRECTIVE_ISSUES: int = 5
51
69
  MINIMUM_RESUME_TASK_ENUMERATION_ITEMS: int = 2
52
70
  DOCSTRING_TRIVIAL_FUNCTION_BODY_LINE_LIMIT: int = 3
53
71
  MAX_DOCSTRING_FALLBACK_BRANCH_ISSUES: int = 3
@@ -59,6 +77,7 @@ MAX_STALE_TEST_NAME_TARGET_ISSUES: int = 3
59
77
  STALE_TEST_NAME_MINIMUM_SHARED_TOKEN_COUNT: int = 2
60
78
  MAX_MODULE_DOCSTRING_CHECK_ROSTER_ISSUES: int = 5
61
79
  MINIMUM_PUBLIC_CHECKS_FOR_MODULE_DOCSTRING_ROSTER: int = 2
80
+ MINIMUM_SIBLING_OCCURRENCES_FOR_SHARED_TOKEN: int = 2
62
81
  MAX_DOCSTRING_TUPLE_ENUMERATION_ISSUES: int = 5
63
82
  MINIMUM_TUPLE_MEMBERS_FOR_DOCSTRING_ENUMERATION: int = 2
64
83
  MAX_DOCSTRING_MARK_GLYPH_ENUMERATION_ISSUES: int = 5
@@ -290,6 +309,30 @@ ALL_TEST_INDICATING_ENVIRONMENT_VARIABLE_NAMES: frozenset[str] = frozenset(
290
309
  }
291
310
  )
292
311
 
312
+ MAX_DOCSTRING_DELEGATION_ENUMERATION_ISSUES: int = 5
313
+ MINIMUM_DELEGATION_ENUMERATION_ITEMS: int = 2
314
+ NEIGHBOR_SCAN_FILE_LIMIT: int = 40
315
+ POINTER_TO_DELEGATE_PATTERN: re.Pattern[str] = re.compile(
316
+ r"full doc(?:umentation)?\s+on\s+`{1,2}([A-Za-z_][A-Za-z0-9_]*)`{1,2}",
317
+ re.IGNORECASE,
318
+ )
319
+ TOKEN_WORD_PATTERN: re.Pattern[str] = re.compile(r"[A-Za-z][A-Za-z0-9]{2,}")
320
+ ALL_DELEGATION_ENUMERATION_STOP_TOKENS: frozenset[str] = frozenset(
321
+ {
322
+ "the",
323
+ "and",
324
+ "then",
325
+ "edit",
326
+ "edits",
327
+ "apply",
328
+ "applies",
329
+ "run",
330
+ "runs",
331
+ "step",
332
+ "steps",
333
+ }
334
+ )
335
+
293
336
  MAX_MODULE_DOCSTRING_DATA_SCHEMA_SCOPE_ISSUES: int = 1
294
337
  MODULE_DOCSTRING_DATA_SCHEMA_CONSTANT_SAMPLE_LIMIT: int = 6
295
338
  ALL_USER_FACING_TEXT_SCOPE_DOCSTRING_PHRASES: tuple[str, ...] = (
@@ -185,7 +185,18 @@ LOGGING_FSTRING_PATTERN = re.compile(
185
185
  LOGGING_PRINTF_TOKEN_PATTERN: re.Pattern[str] = re.compile(
186
186
  r"(?<!%)%[#0\- +]?[0-9.*]*[sdrixfgeEcoX](?![a-zA-Z])"
187
187
  )
188
+ ADJACENT_STRING_LITERAL_PATTERN: re.Pattern[str] = re.compile(
189
+ r'(?<!["\'])[rRbBfFuU]{0,2}(?:"(?:[^"\\\n]|\\.)*"|\'(?:[^\'\\\n]|\\.)*\')'
190
+ r'\s*[rRbBfFuU]{0,2}(?:"(?:[^"\\\n]|\\.)*"|\'(?:[^\'\\\n]|\\.)*\')(?!["\'])'
191
+ )
188
192
  MINIMUM_FORMAT_LOGGER_ARGUMENT_COUNT = 2
193
+ ALL_LOGGING_CALL_METHOD_NAMES: frozenset[str] = frozenset(
194
+ {"debug", "info", "warning", "error", "critical", "exception"}
195
+ )
196
+ LOGGING_HELPER_FUNCTION_NAME_PATTERN: re.Pattern[str] = re.compile(
197
+ r"^log_(?:debug|info|warning|error|critical|exception)$"
198
+ )
199
+ LOGGING_RECEIVER_NAME_PATTERN: re.Pattern[str] = re.compile(r"^_?(?:logger|logging|log)$")
189
200
  SPAWN_AGENT_WITH_JSDOC_PATTERN: re.Pattern[str] = re.compile(
190
201
  r"/\*\*(?P<jsdoc>(?:(?!\*/).)*?)\*/\s*"
191
202
  r"(?:async\s+)?function\s+spawn(?P<role>\w+?)Agent\s*\(",
@@ -233,9 +244,39 @@ JSDOC_RETURNS_STRUCTURED_OBJECT_PROMISE_PATTERN: re.Pattern[str] = re.compile(
233
244
  RETURN_CALL_OPENING_PARENTHESIS_PATTERN: re.Pattern[str] = re.compile(
234
245
  r"\breturn\s+(?:await\s+)?(?P<callee>\w+)\s*\("
235
246
  )
247
+ BARE_FLAG_CONTRACT_PATTERN: re.Pattern[str] = re.compile(
248
+ r"never a bare (?P<flag>\w+) flag", re.IGNORECASE
249
+ )
250
+ BARE_FLAG_RETURN_DIRECTIVE_PATTERN: re.Pattern[str] = re.compile(
251
+ r"\breturn\s+(?P<flag>\w+)\s*:\s*(?:true|false)\b", re.IGNORECASE
252
+ )
236
253
  SCHEMA_OPTIONS_PROPERTY_KEY_PATTERN: re.Pattern[str] = re.compile(
237
254
  r"(?<![A-Za-z0-9_])schema\s*:"
238
255
  )
256
+ RETURN_OBJECT_LITERAL_OPENING_PATTERN: re.Pattern[str] = re.compile(r"\breturn\s*\{")
257
+ ARROW_CONCISE_BODY_OBJECT_LITERAL_OPENING_PATTERN: re.Pattern[str] = re.compile(
258
+ r"=>\s*\(\s*\{"
259
+ )
260
+ JS_OBJECT_KEY_IDENTIFIER_PATTERN: re.Pattern[str] = re.compile(r"[A-Za-z_$][\w$]*")
261
+ JS_OBJECT_METHOD_SHORTHAND_KEY_PATTERN: re.Pattern[str] = re.compile(
262
+ r"\A([A-Za-z_$][\w$]*)\s*\("
263
+ )
264
+ ALL_JAVASCRIPT_CONTROL_FLOW_BLOCK_KEYWORDS: frozenset[str] = frozenset(
265
+ {"if", "for", "await", "while", "switch", "catch", "with"}
266
+ )
267
+ ALL_JAVASCRIPT_PARENTHESIS_FREE_BLOCK_KEYWORDS: frozenset[str] = frozenset(
268
+ {"else", "do", "try", "finally"}
269
+ )
270
+ ALL_JAVASCRIPT_BRACKET_OPENERS: frozenset[str] = frozenset({"(", "[", "{"})
271
+ ALL_JAVASCRIPT_BRACKET_CLOSERS: frozenset[str] = frozenset({")", "]", "}"})
272
+ ALL_JAVASCRIPT_IDENTIFIER_EXTRA_CHARACTERS: frozenset[str] = frozenset({"_", "$"})
273
+ ALL_JAVASCRIPT_RETURN_TYPE_TERMINATORS: frozenset[str] = frozenset({"}", ">", "]"})
274
+ JAVASCRIPT_ARROW_TOKEN_LENGTH: int = 2
275
+ ALL_JAVASCRIPT_BARE_RETURN_TYPE_EXTRA_CHARACTERS: frozenset[str] = frozenset(
276
+ {"_", "$", ".", "|", "&", "?"}
277
+ )
278
+ JAVASCRIPT_OBJECT_SPREAD_PREFIX: str = "..."
279
+ JAVASCRIPT_MODULE_SCOPE_SENTINEL: int = -1
239
280
  ALL_BUILTIN_DICT_METHOD_NAMES: frozenset[str] = frozenset({
240
281
  "get", "items", "keys", "values", "update", "pop",
241
282
  "setdefault", "copy", "clear",
@@ -105,6 +105,10 @@ ALL_HOSTED_HOOK_ENTRIES: tuple[HostedHookEntry, ...] = (
105
105
  applicable_tool_names=ALL_WRITE_AND_EDIT_TOOL_NAMES,
106
106
  native_module_name=STATE_DESCRIPTION_BLOCKER_MODULE_NAME,
107
107
  ),
108
+ HostedHookEntry(
109
+ script_relative_path="blocking/stale_comment_reference_blocker.py",
110
+ applicable_tool_names=frozenset({EDIT_TOOL_NAME}),
111
+ ),
108
112
  HostedHookEntry(
109
113
  script_relative_path="blocking/subprocess_budget_completeness.py",
110
114
  applicable_tool_names=ALL_WRITE_AND_EDIT_TOOL_NAMES,
@@ -0,0 +1,41 @@
1
+ """Configuration constants for the reviewer_spawn_gate PreToolUse hook."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from pathlib import Path
7
+
8
+ BASH_TOOL_NAME: str = "Bash"
9
+
10
+ GATE_SENTINEL_MARKER: str = "CLAUDE_REVIEWER_GATE=autoconverge"
11
+
12
+ COPILOT_REVIEWER_TOKEN: str = "copilot"
13
+ BUGBOT_REVIEWER_TOKEN: str = "bugbot"
14
+
15
+ COPILOT_REVIEWER_LABEL: str = "GitHub Copilot"
16
+ BUGBOT_REVIEWER_LABEL: str = "Cursor Bugbot"
17
+
18
+ ALL_COPILOT_TRIGGER_MARKERS: tuple[str, ...] = (
19
+ "requested_reviewers",
20
+ "copilot-pull-request-reviewer[bot]",
21
+ )
22
+
23
+ BUGBOT_TRIGGER_SCRIPT_MARKER: str = "post_fix_reply.py"
24
+ BUGBOT_RUN_BODY_PATTERN: re.Pattern[str] = re.compile(
25
+ r'--body\s+["\']bugbot run["\']', re.IGNORECASE
26
+ )
27
+
28
+ AVAILABILITY_SCRIPT_RELATIVE_PATH: Path = (
29
+ Path("_shared") / "pr-loop" / "scripts" / "reviewer_availability.py"
30
+ )
31
+ AVAILABILITY_SCRIPT_PATH_ENV_VAR_NAME: str = "REVIEWER_SPAWN_GATE_AVAILABILITY_SCRIPT_PATH"
32
+ AVAILABILITY_SCRIPT_TIMEOUT_SECONDS: int = 15
33
+ AVAILABILITY_REVIEWER_FLAG: str = "--reviewer"
34
+ AVAILABILITY_DOWN_EXIT_CODE: int = 3
35
+
36
+ DENY_REASON_TEMPLATE: str = (
37
+ "BLOCKED [reviewer-spawn-gate]: {reviewer_label} is down or out of quota "
38
+ "this run. Skip requesting {reviewer_label} on this trigger — "
39
+ "autoconverge requests it again once the availability check reports it "
40
+ "back.\n\nAvailability check output: {availability_detail}"
41
+ )
@@ -0,0 +1,76 @@
1
+ """Configuration constants for the PreToolUse hook stale_comment_reference_blocker."""
2
+
3
+ from re import Pattern, compile
4
+
5
+ COMMENT_IDENTIFIER_PATTERN: Pattern[str] = compile(r"[A-Za-z_][A-Za-z0-9_]{2,}")
6
+
7
+ ALL_COMMENT_STOPWORDS: frozenset[str] = frozenset(
8
+ {
9
+ "the",
10
+ "and",
11
+ "for",
12
+ "not",
13
+ "with",
14
+ "from",
15
+ "into",
16
+ "onto",
17
+ "out",
18
+ "off",
19
+ "this",
20
+ "that",
21
+ "these",
22
+ "those",
23
+ "each",
24
+ "all",
25
+ "any",
26
+ "are",
27
+ "was",
28
+ "were",
29
+ "has",
30
+ "have",
31
+ "had",
32
+ "its",
33
+ "use",
34
+ "uses",
35
+ "used",
36
+ "using",
37
+ "when",
38
+ "then",
39
+ "than",
40
+ "before",
41
+ "after",
42
+ "only",
43
+ "also",
44
+ "but",
45
+ "per",
46
+ "via",
47
+ "one",
48
+ "two",
49
+ "new",
50
+ "old",
51
+ "now",
52
+ }
53
+ )
54
+
55
+ PYTHON_FILE_SUFFIX: str = ".py"
56
+
57
+ COMMENT_LINE_PREFIX: str = "#"
58
+
59
+ STALE_COMMENT_DENY_TEMPLATE: str = (
60
+ "The comment above the changed line in {file_path} names "
61
+ "'{orphaned_name}', which this edit removes from the line below. "
62
+ "The comment left in place reads: {contradicted_comment}. "
63
+ "Update or remove the comment in the same edit."
64
+ )
65
+
66
+ STALE_COMMENT_ADDITIONAL_CONTEXT: str = (
67
+ "A standalone comment directly above an edited line describes that "
68
+ "line. When the edit drops a name the comment carries, rewrite the "
69
+ "comment to describe the rewritten line, or delete the comment, inside "
70
+ "the same Edit call."
71
+ )
72
+
73
+ STALE_COMMENT_SYSTEM_MESSAGE: str = (
74
+ "Agent edited a code line without updating the comment above it that "
75
+ "names what the edit removed"
76
+ )
@@ -41,6 +41,14 @@ ALL_COMMENT_TRANSITION_PATTERNS: list[Pattern[str]] = [
41
41
 
42
42
  CODE_FENCE_PATTERN: Pattern[str] = compile(r"```[\s\S]*?```")
43
43
  INLINE_CODE_PATTERN: Pattern[str] = compile(r"``[^`]+``|`[^`]+`")
44
+ DOUBLE_QUOTED_SPAN_PATTERN: Pattern[str] = compile(r'"[^"\n]*"')
45
+ TRIPLE_QUOTED_BLOCK_PATTERN: Pattern[str] = compile(
46
+ r'"""([\s\S]*?)"""|\'\'\'([\s\S]*?)\'\'\''
47
+ )
48
+
49
+ PYTHON_EXTENSION: str = ".py"
50
+
51
+ ALL_DEFINITION_HEADER_PREFIXES: tuple[str, ...] = ("def ", "async def ", "class ")
44
52
 
45
53
  ALL_MARKDOWN_EXTENSIONS: frozenset[str] = frozenset(
46
54
  {".md", ".mdx", ".markdown", ".rmd"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "1.82.0",
3
+ "version": "1.83.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
package/rules/CLAUDE.md CHANGED
@@ -28,6 +28,7 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. Claude Code l
28
28
  | `no-historical-clutter.md` | Documentation describes current state only; no historical or transitional language |
29
29
  | `no-inline-destructive-literals.md` | No destructive-command literals in Bash tool command strings, even as data |
30
30
  | `env-var-table-code-drift.md` | Every env-var summary table row in a `.md` file names a code file whose source references the variable |
31
+ | `es-exe-file-search.md` | File search on Windows routes through the `es.exe` CLI with a scoped query; the Everything HTTP server stays off |
31
32
  | `orphan-css-class.md` | Every `class="..."` attribute in Python-generated markup has a matching selector in the `<style>` block |
32
33
  | `package-inventory-stale-entry.md` | A new production code file added to a directory carries an entry in that directory's `README.md`/`CLAUDE.md` file inventory |
33
34
  | `paired-test-coverage.md` | A public function omitted by a module's established paired test suite must get a behavioral test |
@@ -42,8 +43,10 @@ Rule files installed into `~/.claude/rules/` by `bin/install.mjs`. Claude Code l
42
43
  | `tdd.md` | Test-driven development: red → green → refactor, no production code before a failing test |
43
44
  | `testing.md` | Test quality and infrastructure standards |
44
45
  | `vault-context.md` | Search Obsidian vault for prior sessions and decisions before substantive project work |
45
- | `verify-before-asking.md` | Answer questions by inspecting files or running tools before asking the user |
46
+ | `verify-before-asking.md` | Answer questions by inspecting files or running tools before asking; recalled facts expire until re-checked this session |
47
+ | `verify-runtime-state.md` | A "component is fine / not at fault" verdict rests on a live probe this session, never code reading or prior-session memory |
46
48
  | `windows-filesystem-safe.md` | Use safe `rmtree` patterns on Windows; `mkdirSync` with `recursive: true` on possibly-existing paths |
49
+ | `workers-done-before-complete.md` | A task reaches `completed` only when every spawned worker has finished and its results are merged into run state |
47
50
  | `workflow-substitution-slots.md` | Per-iteration values in `.workflow.js` templates use angle-bracket slots |
48
51
 
49
52
  ## Hook enforcement
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - "**/CLAUDE.md"
4
+ ---
5
+
1
6
  # Orphan File Reference in a Per-Directory CLAUDE.md
2
7
 
3
8
  **When this applies:** Any Write, Edit, or MultiEdit to a file named `CLAUDE.md` that lists files in a markdown table whose first column names each file in backticks, or that shows run commands invoking those files inside fenced code blocks.
@@ -1,3 +1,9 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ - "**/*.md"
5
+ ---
6
+
1
7
  # Docstring Prose Matches Implementation
2
8
 
3
9
  **When this applies:** Any Write or Edit to a public function, method, class, or module whose docstring prose makes an enumerable claim about behavior — a list of inputs the code handles, the conditions it treats as a match, the cases it skips, or the order of its steps. It applies equally to a skill's companion `SKILL.md` (or any sibling `.md`) that describes a producer the skill's `scripts/` carry out: a doc sentence that claims a produced artifact's ordering or content is the prose this rule governs, and it tracks the producer function's own docstring and body.
@@ -6,7 +12,7 @@
6
12
 
7
13
  When a docstring enumerates the behaviors a body applies, the enumeration covers every behavior the body applies. A reader trusts the list to be complete: an item the code applies but the prose omits is a silent gap that misleads every future reader and reviewer.
8
14
 
9
- The gate validator `check_docstring_args_match_signature` covers the `Args:` section parameter names. Ten more gate validators each cover one deterministic slice of the free-form prose. `check_docstring_names_absent_type_checking_gate` covers a module or function docstring that names a `TYPE_CHECKING` gate-detection step, or a `type-checking-gate` helper family, while no identifier in the module's code carries the `type_checking` marker — the drift where the prose points a reader at a gate the body never performs; drop the `TYPE_CHECKING` gate wording, or add the detection the prose describes. `check_docstring_length_constant_superlative_vs_exact_gate` covers a length-constant module whose docstring describes an integer `*_LENGTH` constant with a superlative or range word (`the longest color string the swatch accepts`) while the only code consuming the constant compares `len(...)` against it with `==`/`!=` — an exact-length gate that rejects every other length — and never with an ordered operator; the check scans the constant module's package tree (its own directory, or the parent package when the module sits in a `config/` subdirectory), so the mismatching consumer may sit in a sibling module. `check_docstring_fallback_branch_coverage` covers a summary that scopes a fallback to a single condition (`only when`, `falls back to ... when`) while the body routes to that same fallback call from two or more distinct early-return guards. `check_class_docstring_names_public_methods` covers a class whose docstring is a single summary line while the class exposes two or more public methods whose names the summary never spells out — the drift where a one-line class summary keeps naming its first feature after the class grows a second public entry point. `check_docstring_no_consumer_claim` covers a producer docstring asserting that no consumer reads its output yet (`producer-only artifact`, `no submission-run consumer reads it yet`) — a transitional claim that drifts the moment a reader lands and contradicts any companion `SKILL.md` that documents the consumer; this is the deterministic slice of the O8 companion-doc producer/consumer drift below. `check_docstring_returns_plural_cardinality` covers a `Returns:` clause that names a dict-key prefix family with a plural noun (`the sheen stops`) while the returned dict literal holds exactly one key in that family (`sheen_mid`) — the drift where a single-key family carries a plural noun, so the prose claims a cardinality of two or more that the dict does not hold. `check_docstring_args_single_line_scope_vs_span` covers an `Args:` entry whose prose scopes a finding to a single named line (`only when its block-anchor line is among the changed lines`) while the body builds a `range(...)` span over the finding's source lines and scopes it through a span-intersection scoper — the drift where the Args entry claims a narrower single-line scope than the span-intersection body applies, so an edit touching any non-anchor line of the span still blocks. `check_docstring_cardinal_count_matches_constant_family` covers a docstring that states a cardinal count of an outcome family (`Covers the four outcome branches: ...`) and lists those members, while the module references more members of the same `UPPER_SNAKE` constant family than the count names (`OUTCOME_OFFENDER_UNREADABLE` is imported and exercised, yet the summary stops at four) — the drift where a summary keeps the old count after the code grows another branch; this gate runs on test modules as well as production modules. `check_docstring_raises_unraisable_largezipfile` covers a `Raises:` clause that names `zipfile.LargeZipFile` while the function opens its `zipfile.ZipFile` writer in a write mode (`w`/`a`/`x`) with `allowZip64` left at its default of True — `zipfile` raises `LargeZipFile` only when an entry needs ZIP64 and `allowZip64` is False, so a writer that allows ZIP64 documents an exception the body cannot produce. `check_docstring_no_network_claim_with_metadata_access` covers a function docstring promising a code path returns `without touching the network` (or a sibling no-network phrase) while the body calls a path-metadata method (`is_file`, `is_dir`, `exists`, `stat`, `lstat`) — on a network share each metadata call is a round-trip over the wire, so a cache-hit path the docstring swore avoids the network still pays a stat on every call; reword the claim to state the path is stat-checked on every call, or short-circuit to the cached path before the share is touched. The remaining free-form prose — `"a field counts as read when ..."`, `"resolves to shared temp only"`, `"strip ceremony, then drop blockquotes"`, and the broader module-responsibility paragraph outside the user-facing-text-scope slice the checklist below names — has no signature, method roster, or single structural shape to compare against, so the gate cannot catch its drift. This rule is the judgment standard for that prose; the audit lane below is the enforcement for everything outside the eleven gated slices.
15
+ The gate validator `check_docstring_args_match_signature` covers the `Args:` section parameter names. Eleven more gate validators each cover one deterministic slice of the free-form prose. `check_docstring_delegation_summary_enumeration_drift` covers a thin delegating wrapper's docstring summary enumerating actions that the same-named function's summary in the named sibling file omits, compared from both save directions. `check_docstring_names_absent_type_checking_gate` covers a module or function docstring that names a `TYPE_CHECKING` gate-detection step, or a `type-checking-gate` helper family, while no identifier in the module's code carries the `type_checking` marker — the drift where the prose points a reader at a gate the body never performs; drop the `TYPE_CHECKING` gate wording, or add the detection the prose describes. `check_docstring_length_constant_superlative_vs_exact_gate` covers a length-constant module whose docstring describes an integer `*_LENGTH` constant with a superlative or range word (`the longest color string the swatch accepts`) while the only code consuming the constant compares `len(...)` against it with `==`/`!=` — an exact-length gate that rejects every other length — and never with an ordered operator; the check scans the constant module's package tree (its own directory, or the parent package when the module sits in a `config/` subdirectory), so the mismatching consumer may sit in a sibling module. `check_docstring_fallback_branch_coverage` covers a summary that scopes a fallback to a single condition (`only when`, `falls back to ... when`) while the body routes to that same fallback call from two or more distinct early-return guards. `check_class_docstring_names_public_methods` covers a class whose docstring is a single summary line while the class exposes two or more public methods whose names the summary never spells out — the drift where a one-line class summary keeps naming its first feature after the class grows a second public entry point. `check_docstring_no_consumer_claim` covers a producer docstring asserting that no consumer reads its output yet (`producer-only artifact`, `no submission-run consumer reads it yet`) — a transitional claim that drifts the moment a reader lands and contradicts any companion `SKILL.md` that documents the consumer; this is the deterministic slice of the O8 companion-doc producer/consumer drift below. `check_docstring_returns_plural_cardinality` covers a `Returns:` clause that names a dict-key prefix family with a plural noun (`the sheen stops`) while the returned dict literal holds exactly one key in that family (`sheen_mid`) — the drift where a single-key family carries a plural noun, so the prose claims a cardinality of two or more that the dict does not hold. `check_docstring_args_single_line_scope_vs_span` covers an `Args:` entry whose prose scopes a finding to a single named line (`only when its block-anchor line is among the changed lines`) while the body builds a `range(...)` span over the finding's source lines and scopes it through a span-intersection scoper — the drift where the Args entry claims a narrower single-line scope than the span-intersection body applies, so an edit touching any non-anchor line of the span still blocks. `check_docstring_cardinal_count_matches_constant_family` covers a docstring that states a cardinal count of an outcome family (`Covers the four outcome branches: ...`) and lists those members, while the module references more members of the same `UPPER_SNAKE` constant family than the count names (`OUTCOME_OFFENDER_UNREADABLE` is imported and exercised, yet the summary stops at four) — the drift where a summary keeps the old count after the code grows another branch; this gate runs on test modules as well as production modules. `check_docstring_raises_unraisable_largezipfile` covers a `Raises:` clause that names `zipfile.LargeZipFile` while the function opens its `zipfile.ZipFile` writer in a write mode (`w`/`a`/`x`) with `allowZip64` left at its default of True — `zipfile` raises `LargeZipFile` only when an entry needs ZIP64 and `allowZip64` is False, so a writer that allows ZIP64 documents an exception the body cannot produce. `check_docstring_no_network_claim_with_metadata_access` covers a function docstring promising a code path returns `without touching the network` (or a sibling no-network phrase) while the body calls a path-metadata method (`is_file`, `is_dir`, `exists`, `stat`, `lstat`) — on a network share each metadata call is a round-trip over the wire, so a cache-hit path the docstring swore avoids the network still pays a stat on every call; reword the claim to state the path is stat-checked on every call, or short-circuit to the cached path before the share is touched. The remaining free-form prose — `"a field counts as read when ..."`, `"resolves to shared temp only"`, `"strip ceremony, then drop blockquotes"`, and the broader module-responsibility paragraph outside the user-facing-text-scope slice the checklist below names — has no signature, method roster, or single structural shape to compare against, so the gate cannot catch its drift. This rule is the judgment standard for that prose; the audit lane below is the enforcement for everything outside the twelve gated slices.
10
16
 
11
17
  ## What to check before you write the docstring
12
18
 
@@ -16,8 +22,11 @@ Read the body and the docstring side by side:
16
22
  - **Suppressor / skip lists.** A body with several early returns that suppress the check names each suppressor in the prose.
17
23
  - **Shared fallback routes.** A summary that scopes a fallback call to one condition names every condition that reaches that call. When the body routes to the same fallback from two or more early-return guards (`if a is None: fallback(); return` and `if random() < p: fallback(); return`), the prose enumerates both guards. The `check_docstring_fallback_branch_coverage` gate blocks the single-condition form of this drift at Write/Edit time.
18
24
  - **Step order.** A docstring that says `A then B then C` matches the call order in the body. A step enumeration that names the body's linear steps also names every corrective step the body guards inside an `if`/`elif` branch (`if not await cancel_and_reinitiate_update(...): return`). The `check_docstring_step_enumeration_dispatch_coverage` gate blocks the branch-guarded-dispatch form of this drift — a step-enumeration docstring that omits a two-or-more-token dispatch step the body guards inside a branch — at Write/Edit time.
25
+ - **Delegation pointer summaries.** A thin delegating method whose docstring names its actions and points at the home of the real body (Apply Russia, review note, publication edits; full doc on `listing_edit_flow`) lists the same actions the delegated function's own summary lists. When an edit moves one action out of the delegated body, the same edit rewords both summaries. The `check_docstring_delegation_summary_enumeration_drift` gate blocks this drift as either side lands: a saved wrapper docstring gets compared against the delegated body beside it, and a saved delegated body gets compared against every neighboring wrapper docstring pointing at it. A conditional bullet in the delegated prose (`re-apply the privacy policy after the upload`) also names every exception the body honors (`unless the reopened button reads Re-register`) — that conditional-completeness slice stays a judgment call for the audit lane.
19
26
  - **JS/`.mjs` resume-task enumerations.** A `spawn<Role>Agent` JSDoc that enumerates its sibling `resume<Role>Agent`'s resume tasks in a parenthetical `resume (repair-verify, hardening-verify)` list names every `task === '<name>'` branch the resume body dispatches on. The `check_js_resume_task_enumeration_coverage` gate blocks the JavaScript form of this drift — a spawn JSDoc whose resume enumeration omits a dispatched task — at Write/Edit time. This is the `.mjs` slice of the same Category O6 standard the Python gates carry; the Python AST docstring gates never inspect JavaScript source.
20
27
  - **JS/`.mjs` `@returns` object with a schema-less branch.** A `function` whose JSDoc `@returns {Promise<object>}` promises a structured object names a return type every branch honors. When the body returns one agent-spawn helper both with a `schema` options object and without one, the schema-less branch resolves to a transcript string, not the object the JSDoc claims. The `check_js_returns_object_schemaless_branch` gate blocks this drift — a `Promise<object>` JSDoc whose body returns the same helper with and without a `schema` key — at Write/Edit time. This is the `.mjs` slice of the same Category O6 standard the Python gates carry; the Python AST docstring gates never inspect JavaScript source.
28
+ - **JS/`.mjs` sibling return-object key drift.** Every return path of a function that yields the same record carries the same keys. When an early return in a workflow body omits exactly one key its sibling tail return carries (`allDeferredPrs`), a caller reading that key off the short path gets undefined where the documented contract and the sibling return both promise it. The `check_js_sibling_return_object_key_drift` gate blocks this drift — a `return { ... }` object literal whose key set misses exactly one key of a sibling return in the same function or module scope, with discriminated-union variants and two-or-more-key exit shapes left alone — at Write/Edit time. This is the `.mjs` slice of the same Category O standard the Python gates carry; the Python AST docstring gates never inspect JavaScript source.
29
+ - **JS/`.mjs` bare-flag return directive vs a stated full-result contract.** A converge-workflow preamble that states a full result-object contract (`{sha, clean:false, down:true, findings:[]}`) and adds "never a bare down flag" matches any `return <flag>: true`/`false` prose directive elsewhere in the file that repeats a status flag the stated contract rules out. When a step's prose says to "return down: true" once a budget runs out, that directive repeats the bare flag the preamble rules out — a StructuredOutput run whose schema needs every field would reject a lone `{down:true}`. The `check_js_bare_flag_return_directive` gate blocks this drift — a `return <name>: true`/`false` prose directive anywhere in the file that repeats a status flag a stated contract rules out, with no proximity or ordering check between the two — at Write/Edit time. This is the `.mjs` slice of the same Category O6 standard the Python gates carry; the Python AST docstring gates never inspect JavaScript source.
21
30
  - **Returns-clause cardinality.** A `Returns:` clause that names a dict-key prefix family with a plural noun (`the sheen stops`) matches the count of keys in that family in the returned dict literal. When the dict holds one key in the family (`sheen_mid`), the noun is singular (`the sheen stop`); a plural noun there claims two or more entries the dict does not hold. The `check_docstring_returns_plural_cardinality` gate blocks the single-key-with-plural-noun form of this drift at Write/Edit time.
22
31
  - **Length-constant superlative vs exact gate.** A module docstring that describes an integer `*_LENGTH` constant with a superlative or range word (`the longest color string the swatch accepts`, `no longer than`) matches how the code consumes the constant. When the only consumer compares `len(...)` against the constant with `==`/`!=` — an exact-length gate where every other length is rejected, not accepted at a shorter length — the superlative prose claims a range of accepted lengths the code never allows. State the exact required length (`the exact #AARRGGBB length`), not a longest/range form. The `check_docstring_length_constant_superlative_vs_exact_gate` gate blocks this drift at Write/Edit time, scanning the constant module's package tree so it sees a consumer that lives in a sibling module; a constant genuinely used as a ceiling (`len(x) <= LIMIT`) is left alone.
23
32
  - **Args single-line scope vs span body.** An `Args:` entry that scopes a finding to one named line (`a finding blocks only when its block-anchor line is among the changed lines`) matches the line breadth the body scopes by. When the body builds a `range(...)` span over the finding's source lines and scopes it through a span-intersection scoper that blocks when any line of the span is among the changed lines, the single-line Args wording understates the scope: an edit touching a non-anchor line of the span still blocks. State the Args entry on the same span breadth the body uses (`a finding blocks when any line of its block span is among the changed lines`). The `check_docstring_args_single_line_scope_vs_span` gate blocks the single-line-Args-over-span-body form of this drift at Write/Edit time.
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - "**/*.md"
4
+ ---
5
+
1
6
  # Env-Var Summary Table Names a Code File That Reads the Variable
2
7
 
3
8
  **When this applies:** Any Write, Edit, or MultiEdit to a markdown (`.md`) file that carries an environment-variable summary table — a markdown table whose rows pair a `` `VARIABLE` `` name with the `` `code/file.py` `` that reads it.
@@ -0,0 +1,17 @@
1
+ # File Search Through the es.exe CLI
2
+
3
+ **When this applies:** Any file-system search on Windows — finding files by name, path, extension, size, or date modified.
4
+
5
+ ## Rule
6
+
7
+ `es.exe` (the Everything command-line tool) is the file-search tool. Every search carries a scope: a project path or registry token, an `ext:` filter, a `dm:` date filter, a `size:` filter, or a name pattern. A bare whole-drive scan or a network-share sweep is out of bounds — narrow the search to what you need.
8
+
9
+ When `es.exe` fails or returns nothing, try to self heal. If self-healing fails, prompt user with askuserquestion with an analysis, plus next steps questions. ie: fall back to `Glob` (name and path patterns) or `Grep` (file contents), and report the outage so the reader knows the index was unavailable.
10
+
11
+ ## Registry tokens
12
+
13
+ The `es_exe_path_rewriter` hook resolves scope tokens before the command runs. A `{project-name}` placeholder or a bare registry key from `~/.claude/project-paths.json` becomes its quoted absolute path in the command. The hook allows and rewrites — it never blocks — so a search scoped to a registered project names the project token and lets the hook fill in the path.
14
+
15
+ ## Operator syntax
16
+
17
+ `skills/everything-search/SKILL.md` holds the full operator reference: `ext:`, `dm:`, `size:`, wildcards, OR/AND/NOT, output flags, and the junction/drive-mapping note.
@@ -1,5 +1,12 @@
1
1
  ---
2
- paths: **/*
2
+ paths:
3
+ - "**/*.md"
4
+ - "**/*.py"
5
+ - "**/*.mjs"
6
+ - "**/*.js"
7
+ - "**/*.ts"
8
+ - "**/*.ps1"
9
+ - "**/*.sh"
3
10
  ---
4
11
 
5
12
  # No Historical Clutter in Documentation or Comments
@@ -8,10 +15,14 @@ paths: **/*
8
15
 
9
16
  **Hook enforcement:** `state-description-blocker` (PreToolUse on Write|Edit) blocks historical/comparative language automatically. See `hooks.json` for registration.
10
17
 
18
+ Coverage spans `.md` prose, code comments, and Python module/class/function docstrings; a phrase wrapped in double quotes or backticks inside a docstring counts as a mention and is skipped.
19
+
11
20
  ## Rule
12
21
 
13
22
  Never reference removed implementations, old defaults, prior behaviors, or how something `"used to be"` when updating documentation. The current state is all that matters.
14
23
 
24
+ A module or function docstring carries the same describe-current-state-only contract as a `.md` file.
25
+
15
26
  ## Examples of prohibited patterns
16
27
 
17
28
  ### In documentation (.md files)
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ ---
5
+
1
6
  # Orphan CSS Class in Generated Markup
2
7
 
3
8
  **When this applies:** Any Write or Edit to a production `.py` file that builds HTML by emitting `class="..."` attributes inside string literals and pairs them with a `<style>` block — in the same file or in a companion module beside it.
@@ -1,3 +1,13 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ - "**/*.mjs"
5
+ - "**/*.js"
6
+ - "**/*.ts"
7
+ - "**/*.ps1"
8
+ - "**/*.sh"
9
+ ---
10
+
1
11
  # New Production File Absent From Its Package Inventory
2
12
 
3
13
  **When this applies:** Any Write that creates a new production code file (`.py`, `.mjs`, `.js`, `.ts`, `.ps1`, `.sh`) in a directory whose sibling `README.md` or `CLAUDE.md` already names two or more of the directory's files in backticks, or in a skill's `scripts/` subdirectory whose parent `SKILL.md` Layout table already names two or more of those scripts.
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ ---
5
+
1
6
  # Public-Function Paired-Test Coverage
2
7
 
3
8
  **When this applies:** Either side of a paired module/test pair, so the check fires whichever file the write touches:
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ ---
5
+
1
6
  # Plain, Illustrative Docstrings
2
7
 
3
8
  **When this applies:** Any Write or Edit to a public function, method, class, or module docstring whose narrative prose — the summary and description before the first `Args:` / `Returns:` / `Raises:` / `Yields:` section — says what the code is for or how it behaves. The standard governs the prose a reader meets first, not the structured `Args:` / `Returns:` entries below it.
@@ -22,6 +22,13 @@ Before writing any AskUserQuestion or asking a clarifying question in chat, eval
22
22
 
23
23
  Only after confirming the answer cannot be obtained through any available tool, ask the user.
24
24
 
25
+ ## Prior-session facts expire
26
+
27
+ A path, port, branch name, or config value you recall from an earlier session counts as unanswered until a tool re-checks it this session. Memory records what was true when it was written; the file may have moved, the port may be down, the branch may have merged. Treat every recalled fact as a claim to re-ground, not an answer to reuse.
28
+
29
+ - When a tool can settle it, re-check in silence and act on the fresh result — no question to the user.
30
+ - When no tool can settle it and the user has a stake in the answer, ask through `AskUserQuestion` (see [`confirm-implementation-forks`](confirm-implementation-forks.md)).
31
+
25
32
  ## Questions That Belong to the User
26
33
 
27
34
  Reserve user questions for:
@@ -0,0 +1,40 @@
1
+ # Verify Runtime State
2
+
3
+ **When this applies:** Before stating that a component is fine, healthy, not at fault, or working — during debugging, triage, or any judgment about whether something runs.
4
+
5
+ ## Rule
6
+
7
+ A verdict that a component is fine or not the cause rests on live evidence gathered this session: a process list, a port probe, a log tail, an HTTP status code, or a fresh repro. Reading the code, recalling how the component behaved earlier, or trusting a prior session's finding does not settle whether it runs right now. Code shows what should happen; only a live probe shows what does.
8
+
9
+ Gather the probe before you write the verdict. When the probe contradicts the code (the code looks right but the port refuses the connection), report the live result and treat the component as suspect.
10
+
11
+ ## Grounding checklist
12
+
13
+ Before stating a runtime claim, gather the matching live signal:
14
+
15
+ | Claim | Grounding probe |
16
+ |---|---|
17
+ | The service is healthy | Hit its health endpoint and read the status code. |
18
+ | The config is in effect | Print the loaded config at runtime and read the value. |
19
+ | The server is up | Probe the port; a refused connection means it is down. |
20
+ | The process is running | List processes and match the name or PID. |
21
+ | The change took effect | Drive the flow and watch the new behavior. |
22
+ | The dependency is reachable | Send one real request and read the response. |
23
+
24
+ Only after a live signal backs the claim do you state it.
25
+
26
+ ## Examples
27
+
28
+ **Wrong:** "The search server code looks correct, so it is not the problem."
29
+ **Right:** Probe port 54321; report "connection refused — the server is down."
30
+
31
+ **Wrong:** "This function handles the retry, so the request must be going through."
32
+ **Right:** Tail the request log and confirm the retry fired, or report that no retry line appears.
33
+
34
+ **Wrong:** "The config sets the timeout to 30 seconds, so the timeout is fine."
35
+ **Right:** Print the loaded config at runtime and report the value the process actually holds.
36
+
37
+ ## Relationship to other rules
38
+
39
+ - **`verify-before-asking`** answers questions with a tool before asking the user. This rule extends that to runtime verdicts: gather the live probe before you conclude, not just before you ask.
40
+ - **`long-horizon-autonomy`** requires every progress claim to rest on a tool result from this session. A runtime verdict is a progress claim; this rule names the probes that back it.
@@ -1,3 +1,11 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ - "**/*.mjs"
5
+ - "**/*.js"
6
+ - "**/*.ts"
7
+ ---
8
+
1
9
  # Windows Filesystem Safety
2
10
 
3
11
  Never call `shutil.rmtree` with `ignore_errors=True` — Windows `ReadOnly` files (e.g. `.git/objects/pack/`) raise `PermissionError`, the flag swallows it, and the tree silently stays on disk. Use an `onexc` (Python >= 3.12) / `onerror` handler that runs `os.chmod(target_path, stat.S_IWRITE)` then retries the removal function the failure interrupted.
@@ -0,0 +1,33 @@
1
+ # Workers Done Before Complete
2
+
3
+ **When this applies:** Before marking any task `completed` when the task spawned workers — subagents, workflow agents, or background shells.
4
+
5
+ ## Rule
6
+
7
+ A task reaches `completed` only when two things hold: every worker it spawned has finished, and each worker's result is merged into run state — `state.json`, `pr-converge-state.json`, the task list, or whatever record the task keeps. A worker that still runs, or one that finished but whose output never landed in run state, leaves the task open.
8
+
9
+ List the live workers before you mark the task complete. When a worker is dead or hung, that is a finding to record and report, not a result to drop in silence. A step that waits on workers ends its turn `in_progress` with a wakeup scheduled, so the run picks the workers back up rather than closing the task without them.
10
+
11
+ ## Checklist before marking complete
12
+
13
+ | Check | Action |
14
+ |---|---|
15
+ | Are any spawned workers still running? | List them; if yes, stay `in_progress` and schedule a wakeup. |
16
+ | Did every finished worker return a result? | Read each result; a dead or hung worker is a finding to report. |
17
+ | Is each result merged into run state? | Write it to `state.json` / the task list before closing. |
18
+ | Does the task's own goal now hold? | Confirm against the merged state, not a worker's self-report. |
19
+
20
+ Mark `completed` only when every row passes.
21
+
22
+ ## Examples
23
+
24
+ **Wrong:** Marking the audit task complete while two bugteam workers still run in the background.
25
+ **Right:** List the workers, see two still running, keep the task `in_progress`, and schedule a wakeup to collect them.
26
+
27
+ **Wrong:** A worker crashes; the task closes as complete because the other workers finished.
28
+ **Right:** Record the crashed worker as a finding, report it, and hold the task open until its work is covered.
29
+
30
+ ## Relationship to other rules
31
+
32
+ - **`long-horizon-autonomy`** covers acting on what you have and not ending a turn on a promise. This rule names the specific completion gate: workers finished and their results merged.
33
+ - **`skills/pr-converge/reference/state-schema.md`** defines the run-state records this rule requires a worker's result to land in before the task closes.
@@ -1,3 +1,8 @@
1
+ ---
2
+ paths:
3
+ - "**/*.workflow.js"
4
+ ---
5
+
1
6
  # Workflow Substitution Slot Rule
2
7
 
3
8
  In a `.workflow.js` agent-prompt template, every per-call or per-iteration value an agent must fill in is marked with the angle-bracket convention — `<plate.svg>`, `<object.svg>`, `<glow_hex>`, `cand_<i>`. A bare token such as `cand_i` reads as a fixed literal, so an agent can create one literal directory named `cand_i` and overwrite it across every iteration of a loop, collapsing an N-iteration gate into a single run.
package/skills/CLAUDE.md CHANGED
@@ -42,7 +42,7 @@ Skills install to `~/.claude/skills/<skill-name>/` via `packages/claude-dev-env/
42
42
  - `research-mode` — activates anti-hallucination discipline for a session
43
43
  - `recall` — retrieves facts from memory files
44
44
  - `remember` — saves a decision, gotcha, or architectural choice to the Obsidian vault
45
- - `everything-search` — file-system search via the Everything MCP tool
45
+ - `everything-search` — file-system search via the Everything `es.exe` CLI
46
46
  - `caveman` — trims noise from a draft artifact
47
47
 
48
48
  **Session and workflow management**