claude-dev-env 2.9.0 → 2.11.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 (318) hide show
  1. package/CLAUDE.md +2 -2
  2. package/_shared/advisor/CLAUDE.md +3 -2
  3. package/_shared/advisor/advisor-protocol.md +74 -108
  4. package/_shared/advisor/reference/advisor-block.md +37 -0
  5. package/_shared/advisor/reference/cli-chain.md +45 -0
  6. package/_shared/advisor/reference/consult-format.md +41 -0
  7. package/_shared/advisor/reference/lifecycle.md +21 -0
  8. package/_shared/advisor/reference/sol-rung.md +31 -0
  9. package/_shared/advisor/reference/spawn-walk-log.md +31 -0
  10. package/_shared/advisor/reference/third-party-bind.md +30 -0
  11. package/_shared/advisor/reference/warm-up.md +33 -0
  12. package/_shared/advisor/scripts/codex_sol_advisor.py +449 -0
  13. package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +21 -0
  14. package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +19 -17
  15. package/_shared/advisor/scripts/config/advisor_scripts_constants/sol_advisor_constants.py +28 -0
  16. package/_shared/advisor/scripts/model_tier_run_validator.py +32 -9
  17. package/_shared/advisor/scripts/tests/test_codex_sol_advisor.py +474 -0
  18. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +79 -0
  19. package/_shared/advisor/scripts/tests/test_tier_model_ids.py +39 -17
  20. package/_shared/advisor/scripts/tier_model_ids.py +24 -0
  21. package/_shared/pr-loop/CLAUDE.md +1 -1
  22. package/_shared/pr-loop/audit-contract.md +17 -6
  23. package/_shared/pr-loop/audit-reply-template.md +4 -4
  24. package/_shared/pr-loop/code-rules-gate.md +3 -5
  25. package/_shared/pr-loop/fix-protocol.md +2 -3
  26. package/_shared/pr-loop/gh-payloads.md +1 -1
  27. package/_shared/pr-loop/scripts/CLAUDE.md +1 -1
  28. package/_shared/pr-loop/scripts/README.md +1 -1
  29. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -0
  30. package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +16 -1
  31. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +11 -5
  32. package/_shared/pr-loop/scripts/preflight.py +9 -4
  33. package/_shared/pr-loop/scripts/reviews_disabled.py +50 -22
  34. package/_shared/pr-loop/scripts/tests/conftest.py +20 -0
  35. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +6 -6
  36. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +50 -6
  37. package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +1 -1
  38. package/_shared/pr-loop/state-schema.md +5 -14
  39. package/agents/CLAUDE.md +2 -2
  40. package/agents/clean-coder.md +58 -548
  41. package/agents/code-quality-agent.md +10 -2
  42. package/agents/code-verifier.md +1 -1
  43. package/agents/test_agent_frontmatter.py +32 -40
  44. package/audit-rubrics/CLAUDE.md +2 -1
  45. package/audit-rubrics/audit-categories.json +704 -0
  46. package/audit-rubrics/prompts/category-i-concurrency.md +1 -1
  47. package/bin/CLAUDE.md +16 -5
  48. package/bin/ever-shipped-skills.mjs +2 -0
  49. package/bin/install-plan.mjs +402 -0
  50. package/bin/install-transaction.mjs +455 -0
  51. package/bin/install.mjs +593 -147
  52. package/bin/install.plan.test.mjs +194 -0
  53. package/bin/install.profile-root.test.mjs +154 -0
  54. package/bin/install.profiles.test.mjs +253 -0
  55. package/bin/install.settings-defaults.test.mjs +200 -0
  56. package/bin/install.transaction.test.mjs +400 -0
  57. package/bin/install.uninstall-transaction.test.mjs +418 -0
  58. package/bin/merge_managed_permissions.mjs +130 -0
  59. package/bin/resolve-install-root.mjs +181 -0
  60. package/bin/select-install-targets.mjs +401 -0
  61. package/commands/CLAUDE.md +0 -2
  62. package/docs/references/CLAUDE.md +3 -1
  63. package/docs/references/advisor-tool.md +25 -7
  64. package/docs/references/prose-style-enforcement.md +25 -0
  65. package/docs/references/team-advisor-skill.md +3 -3
  66. package/docs/references/weak-executor-advisor.md +91 -0
  67. package/hooks/blocking/CLAUDE.md +6 -6
  68. package/hooks/blocking/_path_setup.py +9 -5
  69. package/hooks/blocking/code_rules_docstrings.py +124 -30
  70. package/hooks/blocking/code_rules_enforcer.py +161 -16
  71. package/hooks/blocking/code_rules_shared.py +40 -23
  72. package/hooks/blocking/config/CLAUDE.md +3 -5
  73. package/hooks/blocking/config/prose_style_enforcement_constants.py +38 -0
  74. package/hooks/blocking/config/test_prose_style_enforcement_constants.py +45 -0
  75. package/hooks/blocking/eli11_reply_enforcer.py +70 -113
  76. package/hooks/blocking/hedging_language_blocker.py +103 -20
  77. package/hooks/blocking/hook_prose_detector_consistency.py +6 -0
  78. package/hooks/blocking/intent_only_ending_blocker.py +6 -0
  79. package/hooks/blocking/plain_language_blocker.py +139 -20
  80. package/hooks/blocking/pre_tool_use_dispatcher.py +102 -20
  81. package/hooks/blocking/state_description_blocker.py +7 -1
  82. package/hooks/blocking/tdd_enforcer.py +8 -0
  83. package/hooks/blocking/test__path_setup.py +28 -0
  84. package/hooks/blocking/test_code_rules_enforcer_agent_home_tooling.py +99 -0
  85. package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +232 -10
  86. package/hooks/blocking/test_code_rules_enforcer_ephemeral.py +1 -1
  87. package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +41 -0
  88. package/hooks/blocking/test_code_rules_enforcer_string_magic.py +98 -0
  89. package/hooks/blocking/test_eli11_reply_enforcer.py +98 -165
  90. package/hooks/blocking/test_fable_spawn_gate.py +18 -11
  91. package/hooks/blocking/test_hedging_language_blocker.py +120 -1
  92. package/hooks/blocking/test_hook_prose_detector_consistency.py +28 -8
  93. package/hooks/blocking/test_intent_only_ending_blocker.py +27 -2
  94. package/hooks/blocking/test_package_inventory_stale_blocker.py +11 -4
  95. package/hooks/blocking/test_plain_language_blocker.py +129 -19
  96. package/hooks/blocking/test_plain_language_blocker_allowlist.py +70 -26
  97. package/hooks/blocking/test_pre_tool_use_dispatcher.py +99 -26
  98. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +87 -50
  99. package/hooks/blocking/test_state_description_blocker.py +45 -2
  100. package/hooks/blocking/test_stop_dispatcher.py +11 -7
  101. package/hooks/blocking/test_volatile_path_in_post_blocker.py +12 -12
  102. package/hooks/blocking/volatile_path_in_post_blocker.py +2 -2
  103. package/hooks/hooks.json +15 -0
  104. package/hooks/hooks_constants/CLAUDE.md +14 -3
  105. package/hooks/hooks_constants/ask_user_question_shape.py +281 -0
  106. package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -1
  107. package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +5 -12
  108. package/hooks/hooks_constants/hedging_uncertainty_constants.py +42 -0
  109. package/hooks/hooks_constants/issue_tracker_session_starter_constants.py +23 -0
  110. package/hooks/hooks_constants/orchestrator_auto_starter_constants.py +23 -0
  111. package/hooks/hooks_constants/piped_pytest_blocker_constants.py +4 -1
  112. package/hooks/hooks_constants/plain_language_blocker_constants.py +4 -1
  113. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +6 -0
  114. package/hooks/hooks_constants/project_paths_reader.py +31 -4
  115. package/hooks/hooks_constants/prose_matcher_precision_constants.py +40 -0
  116. package/hooks/hooks_constants/pytest_invocation.py +354 -0
  117. package/hooks/hooks_constants/session_start_injector.py +163 -0
  118. package/hooks/hooks_constants/session_start_injector_constants.py +46 -0
  119. package/hooks/hooks_constants/shell_command_pipeline.py +397 -0
  120. package/hooks/hooks_constants/shell_command_segments.py +5 -0
  121. package/hooks/hooks_constants/test_ask_user_question_shape.py +167 -0
  122. package/hooks/hooks_constants/test_project_paths_reader.py +29 -0
  123. package/hooks/hooks_constants/test_prose_metrics_parity.py +8 -0
  124. package/hooks/hooks_constants/test_pytest_invocation.py +130 -0
  125. package/hooks/hooks_constants/test_session_start_injector.py +168 -0
  126. package/hooks/hooks_constants/test_shell_command_pipeline.py +135 -0
  127. package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +1 -1
  128. package/hooks/hooks_constants/working_style_prompt_constants.py +30 -0
  129. package/hooks/observability/CLAUDE.md +2 -0
  130. package/hooks/observability/prose_matcher_advisory.py +237 -0
  131. package/hooks/observability/test_prose_matcher_advisory.py +143 -0
  132. package/hooks/session/CLAUDE.md +9 -1
  133. package/hooks/session/_path_setup.py +13 -0
  134. package/hooks/session/issue_tracker_session_starter.py +135 -0
  135. package/hooks/session/orchestrator_auto_starter.py +100 -0
  136. package/hooks/session/test__path_setup.py +28 -0
  137. package/hooks/session/test_issue_tracker_session_starter.py +104 -0
  138. package/hooks/session/test_orchestrator_auto_starter.py +99 -0
  139. package/hooks/session/test_working_style_prompt.py +47 -0
  140. package/hooks/session/untracked_repo_detector.py +1 -24
  141. package/hooks/session/working_style_prompt.py +36 -0
  142. package/hooks/validators/_path_setup.py +19 -0
  143. package/hooks/validators/run_all_validators.py +8 -13
  144. package/installable-surfaces.manifest.json +21 -0
  145. package/output-styles/CLAUDE.md +1 -3
  146. package/package.json +4 -2
  147. package/rules/CLAUDE.md +1 -0
  148. package/rules/durable-post-artifacts.md +2 -2
  149. package/rules/eli11-replies.md +6 -1
  150. package/rules/hedging-claims.md +4 -2
  151. package/rules/long-horizon-autonomy.md +3 -1
  152. package/rules/opus5-communication-contract.md +45 -0
  153. package/rules/plain-language.md +2 -2
  154. package/rules/research-mode.md +1 -1
  155. package/scripts/CLAUDE.md +11 -0
  156. package/scripts/Sync-RepoMain.ps1 +215 -0
  157. package/scripts/active_capability_references.py +218 -0
  158. package/scripts/ci/windows-installer-lifecycle.ps1 +78 -0
  159. package/scripts/claude_chain_runner.py +394 -6
  160. package/scripts/claude_chain_usage.py +1 -1
  161. package/scripts/codex_compat_materializer.py +105 -85
  162. package/scripts/dev_env_scripts_constants/CLAUDE.md +2 -0
  163. package/scripts/dev_env_scripts_constants/active_capability_constants.py +46 -0
  164. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +74 -0
  165. package/scripts/dev_env_scripts_constants/verify_installable_package_constants.py +116 -0
  166. package/scripts/profile-isolation-launchers/config/mcp-bundles.json +25 -0
  167. package/scripts/profile-isolation-launchers/config/profile-isolation-constants.mjs +60 -0
  168. package/scripts/profile-isolation-launchers/config/profiles.manifest.json +54 -0
  169. package/scripts/profile-isolation-launchers/config/shared-allowlist.json +64 -0
  170. package/scripts/profile-isolation-launchers/launcher-runtime.mjs +180 -0
  171. package/scripts/profile-isolation-launchers/lib/profile-manifest.mjs +288 -0
  172. package/scripts/profile-isolation-launchers/mcp-bundles.mjs +275 -0
  173. package/scripts/profile-isolation-launchers/profile-isolation-contract.test.mjs +221 -0
  174. package/scripts/profile-isolation-launchers/tests/launcher-runtime.test.mjs +108 -0
  175. package/scripts/profile-isolation-launchers/tests/mcp-bundles.test.mjs +147 -0
  176. package/scripts/profile-isolation-launchers/tests/shortcut-contract.test.ps1 +102 -0
  177. package/scripts/profile-isolation-launchers/tests/version-compatibility.test.mjs +210 -0
  178. package/scripts/profile-isolation-launchers/version-compatibility.mjs +299 -0
  179. package/scripts/profile-isolation-launchers/windows/shortcut-inventory.ps1 +127 -0
  180. package/scripts/profile-isolation-launchers/windows/shortcut-manifest.json +51 -0
  181. package/scripts/profile-isolation-launchers/windows/shortcut-reconcile.ps1 +77 -0
  182. package/scripts/spawn_grok_batch.py +3 -0
  183. package/scripts/test_active_capability_references.py +108 -0
  184. package/scripts/test_claude_chain_runner.py +414 -82
  185. package/scripts/test_claude_chain_usage.py +12 -12
  186. package/scripts/test_resolve_worker_spawn.py +2 -2
  187. package/scripts/test_verify_installable_package.py +208 -0
  188. package/scripts/tests/test_codex_compat_materializer.py +33 -0
  189. package/scripts/verify_installable_package.py +612 -0
  190. package/settings.json +10 -0
  191. package/skills/CLAUDE.md +2 -0
  192. package/skills/_shared/advisor/CLAUDE.md +1 -1
  193. package/skills/_shared/advisor/scripts/README.md +2 -0
  194. package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -0
  195. package/skills/_shared/pr-loop/scripts/audit_category_schema.py +355 -0
  196. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
  197. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +32 -0
  198. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +7 -19
  199. package/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +94 -0
  200. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +21 -0
  201. package/skills/autoconverge/reference/convergence.md +2 -1
  202. package/skills/autoconverge/reference/stop-conditions.md +5 -3
  203. package/skills/beat-sheet/SKILL.md +54 -0
  204. package/skills/beat-sheet/reference/visual-beats.md +29 -0
  205. package/skills/bugteam/CONSTRAINTS.md +4 -4
  206. package/skills/bugteam/EXAMPLES.md +1 -1
  207. package/skills/bugteam/reference/README.md +1 -1
  208. package/skills/e-code-review/SKILL.md +26 -5
  209. package/skills/e-code-review/reference/effort-evaluation.md +35 -0
  210. package/skills/e-code-review/reference/medium.md +15 -4
  211. package/skills/e-code-review/scripts/config/e_code_review_effort_constants/__init__.py +41 -0
  212. package/skills/e-code-review/scripts/config/e_code_review_effort_constants/effort_constants.py +40 -0
  213. package/skills/e-code-review/scripts/e_code_review_scripts_constants/finding_pipeline_constants.py +49 -0
  214. package/skills/e-code-review/scripts/effort_defaults_evidence.json +186 -0
  215. package/skills/e-code-review/scripts/effort_evaluation.py +362 -0
  216. package/skills/e-code-review/scripts/finding_pipeline.py +140 -0
  217. package/skills/e-code-review/scripts/fixtures/demanding.json +26 -0
  218. package/skills/e-code-review/scripts/fixtures/easy.json +14 -0
  219. package/skills/e-code-review/scripts/fixtures/medium.json +20 -0
  220. package/skills/e-code-review/scripts/grok_code_review.py +16 -7
  221. package/skills/e-code-review/scripts/test_effort_evaluation.py +180 -0
  222. package/skills/e-code-review/scripts/test_finding_pipeline.py +197 -0
  223. package/skills/e-code-review/scripts/test_grok_code_review.py +77 -0
  224. package/skills/grokify/SKILL.md +1 -1
  225. package/skills/grokify/templates/handoff-template.md +2 -2
  226. package/skills/orchestrator/SKILL.md +5 -4
  227. package/skills/plan-to-pr/scripts/create_packet.py +4 -4
  228. package/skills/plan-to-pr/scripts/load_skill_constants.py +41 -0
  229. package/skills/plan-to-pr/scripts/validate_packet.py +4 -4
  230. package/skills/plan-to-pr/scripts/validate_protocol.py +4 -1
  231. package/skills/plan-to-pr/scripts/validate_run.py +4 -1
  232. package/skills/pr-converge/scripts/check_convergence.py +21 -19
  233. package/skills/pr-converge/scripts/check_convergence_availability.py +50 -7
  234. package/skills/pr-converge/scripts/conftest.py +35 -0
  235. package/skills/pr-converge/scripts/test_check_convergence_availability.py +65 -0
  236. package/skills/pr-converge/scripts/test_check_convergence_codex.py +11 -1
  237. package/skills/pr-converge/scripts/test_check_convergence_contract.py +9 -2
  238. package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
  239. package/skills/rebase/SKILL.md +15 -3
  240. package/skills/reviewer-gates/SKILL.md +2 -2
  241. package/skills/show/SKILL.md +51 -0
  242. package/skills/show/references/accessibility.md +7 -0
  243. package/skills/show/references/art.md +3 -0
  244. package/skills/show/references/charts.md +3 -0
  245. package/skills/show/references/core-design.md +14 -0
  246. package/skills/show/references/erds.md +3 -0
  247. package/skills/show/references/flowcharts.md +3 -0
  248. package/skills/show/references/host-and-html.md +3 -0
  249. package/skills/show/references/illustrative-diagrams.md +10 -0
  250. package/skills/show/references/interaction.md +3 -0
  251. package/skills/show/references/mockups.md +3 -0
  252. package/skills/show/references/quality-gates.md +7 -0
  253. package/skills/show/references/structural-diagrams.md +3 -0
  254. package/skills/show/references/subject-inventory.md +21 -0
  255. package/skills/show/references/svg-contract.md +22 -0
  256. package/skills/show/routing.yaml +30 -0
  257. package/skills/show/samples/pr1262-v2.svg +222 -0
  258. package/skills/show/scripts/README.md +6 -0
  259. package/skills/show/scripts/validate-artifact.py +91 -0
  260. package/skills/show/scripts/validate-package.py +18 -0
  261. package/skills/show/templates/html-widget.html +4 -0
  262. package/skills/show/templates/svg-base.svg +19 -0
  263. package/skills/show/tests/fixtures/css-var.svg +6 -0
  264. package/skills/show/tests/fixtures/dead-ref.svg +7 -0
  265. package/skills/show/tests/fixtures/filled-glyph.svg +8 -0
  266. package/skills/show/tests/fixtures/inherited-fill.svg +18 -0
  267. package/skills/show/tests/fixtures/invalid.svg +1 -0
  268. package/skills/show/tests/fixtures/large-canvas.svg +21 -0
  269. package/skills/show/tests/fixtures/unfilled-connector.svg +15 -0
  270. package/skills/show/tests/fixtures/valid.html +1 -0
  271. package/skills/show/tests/test_validate-artifact.py +74 -0
  272. package/skills/show/tests/test_validators.py +59 -0
  273. package/skills/show/workflows/create-visual.md +13 -0
  274. package/skills/show/workflows/review-visual.md +20 -0
  275. package/skills/split-pr/SKILL.md +85 -0
  276. package/skills/split-pr/reference/path-layers.md +16 -0
  277. package/skills/split-pr/reference/proposal-format.md +15 -0
  278. package/skills/split-pr/reference/split-further-loop.md +10 -0
  279. package/skills/split-pr/reference/splitting-principles.md +26 -0
  280. package/skills/split-pr/scripts/analyze_pr.py +279 -0
  281. package/skills/split-pr/scripts/categorize_files.py +106 -0
  282. package/skills/split-pr/scripts/config/__init__.py +1 -0
  283. package/skills/split-pr/scripts/config/dependency_constants.py +14 -0
  284. package/skills/split-pr/scripts/config/git_operations_constants.py +36 -0
  285. package/skills/split-pr/scripts/config/packing_constants.py +61 -0
  286. package/skills/split-pr/scripts/config/plan_constants.py +49 -0
  287. package/skills/split-pr/scripts/config/split_pr_constants.py +110 -0
  288. package/skills/split-pr/scripts/execute_split_slices.py +82 -0
  289. package/skills/split-pr/scripts/pack_files_into_slices.py +212 -0
  290. package/skills/split-pr/scripts/split_pr_dependency_graph.py +70 -0
  291. package/skills/split-pr/scripts/split_pr_git_operations.py +184 -0
  292. package/skills/split-pr/scripts/split_pr_layer_order.py +58 -0
  293. package/skills/split-pr/scripts/split_pr_paginate.py +119 -0
  294. package/skills/split-pr/scripts/split_pr_process_runner.py +52 -0
  295. package/skills/split-pr/scripts/split_pr_script_types.py +126 -0
  296. package/skills/split-pr/scripts/split_pr_title.py +41 -0
  297. package/skills/split-pr/scripts/test_analyze_pr.py +228 -0
  298. package/skills/split-pr/scripts/test_categorize_files.py +55 -0
  299. package/skills/split-pr/scripts/test_categorize_files_packing.py +59 -0
  300. package/skills/split-pr/scripts/test_execute_split_slices.py +99 -0
  301. package/skills/split-pr/scripts/test_split_pr_dependency_graph.py +47 -0
  302. package/skills/split-pr/scripts/test_split_pr_git_operations.py +125 -0
  303. package/skills/split-pr/scripts/test_split_pr_layer_order.py +36 -0
  304. package/skills/split-pr/scripts/test_split_pr_paginate.py +65 -0
  305. package/skills/split-pr/scripts/test_split_pr_script_types.py +73 -0
  306. package/skills/split-pr/scripts/test_split_pr_title.py +28 -0
  307. package/skills/split-pr/scripts/test_verify_dependency_graph.py +46 -0
  308. package/skills/split-pr/scripts/test_verify_plan.py +56 -0
  309. package/skills/split-pr/scripts/test_verify_plan_contract.py +50 -0
  310. package/skills/split-pr/scripts/test_verify_plan_path_normalization.py +45 -0
  311. package/skills/split-pr/scripts/verify_dependency_graph.py +111 -0
  312. package/skills/split-pr/scripts/verify_plan.py +139 -0
  313. package/skills/team-advisor/SKILL.md +7 -4
  314. package/skills/team-advisor/reference/advisor-docs-review.md +207 -0
  315. package/system-prompts/software-engineer.xml +11 -2
  316. package/commands/initialize.md +0 -90
  317. package/commands/stubcheck.md +0 -88
  318. package/output-styles/caveman-agent.md +0 -37
