claude-dev-env 1.38.0 → 1.39.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 (271) hide show
  1. package/CLAUDE.md +10 -36
  2. package/_shared/pr-loop/audit-reply-template.md +147 -0
  3. package/_shared/pr-loop/fix-protocol.md +25 -4
  4. package/_shared/pr-loop/gh-payloads.md +37 -50
  5. package/_shared/pr-loop/scripts/code_rules_gate.py +0 -60
  6. package/_shared/pr-loop/scripts/config/post_audit_thread_constants.py +189 -0
  7. package/_shared/pr-loop/scripts/post_audit_thread.py +947 -0
  8. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -19
  9. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +923 -0
  10. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +127 -0
  11. package/_shared/pr-loop/state-schema.md +1 -1
  12. package/agents/clean-coder.md +2 -2
  13. package/bin/install.mjs +6 -7
  14. package/bin/install.test.mjs +8 -0
  15. package/commands/doc-gist.md +16 -0
  16. package/commands/plan.md +0 -2
  17. package/commands/review-plan.md +1 -1
  18. package/docs/CODE_RULES.md +122 -2
  19. package/hooks/blocking/bot_mention_comment_blocker.py +75 -0
  20. package/hooks/blocking/code_rules_enforcer.py +1236 -161
  21. package/hooks/blocking/convergence_gate_blocker.py +130 -0
  22. package/hooks/blocking/destructive_command_blocker.py +74 -0
  23. package/hooks/blocking/gh_body_arg_blocker.py +30 -0
  24. package/hooks/blocking/md_to_html_blocker.py +119 -0
  25. package/hooks/blocking/test_bot_mention_comment_blocker.py +131 -0
  26. package/hooks/blocking/test_code_rules_enforcer.py +21 -0
  27. package/hooks/blocking/test_code_rules_enforcer_any_exempt_files.py +70 -0
  28. package/hooks/blocking/test_code_rules_enforcer_any_imports_and_cast.py +92 -0
  29. package/hooks/blocking/test_code_rules_enforcer_banned_import_alias.py +143 -0
  30. package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +152 -0
  31. package/hooks/blocking/test_code_rules_enforcer_bare_except.py +120 -0
  32. package/hooks/blocking/test_code_rules_enforcer_boundary_types.py +175 -0
  33. package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -1
  34. package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +50 -0
  35. package/hooks/blocking/test_code_rules_enforcer_docstring_format.py +255 -0
  36. package/hooks/blocking/test_code_rules_enforcer_inline_tuple_string_magic.py +130 -0
  37. package/hooks/blocking/test_code_rules_enforcer_stub_implementations.py +141 -0
  38. package/hooks/blocking/test_code_rules_enforcer_test_branching.py +143 -0
  39. package/hooks/blocking/test_code_rules_enforcer_thin_wrapper_files.py +169 -0
  40. package/hooks/blocking/test_code_rules_enforcer_todo_markers.py +99 -0
  41. package/hooks/blocking/test_code_rules_enforcer_typed_dict_pairs.py +141 -0
  42. package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +158 -0
  43. package/hooks/blocking/test_convergence_gate_blocker.py +63 -0
  44. package/hooks/blocking/test_destructive_command_blocker.py +146 -0
  45. package/hooks/blocking/test_destructive_command_blocker_no_verify.py +102 -0
  46. package/hooks/blocking/test_gh_body_arg_blocker.py +45 -0
  47. package/hooks/blocking/test_md_to_html_blocker.py +317 -0
  48. package/hooks/config/any_type_config.py +7 -0
  49. package/hooks/config/banned_identifiers_constants.py +11 -0
  50. package/hooks/config/blocking_check_limits.py +38 -0
  51. package/hooks/config/bot_mention_comment_blocker_constants.py +20 -0
  52. package/hooks/config/code_rules_enforcer_constants.py +53 -0
  53. package/hooks/config/convergence_branch_constants.py +9 -0
  54. package/hooks/config/doc_gist_auto_publish_constants.py +18 -0
  55. package/hooks/config/html_companion_constants.py +20 -0
  56. package/hooks/config/inline_tuple_string_magic_constants.py +22 -0
  57. package/hooks/config/test_banned_identifiers_constants.py +17 -0
  58. package/hooks/hooks.json +28 -20
  59. package/hooks/pyproject.toml +69 -0
  60. package/hooks/validators/mypy_integration.py +47 -1
  61. package/hooks/validators/run_all_validators.py +3 -3
  62. package/hooks/validators/test_mypy_integration.py +50 -1
  63. package/hooks/workflow/doc_gist_auto_publish.py +144 -0
  64. package/hooks/workflow/md_to_html_companion.py +365 -0
  65. package/hooks/workflow/test_doc_gist_auto_publish.py +117 -0
  66. package/hooks/workflow/test_md_to_html_companion.py +452 -0
  67. package/package.json +1 -1
  68. package/rules/gh-body-file.md +2 -0
  69. package/scripts/Install-SweepEmptyDirs.ps1 +111 -0
  70. package/scripts/check.ps1 +106 -0
  71. package/scripts/config/timing.py +11 -0
  72. package/scripts/sweep_empty_dirs.py +138 -0
  73. package/scripts/sync_to_cursor/rules.py +1 -1
  74. package/scripts/test_sweep_empty_dirs.py +183 -0
  75. package/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +323 -0
  76. package/skills/_shared/pr-loop/scripts/_cli_utils.py +22 -0
  77. package/skills/_shared/pr-loop/scripts/_path_resolver.py +165 -0
  78. package/skills/_shared/pr-loop/scripts/_xml_utils.py +20 -0
  79. package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +182 -0
  80. package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +185 -0
  81. package/skills/_shared/pr-loop/scripts/config/__init__.py +0 -0
  82. package/skills/_shared/pr-loop/scripts/config/path_resolver_constants.py +78 -0
  83. package/skills/_shared/pr-loop/scripts/init_loop_state.py +135 -0
  84. package/skills/_shared/pr-loop/scripts/teardown_worktrees.py +175 -0
  85. package/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +182 -0
  86. package/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +206 -0
  87. package/skills/bugteam/CONSTRAINTS.md +21 -22
  88. package/skills/bugteam/EXAMPLES.md +3 -3
  89. package/skills/bugteam/PROMPTS.md +227 -67
  90. package/skills/bugteam/SKILL.md +114 -455
  91. package/skills/bugteam/reference/README.md +1 -1
  92. package/skills/bugteam/reference/audit-and-teammates.md +112 -39
  93. package/skills/bugteam/reference/audit-contract.md +4 -22
  94. package/skills/bugteam/reference/copilot-gap-analysis.md +8 -5
  95. package/skills/bugteam/reference/design-rationale.md +2 -2
  96. package/skills/bugteam/reference/github-pr-reviews.md +50 -57
  97. package/skills/bugteam/reference/obstacles/audit-assign-ids.md +13 -0
  98. package/skills/bugteam/reference/obstacles/audit-capture-excerpts.md +13 -0
  99. package/skills/bugteam/reference/obstacles/audit-walk-categories.md +13 -0
  100. package/skills/bugteam/reference/obstacles/audit-write-xml.md +13 -0
  101. package/skills/bugteam/reference/obstacles/fix-append-summary.md +13 -0
  102. package/skills/bugteam/reference/obstacles/fix-apply-fixes.md +13 -0
  103. package/skills/bugteam/reference/obstacles/fix-git-add-commit.md +13 -0
  104. package/skills/bugteam/reference/obstacles/fix-git-push.md +13 -0
  105. package/skills/bugteam/reference/obstacles/fix-post-reply.md +13 -0
  106. package/skills/bugteam/reference/obstacles/fix-publish-summary.md +13 -0
  107. package/skills/bugteam/reference/obstacles/fix-py-compile.md +13 -0
  108. package/skills/bugteam/reference/obstacles/fix-read-files.md +13 -0
  109. package/skills/bugteam/reference/obstacles/fix-resolve-thread.md +13 -0
  110. package/skills/bugteam/reference/obstacles/fix-test-suite.md +13 -0
  111. package/skills/bugteam/reference/obstacles/fix-violation-count.md +13 -0
  112. package/skills/bugteam/reference/obstacles/fix-write-xml.md +13 -0
  113. package/skills/bugteam/reference/team-setup.md +106 -9
  114. package/skills/bugteam/reference/teardown-publish-permissions.md +39 -8
  115. package/skills/bugteam/scripts/README.md +60 -0
  116. package/skills/bugteam/scripts/_claude_permissions_common.py +358 -0
  117. package/skills/bugteam/scripts/bugteam_code_rules_gate.py +976 -0
  118. package/skills/bugteam/scripts/bugteam_fix_hookspath.py +375 -0
  119. package/skills/bugteam/scripts/bugteam_preflight.py +294 -0
  120. package/skills/bugteam/scripts/config/bugteam_code_rules_gate_constants.py +25 -0
  121. package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +26 -0
  122. package/skills/bugteam/scripts/config/bugteam_preflight_constants.py +35 -0
  123. package/skills/bugteam/scripts/config/claude_permissions_common_constants.py +20 -0
  124. package/skills/bugteam/scripts/config/probe_code_rules_enforcer_check_constants.py +12 -0
  125. package/skills/bugteam/scripts/config/windows_safe_rmtree_constants.py +7 -0
  126. package/skills/bugteam/scripts/grant_project_claude_permissions.py +175 -0
  127. package/skills/bugteam/scripts/probe_code_rules_enforcer_check.py +107 -0
  128. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +220 -0
  129. package/skills/bugteam/scripts/test__claude_permissions_common.py +112 -0
  130. package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +400 -0
  131. package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +384 -0
  132. package/skills/bugteam/scripts/test_bugteam_preflight.py +268 -0
  133. package/skills/bugteam/scripts/test_claude_permissions_common.py +195 -0
  134. package/skills/bugteam/scripts/test_grant_project_claude_permissions.py +55 -0
  135. package/skills/bugteam/scripts/test_probe_code_rules_enforcer_check.py +76 -0
  136. package/skills/bugteam/scripts/test_revoke_project_claude_permissions.py +55 -0
  137. package/skills/bugteam/scripts/test_windows_safe_rmtree.py +108 -0
  138. package/skills/bugteam/scripts/windows_safe_rmtree.py +100 -0
  139. package/skills/bugteam/test_skill_additions.py +1 -11
  140. package/skills/code/SKILL.md +176 -0
  141. package/skills/doc-gist/SKILL.md +99 -0
  142. package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +453 -0
  143. package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +515 -0
  144. package/skills/doc-gist/references/examples/03-code-review-pr.html +638 -0
  145. package/skills/doc-gist/references/examples/04-code-understanding.html +491 -0
  146. package/skills/doc-gist/references/examples/05-design-system.html +629 -0
  147. package/skills/doc-gist/references/examples/06-component-variants.html +605 -0
  148. package/skills/doc-gist/references/examples/07-prototype-animation.html +455 -0
  149. package/skills/doc-gist/references/examples/08-prototype-interaction.html +396 -0
  150. package/skills/doc-gist/references/examples/09-slide-deck.html +592 -0
  151. package/skills/doc-gist/references/examples/10-svg-illustrations.html +492 -0
  152. package/skills/doc-gist/references/examples/11-status-report.html +528 -0
  153. package/skills/doc-gist/references/examples/12-incident-report.html +596 -0
  154. package/skills/doc-gist/references/examples/13-flowchart-diagram.html +395 -0
  155. package/skills/doc-gist/references/examples/14-research-feature-explainer.html +381 -0
  156. package/skills/doc-gist/references/examples/15-research-concept-explainer.html +368 -0
  157. package/skills/doc-gist/references/examples/16-implementation-plan.html +702 -0
  158. package/skills/doc-gist/references/examples/17-pr-writeup.html +595 -0
  159. package/skills/doc-gist/references/examples/18-editor-triage-board.html +573 -0
  160. package/skills/doc-gist/references/examples/19-editor-feature-flags.html +663 -0
  161. package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +722 -0
  162. package/skills/doc-gist/references/examples/README.md +5 -0
  163. package/skills/doc-gist/scripts/config/__init__.py +0 -0
  164. package/skills/doc-gist/scripts/config/gist_upload_constants.py +16 -0
  165. package/skills/doc-gist/scripts/gist_upload.py +177 -0
  166. package/skills/doc-gist/scripts/test_gist_upload.py +51 -0
  167. package/skills/findbugs/SKILL.md +68 -2
  168. package/skills/monitor-open-prs/SKILL.md +13 -32
  169. package/skills/monitor-open-prs/test_skill_contract.py +0 -11
  170. package/skills/pr-consistency-audit/SKILL.md +112 -0
  171. package/skills/pr-consistency-audit/reference/detection-rules.md +96 -0
  172. package/skills/pr-consistency-audit/reference/illustrations.md +78 -0
  173. package/skills/pr-converge/SKILL.md +227 -23
  174. package/skills/pr-converge/config/__init__.py +0 -0
  175. package/skills/pr-converge/config/constants.py +62 -0
  176. package/skills/pr-converge/reference/convergence-gates.md +138 -44
  177. package/skills/pr-converge/reference/examples.md +43 -11
  178. package/skills/pr-converge/reference/fix-protocol.md +6 -5
  179. package/skills/pr-converge/reference/ground-rules.md +5 -3
  180. package/skills/pr-converge/reference/multi-pr-orchestration.md +44 -19
  181. package/skills/pr-converge/reference/obstacles/fix-post-replies.md +13 -0
  182. package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +13 -0
  183. package/skills/pr-converge/reference/obstacles/fix-push.md +13 -0
  184. package/skills/pr-converge/reference/obstacles/fix-read-filelines.md +13 -0
  185. package/skills/pr-converge/reference/obstacles/fix-reset-state.md +13 -0
  186. package/skills/pr-converge/reference/obstacles/fix-resolve-threads.md +13 -0
  187. package/skills/pr-converge/reference/obstacles/fix-spawn-clean-coder.md +13 -0
  188. package/skills/pr-converge/reference/obstacles/fix-stage-commit.md +13 -0
  189. package/skills/pr-converge/reference/obstacles/fix-trigger-bugbot.md +13 -0
  190. package/skills/pr-converge/reference/obstacles/fix-write-test.md +13 -0
  191. package/skills/pr-converge/reference/per-tick.md +90 -31
  192. package/skills/pr-converge/reference/state-schema.md +22 -1
  193. package/skills/pr-converge/reference/stop-conditions.md +9 -7
  194. package/skills/pr-converge/scripts/README.md +34 -46
  195. package/skills/pr-converge/scripts/check_bugbot_ci.py +174 -0
  196. package/skills/pr-converge/scripts/check_convergence.py +497 -0
  197. package/skills/pr-converge/scripts/check_pending_reviews.py +154 -0
  198. package/skills/pr-converge/scripts/config/pr_converge_constants.py +118 -0
  199. package/skills/pr-converge/scripts/fetch_copilot_reviews.py +134 -0
  200. package/skills/pr-converge/scripts/post_fix_reply.py +168 -0
  201. package/skills/pr-converge/workflows/schedule-wakeup-loop.md +5 -12
  202. package/skills/qbug/SKILL.md +132 -27
  203. package/skills/session-log/SKILL.md +216 -114
  204. package/skills/session-tidy/SKILL.md +1 -1
  205. package/skills/skill-builder/SKILL.md +138 -56
  206. package/skills/skill-builder/references/delegation-map.md +72 -113
  207. package/skills/skill-builder/references/progressive-disclosure.md +122 -0
  208. package/skills/skill-builder/references/self-audit-checklist.md +92 -0
  209. package/skills/skill-builder/references/skill-types.md +228 -0
  210. package/skills/skill-builder/references/thariq-x-post-skills.json +33 -0
  211. package/skills/skill-builder/templates/gap-analysis.md +15 -8
  212. package/skills/skill-builder/workflows/improve-skill.md +86 -57
  213. package/skills/skill-builder/workflows/new-skill.md +80 -168
  214. package/skills/skill-builder/workflows/polish-skill.md +78 -54
  215. package/skills/structure-prompt/SKILL.md +50 -0
  216. package/skills/structure-prompt/reference/adversarial-tuning.md +62 -0
  217. package/skills/structure-prompt/reference/block-classification.md +27 -0
  218. package/skills/structure-prompt/reference/canonical-case.md +48 -0
  219. package/skills/structure-prompt/reference/citation-depth.md +70 -0
  220. package/skills/structure-prompt/reference/cleanup.md +33 -0
  221. package/skills/structure-prompt/reference/constraints.md +33 -0
  222. package/skills/structure-prompt/reference/directives.md +37 -0
  223. package/skills/structure-prompt/reference/examples.md +72 -0
  224. package/skills/structure-prompt/reference/instantiation.md +51 -0
  225. package/skills/structure-prompt/reference/output-contract.md +72 -0
  226. package/skills/structure-prompt/reference/per-category.md +23 -0
  227. package/skills/structure-prompt/reference/persona.md +38 -0
  228. package/skills/structure-prompt/reference/research.md +33 -0
  229. package/skills/structure-prompt/reference/structure.md +28 -0
  230. package/agents/code-standards-agent.md +0 -93
  231. package/agents/groq-coder.md +0 -113
  232. package/agents/plan-executor.md +0 -226
  233. package/agents/project-docs-analyzer.md +0 -53
  234. package/agents/project-structure-organizer-agent.md +0 -72
  235. package/agents/skill-to-agent-converter.md +0 -370
  236. package/agents/skill-writer-agent.md +0 -470
  237. package/agents/user-docs-writer.md +0 -67
  238. package/agents/workflow-visual-documenter.md +0 -82
  239. package/commands/readability-review.md +0 -20
  240. package/hooks/mypy.ini +0 -2
  241. package/hooks/notification/attention_needed_notify.py +0 -71
  242. package/hooks/notification/claude_notification_handler.py +0 -67
  243. package/hooks/notification/notification_utils.py +0 -267
  244. package/hooks/notification/subagent_complete_notify.py +0 -381
  245. package/hooks/notification/test_attention_needed_notify.py +0 -47
  246. package/hooks/notification/test_claude_notification_handler.py +0 -54
  247. package/hooks/notification/test_notification_utils.py +0 -91
  248. package/hooks/notification/test_subagent_complete_notify.py +0 -79
  249. package/scripts/config/groq_bugteam_config.py +0 -230
  250. package/scripts/config/test_groq_bugteam_config.py +0 -83
  251. package/scripts/config/test_spec_implementer_prompt.py +0 -32
  252. package/scripts/groq_bugteam.README.md +0 -131
  253. package/scripts/groq_bugteam.py +0 -647
  254. package/scripts/groq_bugteam_dotenv.py +0 -40
  255. package/scripts/groq_bugteam_spec.py +0 -226
  256. package/scripts/test_groq_bugteam.py +0 -529
  257. package/scripts/test_groq_bugteam_apply_fix_from_spec.py +0 -426
  258. package/scripts/test_groq_bugteam_dotenv.py +0 -66
  259. package/scripts/test_groq_bugteam_spec.py +0 -338
  260. package/skills/bugteam/SKILL_EVALS.md +0 -309
  261. package/skills/dream/SKILL.md +0 -118
  262. package/skills/ingest/SKILL.md +0 -40
  263. package/skills/npm-creator/SKILL.md +0 -187
  264. package/skills/readability-review/SKILL.md +0 -127
  265. package/skills/resume-review/SKILL.md +0 -261
  266. package/skills/rule-audit/SKILL.md +0 -307
  267. package/skills/rule-creator/SKILL.md +0 -150
  268. package/skills/searching-obsidian-vault/SKILL.md +0 -131
  269. package/skills/skill-writer/REFERENCE.md +0 -284
  270. package/skills/skill-writer/SKILL.md +0 -222
  271. package/skills/tdd-team/SKILL.md +0 -128