@@ -16,17 +16,16 @@ Each bypass flag closes one reviewer gate when that reviewer is unavailable.
16
16
  the Copilot review and pending-review gates. ``--bugteam-post-blocked`` skips
17
17
  the bugteam CLEAN-review gate. ``--codex-down`` skips the Codex review gate.
18
18
 
19
- Each flag also honors its own reviews-disabled token: "bugbot", "copilot",
20
- "bugteam", or "codex". A caller that cannot pass the flag reaches the same
21
- bypass by exporting the token. The mark-ready blocker hook re-runs this script
22
- with no flags, so its convergence re-check reads the bypass from the exported
23
- token instead. For Codex, sticky job-dir state ``codex_down: true`` is a third
24
- bypass source when the original run could not re-pass ``--codex-down``.
25
-
26
- Copilot and Bugbot waivers are disk-authoritative.
19
+ Bugbot, bugteam, and codex are off by default. Each gate runs only when
20
+ ``CLAUDE_REVIEWS_ENABLED`` lists its token, and a token in
21
+ ``CLAUDE_REVIEWS_DISABLED`` forces one off even when the opt-in lists it.
22
+ Copilot runs by default and stops only when the disabled list names it. For
23
+ Codex, sticky job-dir state ``codex_down: true`` is a further bypass source
24
+ when the original run could not re-pass ``--codex-down``.
25
+
26
+ Every reviewer waiver is disk-authoritative.
27
27
  When ``~/.claude/settings.json`` is readable, its env block is the single source.
28
28
  The frozen process env is only a fallback when that disk read fails (logged once).
29
- Bugteam's opt-out is env-only via ``_resolve_bugteam_post_blocked``.
30
29
  A probe error does not waive the gate; the live GitHub checks still run.
31
30
 
32
31
  The Codex gate is conditional-required: it demands
@@ -105,11 +104,11 @@ from pr_converge_skill_constants.constants import (
105
104
  )
106
105
  from reviews_disabled import (
107
106
  is_bugbot_disabled_via_env,
108
- is_bugteam_disabled_via_env,
109
- is_codex_disabled_via_env,
110
107
  is_copilot_disabled_via_env,
111
108
  )
112
109
  from check_convergence_availability import (
110
+ _is_bugteam_disabled_via_resolved_settings,
111
+ _is_codex_disabled_via_resolved_settings,
113
112
  _resolve_bugbot_waiver,
114
113
  _resolve_copilot_waiver,
115
114
  _waiver_from_cli_flag,
@@ -815,18 +814,21 @@ def _resolve_copilot_down(is_copilot_down_flag: bool) -> bool:
815
814
 
816
815
 
817
816
  def _resolve_bugteam_post_blocked(is_bugteam_post_blocked_flag: bool) -> bool:
818
- """Combine the --bugteam-post-blocked flag with the bugteam env opt-out.
817
+ """Combine the --bugteam-post-blocked flag with the resolved bugteam opt-in.
819
818
 
820
819
  ::
821
820
 
822
- flag True, env unset -> True (caller passed the flag)
823
- flag False, reviews-disabled lists bugteam -> True (exported token)
824
- flag False, env unset -> False (gate runs)
821
+ flag True -> True (caller passed the flag)
822
+ flag False, reviews-enabled lists bugteam -> False (gate runs)
823
+ flag False, neither list names bugteam -> True (off by default)
824
+ flag False, reviews-disabled lists bugteam -> True (opt-out wins)
825
825
 
826
- The mark-ready blocker hook re-runs this script with no flags, so the env
827
- fallback lets an exported bugteam token carry the bypass into that re-check.
826
+ Bugteam is off by default and runs only on an explicit opt-in. Settings on
827
+ disk are the source when readable, so a settings.json opt-in reaches the
828
+ mark-ready blocker hook, which re-runs this script with no flags. The
829
+ process env is the fallback when that disk read fails.
828
830
  """
829
- return is_bugteam_post_blocked_flag or is_bugteam_disabled_via_env()
831
+ return is_bugteam_post_blocked_flag or _is_bugteam_disabled_via_resolved_settings()
830
832
 
831
833
 
832
834
  def _resolve_codex_down(
@@ -854,7 +856,7 @@ def _resolve_codex_down(
854
856
  """
855
857
  return (
856
858
  is_codex_down_flag
857
- or is_codex_disabled_via_env()
859
+ or _is_codex_disabled_via_resolved_settings()
858
860
  or _read_codex_down_from_job_state(all_job_state_fields)
859
861
  )
860
862
 
@@ -45,6 +45,8 @@ from pr_loop_shared_constants.copilot_quota_constants import (
45
45
  )
46
46
  from pr_loop_shared_constants.reviews_disabled_constants import (
47
47
  CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN,
48
+ CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN,
49
+ CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN,
48
50
  CLAUDE_REVIEWS_DISABLED_COPILOT_TOKEN,
49
51
  CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME,
50
52
  CLAUDE_REVIEWS_DISABLED_TOKEN_SEPARATOR,
@@ -120,8 +122,15 @@ def _log_disk_settings_fallback_once() -> None:
120
122
  )
121
123
 
122
124
 
125
+ @functools.lru_cache(maxsize=1)
123
126
  def _resolve_reviews_settings() -> _ReviewsSettings:
124
- """Return disabled and enabled tokens from disk, or env when disk is unreadable."""
127
+ """Return disabled and enabled tokens from disk, or env when disk is unreadable.
128
+
129
+ Cached for the process. Four reviewer gates ask for these tokens in one
130
+ run, and settings cannot change under a running check, so the disk read
131
+ and JSON parse happen once. A test that rebinds the settings path calls
132
+ ``_resolve_reviews_settings.cache_clear()`` first.
133
+ """
125
134
  all_disk_env_entries = _try_read_disk_env_block()
126
135
  if all_disk_env_entries is not None:
127
136
  return _ReviewsSettings(
@@ -147,18 +156,52 @@ def _is_copilot_disabled_via_resolved_settings() -> bool:
147
156
  )
148
157
 
149
158
 
159
+ def _is_off_by_default_reviewer_disabled(reviewer_token: str) -> bool:
160
+ """Return True when the resolved settings leave an opt-in reviewer off.
161
+
162
+ ::
163
+
164
+ enabled names the token, disabled empty -> False (gate runs)
165
+ neither list names the token -> True (off by default)
166
+ both lists name the token -> True (opt-out wins)
167
+
168
+ Args:
169
+ reviewer_token: The lowercase reviewer token to look up in both lists.
170
+
171
+ Returns:
172
+ True when the reviewer stays off for this run.
173
+ """
174
+ reviews_settings = _resolve_reviews_settings()
175
+ is_opted_out = reviewer_token in reviews_settings.disabled_tokens
176
+ is_opted_in = reviewer_token in reviews_settings.enabled_tokens
177
+ return is_opted_out or not is_opted_in
178
+
179
+
150
180
  def _is_bugbot_disabled_via_resolved_settings() -> bool:
151
181
  """Return True when the resolved settings disable the bugbot reviewer.
152
182
 
153
183
  Bugbot is off by default. It is disabled when the disabled list names it, or
154
184
  when the enabled list does not name it.
155
185
  """
156
- reviews_settings = _resolve_reviews_settings()
157
- is_opted_out = (
158
- CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN in reviews_settings.disabled_tokens
159
- )
160
- is_opted_in = CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN in reviews_settings.enabled_tokens
161
- return is_opted_out or not is_opted_in
186
+ return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN)
187
+
188
+
189
+ def _is_bugteam_disabled_via_resolved_settings() -> bool:
190
+ """Return True when the resolved settings disable the bug-audit family.
191
+
192
+ Bugteam is off by default. It is disabled when the disabled list names it,
193
+ or when the enabled list does not name it.
194
+ """
195
+ return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN)
196
+
197
+
198
+ def _is_codex_disabled_via_resolved_settings() -> bool:
199
+ """Return True when the resolved settings disable the Codex reviewer.
200
+
201
+ Codex is off by default. It is disabled when the disabled list names it, or
202
+ when the enabled list does not name it.
203
+ """
204
+ return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN)
162
205
 