@@ -0,0 +1,5 @@
1
+ The example files in this directory are verbatim copies of Thariq Shihipar's [html-effectiveness](https://thariqs.github.io/html-effectiveness/) prototypes, used with permission as reference material for the doc-gist skill's artifact design gallery.
2
+
3
+ Each file demonstrates a distinct HTML artifact shape — annotated PR diff, design system swatches, incident timeline, slide deck, prompt tuner — and serves as learning material for fresh per-request HTML design. The gallery teaches what shapes work; the agent adapts per request rather than copying.
4
+
5
+ See [SKILL.md](../../SKILL.md) for the full gallery-to-artifact-type mapping.
File without changes
@@ -0,0 +1,16 @@
1
+ """Constants for the gist_upload utility.
2
+
3
+ GIST_HOST_PREFIX: anchor for parsing gh's emitted gist URL into user + id.
4
+ PREVIEW_URL_TEMPLATE: the htmlpreview.github.io shape that renders a raw gist file.
5
+ GIST_DEFAULT_FILENAME: filename used when input is stdin (no filename to inherit).
6
+ MINIMUM_GIST_URL_PARTS: gh's gist URL is /<user>/<id>; need at least these many segments.
7
+ """
8
+
9
+ GIST_HOST_PREFIX = "https://gist.github.com/"
10
+ PREVIEW_URL_TEMPLATE = (
11
+ "https://htmlpreview.github.io/?https://gist.githubusercontent.com/"
12
+ "{user}/{gist_id}/raw/{filename}"
13
+ )
14
+ GIST_DEFAULT_FILENAME = "doc.html"
15
+ MINIMUM_GIST_URL_PARTS = 2
16
+ UPLOAD_TIMEOUT_SECONDS = 45
@@ -0,0 +1,177 @@
1
+ """Upload an HTML file as a secret GitHub gist and emit the htmlpreview URL.
2
+
3
+ Single-purpose transport. Takes HTML on stdin or via `--input <path>`, runs
4
+ `gh gist create` (secret by default), parses the gist URL from gh's output,
5
+ composes the htmlpreview.github.io preview URL, optionally opens it in the
6
+ default browser, and prints both URLs.
7
+
8
+ Designed to compose with anything that produces HTML — pipe in the output of
9
+ a script, the contents of a hand-authored file, or have the auto-publish
10
+ hook invoke it on a file Claude just wrote. The script does not opine on
11
+ HTML shape, structure, or styling.
12
+
13
+ Usage:
14
+ gist_upload.py --input <path>
15
+ gist_upload.py --input - --filename writeup.html < some.html
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import argparse
21
+ import os
22
+ import subprocess
23
+ import sys
24
+ import tempfile
25
+ import webbrowser
26
+ from pathlib import Path
27
+ from urllib.parse import quote
28
+
29
+ _script_directory = str(Path(__file__).resolve().parent)
30
+ if _script_directory not in sys.path:
31
+ sys.path.insert(0, _script_directory)
32
+
33
+ from config.gist_upload_constants import ( # noqa: E402
34
+ GIST_DEFAULT_FILENAME,
35
+ GIST_HOST_PREFIX,
36
+ MINIMUM_GIST_URL_PARTS,
37
+ PREVIEW_URL_TEMPLATE,
38
+ UPLOAD_TIMEOUT_SECONDS,
39
+ )
40
+
41
+
42
+ def _read_html(input_argument: str) -> str:
43
+ """Read HTML content from stdin (when input is '-') or a file path.
44
+
45
+ Reads the full stdin stream when input_argument is '-'. Callers piping
46
+ content through an external process should ensure bounded input.
47
+ """
48
+ if input_argument == "-":
49
+ return sys.stdin.read()
50
+ try:
51
+ return Path(input_argument).expanduser().resolve().read_text(encoding="utf-8")
52
+ except (OSError, UnicodeError) as error:
53
+ raise SystemExit(f"Cannot read {input_argument}: {error}")
54
+
55
+
56
+ def _resolve_filename(input_argument: str, override: str | None) -> str:
57
+ """Pick the filename gh will use for the gist file."""
58
+ default_filename = GIST_DEFAULT_FILENAME
59
+ if override:
60
+ return Path(override).name
61
+ if input_argument != "-":
62
+ return Path(input_argument).name
63
+ return default_filename
64
+
65
+
66
+ def _write_to_temp(html_text: str, filename: str, parent_directory: Path) -> Path:
67
+ """Write HTML to a temp file inside parent_directory with the given filename."""
68
+ target_path = parent_directory / filename
69
+ target_path.write_text(html_text, encoding="utf-8")
70
+ return target_path
71
+
72
+
73
+ def _create_secret_gist(html_path: Path, description: str) -> str:
74
+ """Run `gh gist create` against html_path and return the gist URL."""
75
+ try:
76
+ completed = subprocess.run(
77
+ ["gh", "gist", "create", str(html_path), "--desc", description],
78
+ check=False,
79
+ capture_output=True,
80
+ text=True,
81
+ encoding="utf-8",
82
+ errors="replace",
83
+ timeout=UPLOAD_TIMEOUT_SECONDS,
84
+ )
85
+ except FileNotFoundError:
86
+ raise SystemExit(
87
+ "gh CLI not found. Install GitHub CLI (https://cli.github.com) and run `gh auth login`."
88
+ )
89
+ except subprocess.TimeoutExpired:
90
+ raise SystemExit(
91
+ f"gh gist create timed out after {UPLOAD_TIMEOUT_SECONDS}s. Check network and retry."
92
+ )
93
+ if completed.returncode != 0:
94
+ message_text = completed.stderr.strip() or completed.stdout.strip()
95
+ raise SystemExit(
96
+ f"gh gist create failed:\n{message_text}\nRun `gh auth login` and retry."
97
+ )
98
+ output_lines = completed.stdout.strip().splitlines()
99
+ if not output_lines:
100
+ raise SystemExit("gh gist create produced no output.")
101
+ last_line = output_lines[-1].strip()
102
+ if not last_line.startswith(GIST_HOST_PREFIX):
103
+ raise SystemExit(f"Unexpected gh gist create output: {last_line!r}")
104
+ return last_line
105
+
106
+
107
+ def _compose_preview_url(gist_url: str, filename: str) -> str:
108
+ """Build the htmlpreview.github.io URL from the gist URL and the gist filename."""
109
+ minimum_parts = MINIMUM_GIST_URL_PARTS
110
+ preview_template = PREVIEW_URL_TEMPLATE
111
+ path_after_host = gist_url[len(GIST_HOST_PREFIX) :]
112
+ parts = path_after_host.split("/")
113
+ if len(parts) < minimum_parts:
114
+ raise SystemExit(f"Cannot parse gist URL: {gist_url!r}")
115
+ return preview_template.format(user=parts[0], gist_id=parts[1], filename=quote(filename, safe=""))
116
+
117
+
118
+ def _open_in_browser(url: str) -> None:
119
+ """Open the URL in the default browser, deferring to OS-native behavior on Windows."""
120
+ if sys.platform.startswith("win"):
121
+ os.startfile(url)
122
+ return
123
+ webbrowser.open(url)
124
+
125
+
126
+ def main() -> int:
127
+ """Entry point — read HTML, upload as secret gist, print URLs, open preview.
128
+
129
+ Returns:
130
+ Process exit code (0 on success).
131
+ """
132
+ parser = argparse.ArgumentParser(
133
+ description="Upload HTML as a secret gist; print gist + htmlpreview URLs."
134
+ )
135
+ parser.add_argument(
136
+ "--input",
137
+ required=True,
138
+ help="Path to an .html file, or '-' for stdin.",
139
+ )
140
+ parser.add_argument(
141
+ "--filename",
142
+ default=None,
143
+ help="Filename inside the gist. Defaults to the input filename, or 'doc.html' for stdin.",
144
+ )
145
+ parser.add_argument(
146
+ "--description",
147
+ default="HTML artifact",
148
+ help="Gist description.",
149
+ )
150
+ parser.add_argument(
151
+ "--no-open",
152
+ action="store_true",
153
+ help="Skip opening the preview URL in the default browser.",
154
+ )
155
+ arguments = parser.parse_args()
156
+
157
+ html_text = _read_html(arguments.input)
158
+ filename = _resolve_filename(arguments.input, arguments.filename)
159
+
160
+ with tempfile.TemporaryDirectory(prefix="gist-upload-") as temp_directory:
161
+ upload_path = _write_to_temp(html_text, filename, Path(temp_directory))
162
+ gist_url = _create_secret_gist(upload_path, arguments.description)
163
+ preview_url = _compose_preview_url(gist_url, filename)
164
+
165
+ print(f"Gist: {gist_url}", file=sys.stderr)
166
+ print(f"Preview: {preview_url}", file=sys.stderr)
167
+
168
+ if not arguments.no_open:
169
+ _open_in_browser(preview_url)
170
+ print("Opened preview in default browser.", file=sys.stderr)
171
+
172
+ print(preview_url)
173
+ return 0
174
+
175
+
176
+ if __name__ == "__main__":
177
+ sys.exit(main())
@@ -0,0 +1,51 @@
1
+ """Tests for gist_upload.py pure functions — URL composition and filename resolution."""
2
+
3
+ from pathlib import Path
4
+ import sys
5
+
6
+ _script_directory = str(Path(__file__).resolve().parent)
7
+ if _script_directory not in sys.path:
8
+ sys.path.insert(0, _script_directory)
9
+
10
+ from gist_upload import _compose_preview_url, _resolve_filename
11
+
12
+
13
+ class TestResolveFilename:
14
+ def test_uses_override_when_provided(self):
15
+ assert (
16
+ _resolve_filename("report.html", "custom-name.html") == "custom-name.html"
17
+ )
18
+
19
+ def test_strips_directory_from_override(self):
20
+ assert (
21
+ _resolve_filename("report.html", "/some/path/override.html")
22
+ == "override.html"
23
+ )
24
+
25
+ def test_uses_input_filename_when_no_override(self):
26
+ assert _resolve_filename("report.html", None) == "report.html"
27
+
28
+ def test_uses_default_for_stdin_without_override(self):
29
+ assert _resolve_filename("-", None) == "doc.html"
30
+
31
+ def test_override_takes_precedence_over_stdin(self):
32
+ assert _resolve_filename("-", "writeup.html") == "writeup.html"
33
+
34
+
35
+ class TestComposePreviewUrl:
36
+ def test_standard_gist_url(self):
37
+ result = _compose_preview_url(
38
+ "https://gist.github.com/user123/abc123def456",
39
+ "report.html",
40
+ )
41
+ assert result == (
42
+ "https://htmlpreview.github.io/"
43
+ "?https://gist.githubusercontent.com/user123/abc123def456/raw/report.html"
44
+ )
45
+
46
+ def test_filename_with_spaces_is_encoded(self):
47
+ result = _compose_preview_url(
48
+ "https://gist.github.com/user123/abc123def456",
49
+ "my report.html",
50
+ )
51
+ assert "my%20report.html" in result
@@ -112,7 +112,73 @@ The XML prompt skeleton:
112
112
  </output_format>
113
113
  ```
114
114
 
115
- ### Step 4: Surface findings, then clean up
115
+ ### Step 4: Post the audit review
116
+
117
+ Every `/findbugs` invocation posts one audit review back to the PR. The
118
+ unresolved-thread gate counts review threads, so a findbugs pass that
119
+ returns findings without posting them as inline comments is invisible
120
+ to the gate. Findbugs remains read-only on code — the review post is
121
+ the only side effect.
122
+
123
+ **Self-PR precondition.** GitHub rejects both `APPROVE` and
124
+ `REQUEST_CHANGES` reviews when the authenticated identity matches the
125
+ PR author with HTTP 422; `post_audit_thread.py` retries and then exits 2.
126
+ To run findbugs on a PR you authored, switch `gh auth` to an alternate
127
+ reviewer identity (a separate GitHub account) BEFORE invoking the skill.
128
+ Without this switch, exit 2 is a hard halt — there is no automated
129
+ fallback path. The script does not auto-downgrade on the self-PR case.
130
+
131
+ After the agent (and Haiku secondary) return and the merge is complete,
132
+ serialize the merged findings to a JSON file and call
133
+ `post_audit_thread.py`:
134
+
135
+ ```
136
+ python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/post_audit_thread.py" \
137
+ --skill findbugs \
138
+ --owner <owner> \
139
+ --repo <repo> \
140
+ --pr-number <N> \
141
+ --commit <head_sha> \
142
+ --state <CLEAN|DIRTY> \
143
+ --findings-json <path>
144
+ ```
145
+
146
+ The findings JSON root is a list of objects shaped
147
+ `{path, line, side, severity, description, fix_summary}`. Before
148
+ serializing, partition the merged findings into anchored (line appears
149
+ in the captured diff) and unanchored (line is not in the diff) buckets.
150
+ Only anchored findings are serialized to the JSON — the GitHub reviews
151
+ API rejects the entire POST if any inline comment in `comments[]`
152
+ targets a line not in the diff at `--commit`, so a single unanchored
153
+ entry breaks the whole review. Unanchored findings are surfaced via
154
+ Step 5's user-facing output rather than as inline anchored comments.
155
+ For each anchored finding, map `file` → `path`; split the finding's
156
+ `failure_mode` at the literal `Fix:` heading so the failure narrative
157
+ becomes `description` and the suffix beginning at `Fix:` (including
158
+ the trailing `Validation:` clause) becomes `fix_summary` (the
159
+ `failure_mode` field carries the full audit-to-fix handoff per
160
+ [`agents/code-quality-agent.md`](../../agents/code-quality-agent.md)).
161
+ When a finding's `failure_mode` omits the `Fix:` heading, write the
162
+ full text to BOTH `description` and `fix_summary`. Set `side="RIGHT"`
163
+ for every entry. Zero anchored findings → `--state CLEAN` with the
164
+ findings file holding an empty array (`[]`); one or more anchored
165
+ findings → `--state DIRTY` with the full list. CLEAN posts an APPROVE review (the
166
+ request event; GitHub stores it as `state=APPROVED`) with a "no
167
+ findings" summary; DIRTY posts a REQUEST_CHANGES review with one inline
168
+ anchored comment per finding (each becomes its own resolvable thread on
169
+ the PR).
170
+
171
+ Capture `<head_sha>` once at the start of Step 4 via `git rev-parse
172
+ HEAD` in the worktree the diff was scoped against.
173
+
174
+ Exit codes: `0` on success (emits the new review's `html_url` to
175
+ stdout, surface alongside the totals in Step 5); `1` on user input
176
+ error; `2` on retry exhaustion (1s / 4s / 16s backoff across four
177
+ attempts). On exit 2, tell the user the review post failed and that
178
+ the unresolved-thread gate will not see this audit pass; do not retry
179
+ silently.
180
+
181
+ ### Step 5: Surface findings, then clean up
116
182
 
117
183
  When the agent returns, report concisely:
118
184
 
@@ -148,7 +214,7 @@ Want me to run /fixbugs for the P0/P1 findings?
148
214
 
149
215
  ## Constraints
150
216
 
151
- - **Read-only.** The skill never edits code, never pushes, never commits.
217
+ - **Read-only on code.** The skill never edits files, never pushes, never commits. One audit review per invocation gets posted back to the PR (Step 4) — that is the only side effect, and it is required so the unresolved-thread gate sees the audit pass.
152
218
  - **Foreground spawn.** The user is waiting for the result on this turn.
153
219
  - **PR-scoped, not session-scoped.** The audit covers the entire PR diff regardless of which files were edited in this conversation.
154
220
  - **Clean-room prompt.** The agent's prompt is self-contained — no references to chat history, no anchoring hints, no expected outcomes.
@@ -2,24 +2,22 @@
2
2
  name: monitor-open-prs
3
3
  description: >-
4
4
  Discover every open pull request across the jl-cmd/* and JonEcho/*
5
- owner scopes, spawn /bugteam on each in parallel with the Groq-backed
6
- FIX implementer (BUGTEAM_FIX_IMPLEMENTER=groq-coder) and the bugbot
7
- re-trigger flag (--bugbot-retrigger), wrap the session in `bws run`
8
- to inject GROQ_API_KEY, and poll Cursor's bugbot replies after
9
- convergence so any post-Groq findings loop back through /bugteam.
10
- Triggers: '/monitor-open-prs', 'sweep the open PRs', 'groq-bugteam the backlog'.
5
+ owner scopes, spawn /bugteam on each in parallel with the bugbot
6
+ re-trigger flag (--bugbot-retrigger), and poll Cursor's bugbot replies
7
+ after convergence so any post-bugteam findings loop back through
8
+ /bugteam. Triggers: '/monitor-open-prs', 'sweep the open PRs',
9
+ 'audit the open PR backlog'.
11
10
  ---
12
11
 
13
12
  # Monitor Open PRs
14
13
 
15
- **Core principle:** One sweep covers every open PR across both owner scopes. Claude discovers PRs live via `scripts/discover_open_prs.py` which shells out to `gh search prs --owner <owner> --state open --json ...`, dispatches `/bugteam` per PR with `BUGTEAM_FIX_IMPLEMENTER=groq-coder` and `--bugbot-retrigger`, then polls Cursor's bugbot replies until each PR is quiet for a full backoff cycle.
14
+ **Core principle:** One sweep covers every open PR across both owner scopes. Claude discovers PRs live via `scripts/discover_open_prs.py` which shells out to `gh search prs --owner <owner> --state open --json ...`, dispatches `/bugteam --bugbot-retrigger` per PR, then polls Cursor's bugbot replies until each PR is quiet for a full backoff cycle.
16
15
 
17
16
  ## Contents
18
17
 
19
18
  - When this skill applies — refusal cases and trigger conditions
20
19
  - Discovery — `scripts/discover_open_prs.py` queries via `gh search prs` across both owner scopes
21
- - Wrapping`bws run` for GROQ_API_KEY injection
22
- - Dispatch — `/bugteam --bugbot-retrigger <pr_numbers...>` with groq-coder + retrigger
20
+ - Dispatch`/bugteam --bugbot-retrigger <pr_numbers...>`
23
21
  - Post-convergence polling — bugbot replies and re-invocation
24
22
  - `scripts/discover_open_prs.py` — the discovery helper
25
23
 
@@ -29,37 +27,22 @@ description: >-
29
27
 
30
28
  Refusals — first match wins; respond with the quoted line exactly and stop:
31
29
 
32
- - **bws not on PATH.** `bws not installed. /monitor-open-prs injects GROQ_API_KEY via Bitwarden Secrets Manager.`
33
30
  - **GitHub API not accessible.** `get_me failed. /monitor-open-prs needs active GitHub MCP credentials.`
34
31
  - **Dirty tree on the caller's repo.** `Uncommitted changes detected. Stash, commit, or revert before /monitor-open-prs.`
35
- - **Required subagents missing.** Confirm `code-quality-agent`, `clean-coder`, and `groq-coder` exist. Else: `Required subagent type <name> not installed.`
32
+ - **Required subagents missing.** Confirm `code-quality-agent` and `clean-coder` exist. Else: `Required subagent type <name> not installed.`
36
33
 
37
34
  ## Discovery
38
35
 
39
36
  Call `scripts/discover_open_prs.discover_open_prs(all_owners=["jl-cmd", "JonEcho"])` to merge the live open-PR list across both scopes. The helper shells out to `gh search prs --owner <owner> --state open --json number,repository,url,headRefName,baseRefName` for each owner scope and flattens the result to a uniform dict shape with keys `number`, `owner`, `repo`, `head_ref`, `base_ref`, `url`. Empty scopes contribute empty lists; an entirely empty sweep returns `[]` and exits cleanly.
40
37
 
41
- ## Secret Wrapping
42
-
43
- Every `/bugteam` dispatch runs inside `bws run` so `GROQ_API_KEY` is injected from Bitwarden Secrets Manager without touching the filesystem. The project and secret UUIDs are fixed for this skill:
44
-
45
- ```bash
46
- bws run \
47
- --project-id c69cedc5-aea1-4aa8-b350-b4300145d978 \
48
- -- \
49
- env BUGTEAM_FIX_IMPLEMENTER=groq-coder \
50
- /bugteam --bugbot-retrigger <pr_numbers...>
51
- ```
52
-
53
- The `bws run` subshell resolves the project's secrets and exports them for the wrapped command. The `GROQ_API_KEY` secret's UUID inside that project is `b7e99a7f-2ecc-42b3-99a5-b434010622f9`. GitHub auth is not sourced through `bws` — existing MCP `get_me` credentials carry the session.
54
-
55
38
  ## Dispatch
56
39
 
57
40
  For each discovered PR:
58
41
 
59
42
  1. Resolve the PR's repo checkout (existing worktree or fresh `git clone`).
60
- 2. From that checkout, invoke `/bugteam --bugbot-retrigger <pr_number>` under the `bws run` wrapper from §Secret Wrapping.
61
- 3. The `BUGTEAM_FIX_IMPLEMENTER=groq-coder` env var routes the FIX role to the `groq-coder` subagent. The `--bugbot-retrigger` flag tells bugteam to post `bugbot run` as an issue comment after every successful FIX push so Cursor's bugbot re-evaluates the new commit.
62
- 4. Bugteam runs its own 10-loop audit/fix cycle per PR; this skill waits for each bugteam invocation to return before dispatching the next (or fanning out — see below).
43
+ 2. From that checkout, invoke `/bugteam --bugbot-retrigger <pr_number>`.
44
+ 3. The `--bugbot-retrigger` flag tells bugteam to post `bugbot run` as an issue comment after every successful FIX push so Cursor's bugbot re-evaluates the new commit.
45
+ 4. Bugteam runs its own 20-loop audit/fix cycle per PR; this skill waits for each bugteam invocation to return before dispatching the next (or fanning out — see below).
63
46
 
64
47
  **Fan-out (optional):** when the discovered list has more than one PR, the skill may spawn `/bugteam` dispatches in parallel by issuing multiple `Agent` calls in a single assistant message. Each dispatch operates in its own per-PR worktree (bugteam Step 1.1). Serialize when the caller sets an explicit `--serial` flag.
65
48
 
@@ -70,7 +53,7 @@ After a `/bugteam` invocation returns (converged, cap reached, stuck, or error),
70
53
  1. Baseline: capture `since_timestamp` as the PR's last commit timestamp.
71
54
  2. Every 60 seconds, call `pull_request_read(method="get", pullNumber=<pr_number>, owner=<owner>, repo=<repo>)` and filter the response's `comments` array for entries whose `.author.login` matches `"bugbot"` or `"cursor"` and `.createdAt` is after `<since_timestamp>`.
72
55
  3. Back off: 60s → 120s → 240s → 480s → 960s. If five successive polls return empty, exit polling for this PR.
73
- 4. If bugbot posts a new finding in any poll, re-invoke `/bugteam <pr_number>` via the same `bws run` wrapper with the bugbot finding text seeded into the invocation's `bugs_to_fix` preamble. Reset the backoff.
56
+ 4. If bugbot posts a new finding in any poll, re-invoke `/bugteam <pr_number>` with the bugbot finding text seeded into the invocation's `bugs_to_fix` preamble. Reset the backoff.
74
57
 
75
58
  ### Polling Cost and Cadence
76
59
 
@@ -86,16 +69,14 @@ PRs discovered: <N>
86
69
  jl-cmd/*: <count>
87
70
  JonEcho/*: <count>
88
71
  PRs converged clean: <count>
89
- PRs hit 10-loop cap: <count>
72
+ PRs hit 20-loop cap: <count>
90
73
  PRs stuck: <count>
91
74
  PRs errored: <count>
92
75
  Bugbot re-triggers fired: <count>
93
- Total Groq tokens consumed: <approx from /bugteam outcome summaries>
94
76
  ```
95
77
 
96
78
  ## Non-Negotiable Guardrails
97
79
 
98
- - Never source secrets outside `bws run` — no `.env` files, no shell history, no logs.
99
80
  - Never pass `--no-verify` or `--no-gpg-sign` to git in any dispatched bugteam run.
100
81
  - Never open a PR from this skill; only comment on existing ones.
101
82
  - Never merge or close PRs; the skill is read + audit + patch only.
@@ -16,12 +16,6 @@ def test_skill_has_frontmatter_name():
16
16
  assert "name: monitor-open-prs" in skill_text
17
17
 
18
18
 
19
- def test_skill_invokes_bugteam_with_groq_implementer():
20
- skill_text = _read_skill_text()
21
- assert "BUGTEAM_FIX_IMPLEMENTER" in skill_text
22
- assert "groq-coder" in skill_text
23
-
24
-
25
19
  def test_skill_references_bugbot_retrigger_flag():
26
20
  skill_text = _read_skill_text()
27
21
  assert "--bugbot-retrigger" in skill_text
@@ -31,8 +25,3 @@ def test_skill_enumerates_both_owner_scopes():
31
25
  skill_text = _read_skill_text()
32
26
  assert "jl-cmd" in skill_text
33
27
  assert "JonEcho" in skill_text
34
-
35
-
36
- def test_skill_documents_bws_wrapping():
37
- skill_text = _read_skill_text()
38
- assert "bws run" in skill_text
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: pr-consistency-audit
3
+ description: >-
4
+ Audits a PR for cross-file inconsistencies. Finds wrong argument names, missing required args, references to files or scripts that do not exist, stale feature remnants, docstring-vs-implementation mismatches, placeholder text, cross-file contradictions, parameter naming convention violations, and cross-platform bugs. Use when the user says "audit this PR", "find inconsistencies", "cross-reference docs against scripts", "check for stale references", "PR consistency audit".
5
+ ---
6
+
7
+ # PR Consistency Audit
8
+
9
+ Read every changed file in a pull request. Find every inconsistency across files. Leave nothing unchecked. Leave nothing assumed. Zero context needed beyond the diff.
10
+
11
+ ## Gotchas
12
+
13
+ - The highest-signal rule is canonical-source cross-reference. Do it first. Do it slowly. Copilot found 20 of its 43 findings with this rule alone. Missing it means missing half the bugs.
14
+ - Parameter naming conventions are per-tool, not per-project. `issue_read` uses `issue_number` (snake_case). `add_issue_comment` uses `issueNumber` (camelCase). A doc that mixes them is wrong even if snake_case works for `issue_read`.
15
+ - When a finding appears in many files with the same wrong pattern, flag every instance individually. Do not say "this is wrong in 20 files" and move on. List every file with its line.
16
+ - Template files and obstacle files are often skipped because they feel "generated" or "low priority." They are not. Copilot found 6 issues in template files that human auditors never opened.
17
+ - A manifest written to a temp file is not optional. Hold all script signatures, all MCP tool names, all constants, and all concept names in a JSON file. Read from it during detection. Memory fails. Files do not.
18
+
19
+ ## When this skill applies
20
+
21
+ Trigger when the user provides a PR diff, a list of changed files, or asks to audit cross-file consistency. The agent needs no prior knowledge of the repo, the scripts, or the project conventions.
22
+
23
+ ## Process
24
+
25
+ ### Step 1: Build the manifest
26
+
27
+ Read every file in the diff. Top to bottom. Build `<tmp>/audit-manifest-<timestamp>.json`. Track:
28
+
29
+ - Python scripts → argparse arguments (`add_argument("--name", ...)`), which are `required=True`
30
+ - MCP tool call patterns in docs → tool name, every parameter used, file and line
31
+ - Shell commands (`gh`, `git`, `python`, `bash`) → full command, file, line
32
+ - File paths referenced in docs → whether they resolve to real files
33
+ - Named concepts in prose → "inline_lag", "COPILOT_WAIT", "bugfind", phase names, state values. File and line each.
34
+ - Constants, thresholds, timeouts → value, concept it measures, file, line
35
+ - Functions with docstring claims → function name, claim made, file, line
36
+
37
+ ### Step 2: Find canonical sources
38
+
39
+ Identify the files that define the authoritative form of each concept. Signs a file is canonical:
40
+
41
+ - Has structured schemas, payload definitions, API contracts (files like `gh-payloads.md`, `mcp_tool_signatures.json`, `config.py`)
42
+ - Name includes "reference", "spec", "schema", "payload", "contract", "canonical"
43
+ - Other files cite it as the source of truth
44
+ - It defines the implementation that docstrings describe (the `.py` file, not the `.md` that talks about it)
45
+
46
+ For each canonical source, note what concept it is canonical for. When a rule needs to decide what is "correct," the canonical source wins.
47
+
48
+ ### Step 3: Run detection rules
49
+
50
+ Read [`reference/detection-rules.md`](reference/detection-rules.md). Run all ten rules against every file. Write findings immediately to `<tmp>/inconsistency-audit-<timestamp>.csv`:
51
+
52
+ ```
53
+ file_path | line_number | rule_id | severity | what_is_wrong | what_it_should_be | evidence_path | evidence_detail
54
+ ```
55
+
56
+ ### Step 4: Produce summary
57
+
58
+ Print to stdout:
59
+
60
+ ```
61
+ ====== DIFF INCONSISTENCY AUDIT ======
62
+ Files audited: <N>
63
+ Canonical sources: <list>
64
+ Total findings: <N>
65
+
66
+ By rule:
67
+ Rule 1 — canonical_source_cross_reference: X (P0: A, P1: B, P2: C)
68
+ ...
69
+
70
+ By severity:
71
+ P0 (runtime failure): X
72
+ P1 (confusing or wrong): Y
73
+ P2 (cleanup): Z
74
+
75
+ Top findings:
76
+ 1. file:line — [P0] — what is wrong — what it should be
77
+ 2. ...
78
+
79
+ Full report: <tmp>/inconsistency-audit-<timestamp>.csv
80
+ Manifest: <tmp>/audit-manifest-<timestamp>.json
81
+ ====== END AUDIT ======
82
+ ```
83
+
84
+ ## Constraints
85
+
86
+ - Read every file completely. No skimming.
87
+ - Write findings immediately. Do not batch in memory.
88
+ - Every finding cites file:line of problem AND file:line of evidence.
89
+ - When two files contradict, flag both. Do not guess which is correct.
90
+ - If unresolvable, mark "unresolvable — no canonical source found."
91
+ - Run every rule. The highest-signal findings come from rules you think will be empty.
92
+
93
+ ## Severity
94
+
95
+ | Severity | Meaning |
96
+ |----------|---------|
97
+ | P0 | Runtime failure — the command or tool call will error |
98
+ | P1 | Confusing or wrong — will mislead but not crash |
99
+ | P2 | Cleanup — stale references, docs out of sync |
100
+
101
+ ## File index
102
+
103
+ | File | Purpose |
104
+ |------|---------|
105
+ | `SKILL.md` | Hub — process, constraints, gotchas |
106
+ | `reference/detection-rules.md` | All 10 detection rules with procedures |
107
+ | `reference/illustrations.md` | Concrete findings with why-they-matter explanations |
108
+
109
+ ## Folder map
110
+
111
+ - `SKILL.md` — hub.
112
+ - `reference/` — detection rules and illustrations.