163
206
 
164
207
  def _unavailable_note(reviewer_token: str, message: str) -> str:
@@ -3,6 +3,41 @@
3
3
  import sys
4
4
  from pathlib import Path
5
5
 
6
+ import pytest
7
+
6
8
  _scripts_directory = Path(__file__).resolve().parent
7
9
  if str(_scripts_directory) not in sys.path:
8
10
  sys.path.insert(0, str(_scripts_directory))
11
+
12
+ import check_convergence_availability # noqa: E402
13
+ from pr_loop_shared_constants.reviews_disabled_constants import ( # noqa: E402
14
+ CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN,
15
+ CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN,
16
+ CLAUDE_REVIEWS_DISABLED_TOKEN_SEPARATOR,
17
+ CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME,
18
+ )
19
+
20
+ _MISSING_SETTINGS_PATH = Path("settings-absent-in-tests.json")
21
+
22
+
23
+ @pytest.fixture(autouse=True)
24
+ def opt_gated_reviewers_in(monkeypatch: pytest.MonkeyPatch) -> None:
25
+ """Point settings at an absent file and opt bugteam and codex in.
26
+
27
+ Bugteam and codex are off by default, and the resolver reads the real
28
+ ``~/.claude/settings.json`` first. Both together would decide these cases
29
+ from whatever the host machine has on disk. Aiming the resolver at an
30
+ absent path restores the env fallback, and the opt-in lets each case reach
31
+ the gate it was written for. A case that tests the lists themselves
32
+ overrides this from its own body.
33
+ """
34
+ check_convergence_availability._resolve_reviews_settings.cache_clear()
35
+ monkeypatch.setattr(
36
+ check_convergence_availability,
37
+ "get_claude_user_settings_path",
38
+ lambda: _MISSING_SETTINGS_PATH,
39
+ )
40
+ all_opted_in_tokens = CLAUDE_REVIEWS_DISABLED_TOKEN_SEPARATOR.join(
41
+ (CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN, CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN)
42
+ )
43
+ monkeypatch.setenv(CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME, all_opted_in_tokens)
@@ -86,6 +86,7 @@ def _write_settings(
86
86
  def _reset_probe_cache_and_env(monkeypatch: pytest.MonkeyPatch) -> None:
87
87
  availability._probe_copilot_quota.cache_clear()
88
88
  availability._log_disk_settings_fallback_once.cache_clear()
89
+ availability._resolve_reviews_settings.cache_clear()
89
90
  monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
90
91
  monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
91
92
  monkeypatch.setattr(
@@ -324,3 +325,67 @@ def should_probe_copilot_when_neither_flag_env_nor_disk_disable_it(
324
325
  waiver = availability._resolve_copilot_waiver(False)
325
326
  assert waiver.is_waived is True
326
327
  assert waiver.bypass_note == "copilot unavailable: quota exhausted"
328
+
329
+
330
+ def should_disable_bugteam_when_neither_disk_list_names_it(
331
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path
332
+ ) -> None:
333
+ settings_path = _write_settings(
334
+ tmp_path, reviews_disabled_value="", reviews_enabled_value=""
335
+ )
336
+ monkeypatch.setattr(
337
+ availability, "get_claude_user_settings_path", lambda: settings_path
338
+ )
339
+ assert availability._is_bugteam_disabled_via_resolved_settings() is True
340
+
341
+
342
+ def should_enable_bugteam_when_disk_enables_it_even_if_env_omits_opt_in(
343
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path
344
+ ) -> None:
345
+ monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
346
+ settings_path = _write_settings(
347
+ tmp_path, reviews_disabled_value="", reviews_enabled_value="bugteam"
348
+ )
349
+ monkeypatch.setattr(
350
+ availability, "get_claude_user_settings_path", lambda: settings_path
351
+ )
352
+ assert availability._is_bugteam_disabled_via_resolved_settings() is False
353
+
354
+
355
+ def should_disable_bugteam_when_disk_disables_and_enables_it(
356
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path
357
+ ) -> None:
358
+ settings_path = _write_settings(
359
+ tmp_path, reviews_disabled_value="bugteam", reviews_enabled_value="bugteam"
360
+ )
361
+ monkeypatch.setattr(
362
+ availability, "get_claude_user_settings_path", lambda: settings_path
363
+ )
364
+ assert availability._is_bugteam_disabled_via_resolved_settings() is True
365
+
366
+
367
+ def should_disable_codex_when_neither_disk_list_names_it(
368
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path
369
+ ) -> None:
370
+ settings_path = _write_settings(
371
+ tmp_path, reviews_disabled_value="", reviews_enabled_value=""
372
+ )
373
+ monkeypatch.setattr(
374
+ availability, "get_claude_user_settings_path", lambda: settings_path
375
+ )
376
+ assert availability._is_codex_disabled_via_resolved_settings() is True
377
+
378
+
379
+ def should_enable_codex_when_disk_enables_it_even_if_env_omits_opt_in(
380
+ monkeypatch: pytest.MonkeyPatch, tmp_path: Path
381
+ ) -> None:
382
+ monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
383
+ settings_path = _write_settings(
384
+ tmp_path, reviews_disabled_value="", reviews_enabled_value="codex"
385
+ )
386
+ monkeypatch.setattr(
387
+ availability, "get_claude_user_settings_path", lambda: settings_path
388
+ )
389
+ assert availability._is_codex_disabled_via_resolved_settings() is False
390
+
391
+
@@ -370,7 +370,7 @@ def should_resolve_codex_down_true_when_env_disables_codex(
370
370
  ) is True
371
371
 
372
372
 
373
- def should_resolve_codex_down_false_when_flag_unset_and_env_empty(
373
+ def should_resolve_codex_down_false_when_flag_unset_and_codex_opted_in(
374
374
  monkeypatch: pytest.MonkeyPatch,
375
375
  ) -> None:
376
376
  monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
@@ -380,6 +380,16 @@ def should_resolve_codex_down_false_when_flag_unset_and_env_empty(
380
380
  ) is False
381
381
 
382
382
 
383
+ def should_resolve_codex_down_true_when_neither_list_names_codex(
384
+ monkeypatch: pytest.MonkeyPatch,
385
+ ) -> None:
386
+ monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
387
+ monkeypatch.delenv("CLAUDE_JOB_DIR", raising=False)
388
+ assert check_convergence._resolve_codex_down(
389
+ False, check_convergence._read_job_state()
390
+ ) is True
391
+
392
+
383
393
  def should_resolve_codex_down_true_when_job_state_sticky_down(
384
394
  tmp_path: Path,
385
395
  monkeypatch: pytest.MonkeyPatch,
@@ -294,14 +294,21 @@ def test_resolve_bugteam_post_blocked_true_when_env_disables_bugteam(
294
294
  assert check_convergence._resolve_bugteam_post_blocked(False) is True
295
295
 
296
296
 
297
- def test_resolve_bugteam_post_blocked_false_when_flag_unset_and_env_empty(
297
+ def test_resolve_bugteam_post_blocked_false_when_flag_unset_and_bugteam_opted_in(
298
298
  monkeypatch: pytest.MonkeyPatch,
299
299
  ) -> None:
300
300
  monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
301
301
  assert check_convergence._resolve_bugteam_post_blocked(False) is False
302
302
 
303
303
 
304
- def test_resolve_bugteam_post_blocked_false_when_env_disables_only_copilot(
304
+ def test_resolve_bugteam_post_blocked_true_when_neither_list_names_bugteam(
305
+ monkeypatch: pytest.MonkeyPatch,
306
+ ) -> None:
307
+ monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
308
+ assert check_convergence._resolve_bugteam_post_blocked(False) is True
309
+
310
+
311
+ def test_resolve_bugteam_post_blocked_false_when_opted_in_and_env_disables_copilot(
305
312
  monkeypatch: pytest.MonkeyPatch,
306
313
  ) -> None:
307
314
  monkeypatch.setenv("CLAUDE_REVIEWS_DISABLED", "copilot")
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pr-loop-cloud-transport
3
- description: Runs any PR-loop skill in a Claude Code session whose gh CLI cannot act on the PR. Use at run start when pr-converge, autoconverge, bugteam, qbug, findbugs, fixbugs, monitor-open-prs, or copilot-review runs in a cloud session, when `command -v gh` or `gh auth status` fails, or when an MCP tool call fails with InputValidationError.
3
+ description: Runs any PR-loop skill in a Claude Code session whose gh CLI cannot act on the PR. Use at run start when pr-converge, autoconverge, bugteam, clean-room audit, pr-fix-protocol, or copilot-review runs in a cloud session, when `command -v gh` or `gh auth status` fails, or when an MCP tool call fails with InputValidationError.
4
4
  ---
5
5
 
6
6
  # PR-loop cloud transport
@@ -93,7 +93,9 @@ When in doubt, ask. Both work; the choice affects history shape, not correctness
93
93
 
94
94
  ## Phase 3 — Verification gates (mandatory before push)
95
95
 
96
- `py_compile`, `tsc --noEmit`, `cargo check`, etc. validate **syntax and types**, not **import resolution and runtime correctness**. Run real checks:
96
+ `py_compile`, `tsc --noEmit`, `cargo check`, etc. validate **syntax and types**, not **import resolution and runtime correctness**. Run real checks.
97
+
98
+ Before each gate command, state in one line which gate it is and why it applies to this rebase ("post-rebase gate: `pkg_x` carried a conflict resolution, running its suite").
97
99
 
98
100
  8. **Real import check.** For Python:
99
101
 
@@ -105,7 +107,16 @@ When in doubt, ask. Both work; the choice affects history shape, not correctness
105
107
 
106
108
  9. **Test collection.** `pytest --collect-only -q` on the changed packages catches NameError, AttributeError, and ImportError surfaces beyond plain imports.
107
109
 
108
- 10. **Targeted test run.** Run the test suite for every package the rebase touched. Do not push a rebase that dropped or broke test coverage that was passing pre-rebase.
110
+ 10. **Targeted test run scoped by content diff.** First check, per candidate package, whether the rebase changed its content at all:
111
+
112
+ ```
113
+ git diff <pre-rebase-tip> HEAD -- <package>
114
+ ```
115
+
116
+ - **Empty diff:** the package's files are byte-for-byte what the branch already carried before the rebase, and that state was verified pre-rebase. The compile and collect-only gates (steps 8–9) cover the remaining import-level risk; skip the package's full suite.
117
+ - **Non-empty diff, a conflict resolution, or an auto-merged file (step 6) in the package:** run its full suite. Do not push a rebase that dropped or broke test coverage that was passing pre-rebase.
118
+
119
+ Capture the pre-rebase tip SHA before the rebase begins; step 15 pins the force-with-lease to that same SHA.
109
120
 
110
121
  11. **Reference scan for removals/renames.** For every symbol the rebase deleted or renamed (per the commit messages from step 4), scan the post-rebase tree using the same tool-preference order as step 4:
111
122
 
@@ -145,6 +156,7 @@ When in doubt, ask. Both work; the choice affects history shape, not correctness
145
156
  - **Auditing only `git diff --name-only`.** Files unchanged by the rebase can still break if their imports depended on what the rebase removed.
146
157
  - **Force-pushing under "the user asked me to fix the conflicts" interpretation.** Force-push is a separate authorization from "fix this." Ask.
147
158
  - **Bare `--force` instead of `--force-with-lease=<branch>:<sha>`.** Loses the safety net against concurrent pushes.
159
+ - **Running full suites for packages the rebase left byte-for-byte the same.** The step-10 content diff settles it in seconds; a long suite on unchanged content stalls the session.
148
160
 
149
161
  ## Quick decision flowchart
150
162
 
@@ -157,7 +169,7 @@ Solo, ≤5 commits ahead? ──► straight rebase
157
169
  After rebase, BEFORE push:
158
170
  python -c "import …" ──► must succeed
159
171
  pytest --collect-only ──► must succeed
160
- targeted pytest run ──► must pass
172
+ pytest, packages w/ diff ──► must pass
161
173
  symbol scan (serena → Grep) ──► no stale references
162
174
 
163
175
  Push:
@@ -16,7 +16,7 @@ description: >-
16
16
  - **Skill-capable contexts** (a lead session with the `Skill` tool): `Skill({skill: "reviewer-gates", args: "--skill <caller> <gate> [gate parameters]"})`.
17
17
  - **Fallback** (a subagent or teammate without the `Skill` tool): the caller's spawn prompt says "Read `~/.claude/skills/reviewer-gates/SKILL.md` and apply the `<gate>` section with the parameters below."
18
18
 
19
- Every invocation carries the caller's identity (`--skill <caller>`, e.g. `pr-converge`, `qbug`). The refusal line in Gate 1 and every logged decision names the caller, so a multi-skill session's transcript shows which loop each gate served.
19
+ Every invocation carries the caller's identity (`--skill <caller>`, e.g. `pr-converge`, `bugteam`). The refusal line in Gate 1 and every logged decision names the caller, so a multi-skill session's transcript shows which loop each gate served.
20
20
 
21
21
  ## Gate 1: Reviewer opt-out (`CLAUDE_REVIEWS_DISABLED`)
22
22
 
@@ -24,7 +24,7 @@ The `CLAUDE_REVIEWS_DISABLED` environment variable is a comma-separated token li
24
24
 
25
25
  | Token | Disables |
26
26
  |---|---|
27
- | `bugteam` | The whole bug-audit family: `/bugteam`, `/qbug`, `/findbugs`, and audit dispatch in `/monitor-open-prs` |
27
+ | `bugteam` | The whole bug-audit family: `/bugteam`, `clean-room audit (code-quality-agent)`, and audit dispatch in `/pr-converge` |
28
28
  | `bugbot` | Cursor Bugbot triggering and polling |
29
29
  | `copilot` | GitHub Copilot review requests and polling |
30
30
  | `codex` | Codex reviewer requests and polling |
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: show
3
+ description: Create and review inline visual explanations, diagrams, interactive widgets, mockups, charts, and illustrations. Triggers on "/show", "show me", "draw", "diagram this", "visualize", "map this out", "make it interactive", or a request for a mockup, chart, or illustration.
4
+ ---
5
+
6
+ # Show
7
+
8
+ Use this skill when a user asks to show, draw, map, visualize, explain visually, or build an interactive visual.
9
+
10
+ ## Routes
11
+
12
+ Pick the row whose intent matches the request, then follow `workflows/create-visual.md`.
13
+
14
+ | Intent | Route |
15
+ |---|---|
16
+ | Steps, decisions, lifecycle, transformation | `flowchart` |
17
+ | Architecture, containment, hierarchy | `structural` |
18
+ | Mechanism, intuition, spatial metaphor | `illustrative` |
19
+ | Entity or class relationships | `erd` |
20
+ | Controls that change a visual explanation | `interactive` |
21
+ | UI surface, form, card, dashboard | `mockup` |
22
+ | Quantitative or geographic data | `chart` |
23
+ | Illustration or generative art | `art` |
24
+
25
+ Each route's references and template live in `routing.yaml`; the template sets the output type.
26
+
27
+ ## Invariants
28
+
29
+ - Design, palette, and color meaning follow `references/core-design.md`.
30
+ - SVG output follows `references/svg-contract.md`; HTML output follows `references/host-and-html.md`.
31
+ - Prefer multiple focused visuals over one dense canvas, and keep explanatory prose outside the visual.
32
+ - Keep one diagram family per visual.
33
+ - When the visual shows code, a diff, or a plan that lives in a repo, read the real lines and tie every arrow to a `path:line` citation before drawing. When the picture and the source disagree, the picture is wrong.
34
+ - `samples/` holds good examples the user has picked out. Read them on demand to study what works; the rules stay in the references.
35
+
36
+ ## Workflows
37
+
38
+ - New visual: `workflows/create-visual.md`
39
+ - Review or repair: `workflows/review-visual.md`
40
+
41
+ ## Validation
42
+
43
+ Run from any working directory:
44
+
45
+ ```text
46
+ python <skill-root>/scripts/validate-package.py
47
+ python <skill-root>/scripts/validate-artifact.py <artifact>
48
+ ```
49
+
50
+ The package is complete only when package checks, artifact checks, and rendered inspection all pass.
51
+
@@ -0,0 +1,7 @@
1
+ # Accessibility
2
+
3
+ Interactive controls have accessible names and visible focus. Decorative icons use `aria-hidden="true"`.
4
+
5
+ SVG roots use `role="img"`. Text remains readable in light and dark modes. Color never carries meaning without a label, shape, position, or legend.
6
+
7
+ The hidden summary heading each HTML widget opens with is set in `references/host-and-html.md`; the `<title>` and `<desc>` order each SVG opens with is set in `references/svg-contract.md`.
@@ -0,0 +1,3 @@
1
+ # Art
2
+
3
+ Use art for illustration and generative composition. Keep the requested subject and style clear. Provide accessible surrounding prose when the image itself cannot expose equivalent meaning.
@@ -0,0 +1,3 @@
1
+ # Charts
2
+
3
+ Choose a chart by the question the data answers. Label axes and units, preserve truthful scale, and provide a text summary for key findings. Use color for categories or emphasis rather than decoration.
@@ -0,0 +1,14 @@
1
+ # Core design
2
+
3
+ Use flat surfaces, transparent outer containers, sentence case, the 16-at-680 scaled text floor set in `references/svg-contract.md`, and weights 400 or 500. Keep visible prose outside the visual. Use no decorative gradients, glow, blur, noise, or drop shadows. Use no emoji. Keep a visual compact and split it when labels or relationships become hard to read.
4
+
5
+ ## Color
6
+
7
+ Color is the default, in the style of `samples/`: pick a palette of three to four named hues (for example a red, a green, an amber) plus neutral grays and near-black text, and use it throughout the visual.
8
+
9
+ - Paint category and state surfaces with light tinted fills of the palette hues (for example `#DFF0E4` under a `#1E8449` stroke), with white or warm-white cards for plain content.
10
+ - Draw strokes and text in strong fixed colors: near-black `#1A1A1A` for primary text, mid-gray for secondary, a palette hue for anything whose color carries meaning.
11
+ - Use each hue for one meaning and keep that meaning consistent across the visual; a short legend explains any pairing the reader cannot work out alone.
12
+ - The palette is fixed rather than host-derived, so every SVG owns its background rect — see `references/svg-contract.md`.
13
+ - Keep contrast strong: text and strokes hold up against the fill behind them.
14
+ - Reserve a monochrome outline style for the rare case the user asks for it.
@@ -0,0 +1,3 @@
1
+ # Entity relationship diagrams
2
+
3
+ Use an embeddable HTML or SVG ERD. Show entities, key fields, and cardinality. Keep relationship labels short and avoid crossing unrelated entities.
@@ -0,0 +1,3 @@
1
+ # Flowcharts
2
+
3
+ Use one direction, top-to-bottom or left-to-right. Keep a diagram to four or five primary nodes. Use at least 20 units between peer boxes and route arrows around obstacles. Use a stepper for a multi-stage cycle with per-stage detail.
@@ -0,0 +1,3 @@
1
+ # HTML host contract
2
+
3
+ Return an embeddable fragment without `doctype`, `html`, `head`, or `body`. Begin with the hidden summary heading. Use host CSS variables for surfaces and text. Do not use `position: fixed`, nested scrolling, comments, or unapproved remote resources.
@@ -0,0 +1,10 @@
1
+ # Illustrative diagrams
2
+
3
+ Draw the mechanism or a useful spatial metaphor.
4
+
5
+ - Draw each idea as a physical object: machine, pipe, valve, stamp, funnel, conveyor, lever, drawer. Reach for an object first, and for a word only when no object carries the idea.
6
+ - Text inside the visual is evidence: exact identifiers, field names, and example values, verbatim, in monospace. Explanatory sentences stay in the surrounding prose.
7
+ - Color carries meaning and holds the same meaning across every panel — for example red for a defect, green for correct flow, amber for the change. One story per panel, panels numbered, read in order.
8
+ - Every route and arrow ends touching its target. Long paths carry motion cues such as chevrons or trails to show direction.
9
+
10
+ Use one functional two-stop gradient only when it is a continuous physical property. Keep physical scene colors consistent and give a dark-mode treatment when needed.
@@ -0,0 +1,3 @@
1
+ # Interaction
2
+
3
+ Use local JavaScript for filtering, sorting, toggling, and simple calculations. Use `sendPrompt(text)` when the next action needs model reasoning. Give every control an accessible name, keyboard behavior, and visible state.
@@ -0,0 +1,3 @@
1
+ # Mockups
2
+
3
+ Use a bounded interface surface with clear hierarchy, realistic labels, and host variables. Keep controls visually consistent and make the primary action obvious.
@@ -0,0 +1,7 @@
1
+ # Quality gates
2
+
3
+ Judgment checks a script cannot make. Run them by eye on the rendered result, after `scripts/validate-artifact.py` passes.
4
+
5
+ - The artifact is self-contained and uses an approved external-resource origin when a resource is needed.
6
+ - Rendered output has no clipping, unintended overlap, or unreadable contrast.
7
+ - The visual reads at display scale, not just at full zoom.
@@ -0,0 +1,3 @@
1
+ # Structural diagrams
2
+
3
+ Use a rounded outer container and two or three levels of containment at most. Keep external inputs and outputs outside the container. Give each region a short name and description.
@@ -0,0 +1,21 @@
1
+ # Subject inventory
2
+
3
+ List every element of the subject a reader expects to find, then mark each one kept or cut and say why in prose.
4
+
5
+ For a diff or a pull request the list is fixed and needs no judgment:
6
+
7
+ - Files touched
8
+ - Identifiers added and removed
9
+ - Behavior changed
10
+ - Tests added
11
+ - Docs changed
12
+ - Commits
13
+
14
+ Read those six from the repo itself:
15
+
16
+ ```bash
17
+ git diff --stat <base>..<head>
18
+ git log --oneline <base>..<head>
19
+ ```
20
+
21
+ Every element then sits in a visual or gets named in the surrounding prose. An inventory too large for one canvas becomes an overview visual plus detail visuals.
@@ -0,0 +1,22 @@
1
+ # SVG contract
2
+
3
+ Put `<title>`, `<desc>`, then `<defs>` first. Every connector has `fill="none"`; arrowheads use the standard marker. Avoid negative coordinates, clipping, crossing labels, and standalone labels outside a region or callout.
4
+
5
+ ## Canvas tiers
6
+
7
+ Pick one of two widths:
8
+
9
+ - **Standard** — `viewBox="0 0 680 H"`. Use it for a single small explainer.
10
+ - **Large infographic** — `viewBox="0 0 W H"` with `W` from 1360 to 2000. This is the default for anything with two or more panels or more than about 6 labeled elements.
11
+
12
+ ## Text floor
13
+
14
+ The smallest caption sits at `16 × (width / 680)` units, rounded to the nearest whole unit: 16 at 680, 32 at 1360, 41 at 1760. Body text sits above that floor.
15
+
16
+ ## Safe area
17
+
18
+ The safe area scales with the canvas the same way: `40 × (width / 680)` units, so 40 at 680 and about 80 at 1360. Keep authored content inside it.
19
+
20
+ ## Background
21
+
22
+ Every SVG draws its own opaque warm-white background rect (for example `#F2EFE6` or `#FFFFFF`) as the first shape after `<defs>`, covering the full viewBox. The visual carries a fixed palette (see `references/core-design.md`), so an owned background keeps it legible on light and dark hosts alike.
@@ -0,0 +1,30 @@
1
+ workflow: workflows/create-visual.md
2
+ shared_references:
3
+ - references/core-design.md
4
+ - references/accessibility.md
5
+ - references/quality-gates.md
6
+ routes:
7
+ flowchart:
8
+ references: [references/svg-contract.md, references/subject-inventory.md, references/flowcharts.md]
9
+ template: templates/svg-base.svg
10
+ structural:
11
+ references: [references/svg-contract.md, references/subject-inventory.md, references/structural-diagrams.md]
12
+ template: templates/svg-base.svg
13
+ illustrative:
14
+ references: [references/svg-contract.md, references/subject-inventory.md, references/illustrative-diagrams.md]
15
+ template: templates/svg-base.svg
16
+ erd:
17
+ references: [references/host-and-html.md, references/subject-inventory.md, references/erds.md]
18
+ template: templates/html-widget.html
19
+ interactive:
20
+ references: [references/host-and-html.md, references/interaction.md]
21
+ template: templates/html-widget.html
22
+ mockup:
23
+ references: [references/host-and-html.md, references/mockups.md]
24
+ template: templates/html-widget.html
25
+ chart:
26
+ references: [references/host-and-html.md, references/charts.md]
27
+ template: templates/html-widget.html
28
+ art:
29
+ references: [references/art.md]
30
+ template: templates/html-widget.html