claude-dev-env 1.95.0 → 2.0.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 (240) hide show
  1. package/_shared/advisor/CLAUDE.md +2 -2
  2. package/_shared/advisor/advisor-protocol.md +20 -20
  3. package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +15 -12
  4. package/_shared/advisor/scripts/model_tier_run_validator.py +11 -10
  5. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +25 -19
  6. package/_shared/advisor/scripts/tests/test_tier_model_ids.py +17 -17
  7. package/_shared/advisor/scripts/tier_model_ids.py +18 -18
  8. package/_shared/pr-loop/CLAUDE.md +1 -0
  9. package/_shared/pr-loop/scripts/CLAUDE.md +2 -1
  10. package/_shared/pr-loop/scripts/README.md +1 -0
  11. package/_shared/pr-loop/scripts/code_rules_gate.py +253 -1980
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +32 -0
  13. package/_shared/pr-loop/scripts/code_rules_gate_parts/__init__.py +7 -0
  14. package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +268 -0
  15. package/_shared/pr-loop/scripts/code_rules_gate_parts/enforcer_loading.py +172 -0
  16. package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_arguments.py +70 -0
  17. package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +326 -0
  18. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +85 -0
  19. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +331 -0
  20. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +369 -0
  21. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/conftest.py +14 -0
  22. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_added_line_maps.py +118 -0
  23. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_enforcer_loading.py +17 -0
  24. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_arguments.py +29 -0
  25. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_running.py +99 -0
  26. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_blob_readers.py +69 -0
  27. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_file_sets.py +137 -0
  28. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +116 -0
  29. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_violation_scoping.py +75 -0
  30. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_wrapper_plumb_check.py +49 -0
  31. package/_shared/pr-loop/scripts/code_rules_gate_parts/violation_scoping.py +328 -0
  32. package/_shared/pr-loop/scripts/code_rules_gate_parts/wrapper_plumb_check.py +206 -0
  33. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +24 -17
  34. package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviews_disabled_constants.py +1 -0
  35. package/_shared/pr-loop/scripts/reviews_disabled.py +19 -2
  36. package/_shared/pr-loop/scripts/test_code_rules_gate.py +278 -0
  37. package/_shared/pr-loop/scripts/tests/test_code_rules_gate_constants.py +6 -39
  38. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +43 -0
  39. package/_shared/pr-loop/worker-spawn.md +186 -0
  40. package/agents/code-verifier.md +1 -1
  41. package/bin/ever-shipped-skills.mjs +3 -0
  42. package/bin/expand_home_directory_tokens.mjs +1 -1
  43. package/bin/install.mjs +5 -2
  44. package/hooks/advisory/refactor_guard.py +3 -4
  45. package/hooks/blocking/CLAUDE.md +7 -1
  46. package/hooks/blocking/block_main_commit.py +2 -2
  47. package/hooks/blocking/claude_md_orphan_file_blocker.py +75 -699
  48. package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +28 -0
  49. package/hooks/blocking/claude_md_orphan_file_blocker_parts/__init__.py +1 -0
  50. package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/__init__.py +1 -0
  51. package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/orphan_blocker_constants.py +18 -0
  52. package/hooks/blocking/claude_md_orphan_file_blocker_parts/decision.py +81 -0
  53. package/hooks/blocking/claude_md_orphan_file_blocker_parts/references.py +307 -0
  54. package/hooks/blocking/claude_md_orphan_file_blocker_parts/scan_plan.py +124 -0
  55. package/hooks/blocking/claude_md_orphan_file_blocker_parts/subtree_scan.py +179 -0
  56. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/conftest.py +10 -0
  57. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_decision.py +34 -0
  58. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_references.py +42 -0
  59. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_scan_plan.py +27 -0
  60. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_subtree_scan.py +30 -0
  61. package/hooks/blocking/code_rules_boolean_mustcheck.py +1 -1
  62. package/hooks/blocking/code_rules_mock_completeness.py +1 -1
  63. package/hooks/blocking/code_rules_optional_params.py +2 -2
  64. package/hooks/blocking/code_rules_shared.py +1 -1
  65. package/hooks/blocking/code_rules_test_assertions.py +1 -1
  66. package/hooks/blocking/code_rules_typeddict_stub.py +1 -1
  67. package/hooks/blocking/gh_pr_author_enforcer.py +1 -1
  68. package/hooks/blocking/inventory_intent_records/CLAUDE.md +26 -0
  69. package/hooks/blocking/inventory_intent_records/__init__.py +1 -0
  70. package/hooks/blocking/inventory_intent_records/config/__init__.py +1 -0
  71. package/hooks/blocking/inventory_intent_records/config/intent_records_constants.py +20 -0
  72. package/hooks/blocking/inventory_intent_records/records.py +271 -0
  73. package/hooks/blocking/inventory_intent_records/tests/conftest.py +10 -0
  74. package/hooks/blocking/inventory_intent_records/tests/test_records.py +80 -0
  75. package/hooks/blocking/package_inventory_stale_blocker.py +54 -384
  76. package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +26 -0
  77. package/hooks/blocking/package_inventory_stale_blocker_parts/__init__.py +1 -0
  78. package/hooks/blocking/package_inventory_stale_blocker_parts/config/__init__.py +1 -0
  79. package/hooks/blocking/package_inventory_stale_blocker_parts/config/inventory_blocker_constants.py +16 -0
  80. package/hooks/blocking/package_inventory_stale_blocker_parts/decision.py +84 -0
  81. package/hooks/blocking/package_inventory_stale_blocker_parts/inventory_detection.py +307 -0
  82. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/conftest.py +10 -0
  83. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_decision.py +38 -0
  84. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_inventory_detection.py +61 -0
  85. package/hooks/blocking/pii_payload_scan.py +138 -42
  86. package/hooks/blocking/pii_prevention_blocker.py +185 -291
  87. package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +24 -0
  88. package/hooks/blocking/pii_prevention_blocker_parts/__init__.py +1 -0
  89. package/hooks/blocking/pii_prevention_blocker_parts/config/__init__.py +1 -0
  90. package/hooks/blocking/pii_prevention_blocker_parts/config/repository_resolution_constants.py +28 -0
  91. package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +214 -0
  92. package/hooks/blocking/pii_prevention_blocker_parts/repository_resolution.py +208 -0
  93. package/hooks/blocking/pr_description_command_parser.py +8 -4
  94. package/hooks/blocking/precommit_code_rules_gate.py +3 -3
  95. package/hooks/blocking/tdd_enforcer.py +97 -608
  96. package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +30 -0
  97. package/hooks/blocking/tdd_enforcer_parts/__init__.py +1 -0
  98. package/hooks/blocking/tdd_enforcer_parts/candidate_paths.py +142 -0
  99. package/hooks/blocking/tdd_enforcer_parts/config/__init__.py +1 -0
  100. package/hooks/blocking/tdd_enforcer_parts/config/tdd_enforcer_constants.py +32 -0
  101. package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +268 -0
  102. package/hooks/blocking/tdd_enforcer_parts/decisions.py +92 -0
  103. package/hooks/blocking/tdd_enforcer_parts/freshness.py +80 -0
  104. package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +63 -0
  105. package/hooks/blocking/tdd_enforcer_parts/path_classification.py +119 -0
  106. package/hooks/blocking/tdd_enforcer_parts/tests/conftest.py +10 -0
  107. package/hooks/blocking/tdd_enforcer_parts/tests/test_candidate_paths.py +31 -0
  108. package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +30 -0
  109. package/hooks/blocking/tdd_enforcer_parts/tests/test_decisions.py +34 -0
  110. package/hooks/blocking/tdd_enforcer_parts/tests/test_freshness.py +28 -0
  111. package/hooks/blocking/tdd_enforcer_parts/tests/test_git_tracking.py +48 -0
  112. package/hooks/blocking/tdd_enforcer_parts/tests/test_path_classification.py +36 -0
  113. package/hooks/blocking/test_inventory_deadlock_resolution.py +154 -0
  114. package/hooks/blocking/test_pii_payload_scan.py +168 -0
  115. package/hooks/blocking/test_tdd_enforcer_restore.py +108 -0
  116. package/hooks/blocking/tests/conftest.py +10 -0
  117. package/hooks/blocking/tests/test_pii_prevention_blocker.py +260 -0
  118. package/hooks/blocking/tests/test_repository_exemption.py +105 -0
  119. package/hooks/blocking/tests/test_repository_resolution.py +108 -0
  120. package/hooks/diagnostic/hook_log_extractor.py +12 -10
  121. package/hooks/git-hooks/post_commit.py +3 -4
  122. package/hooks/hooks_constants/CLAUDE.md +2 -2
  123. package/hooks/hooks_constants/banned_identifiers_constants.py +0 -1
  124. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  125. package/hooks/hooks_constants/local_identity.py +59 -8
  126. package/hooks/hooks_constants/pii_prevention_constants.py +0 -6
  127. package/hooks/hooks_constants/test_local_identity.py +105 -3
  128. package/hooks/pyproject.toml +13 -36
  129. package/hooks/session/plugin_data_dir_cleanup.py +0 -1
  130. package/hooks/validation/mypy_validator.py +2 -2
  131. package/hooks/validators/health_check.py +1 -0
  132. package/hooks/validators/mypy_integration.py +2 -0
  133. package/hooks/validators/ruff_integration.py +3 -0
  134. package/hooks/workflow/auto_formatter.py +5 -4
  135. package/package.json +1 -1
  136. package/scripts/CLAUDE.md +4 -0
  137. package/scripts/dev_env_scripts_constants/CLAUDE.md +6 -4
  138. package/scripts/dev_env_scripts_constants/code_review_constants.py +71 -0
  139. package/scripts/dev_env_scripts_constants/grok_worker_constants.py +435 -0
  140. package/scripts/dev_env_scripts_constants/timing.py +7 -1
  141. package/scripts/grok_headless_runner.py +294 -0
  142. package/scripts/grok_worker_preflight.py +410 -0
  143. package/scripts/invoke_code_review.py +463 -0
  144. package/scripts/resolve_worker_spawn.py +619 -0
  145. package/scripts/spawn_grok_batch.py +672 -0
  146. package/scripts/test_grok_headless_runner.py +626 -0
  147. package/scripts/test_grok_worker_preflight.py +1054 -0
  148. package/scripts/test_invoke_code_review.py +672 -0
  149. package/scripts/test_resolve_worker_spawn.py +1014 -0
  150. package/scripts/test_spawn_grok_batch.py +1017 -0
  151. package/skills/CLAUDE.md +5 -3
  152. package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +72 -13
  153. package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +121 -14
  154. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +78 -0
  155. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +121 -0
  156. package/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +196 -6
  157. package/skills/autoconverge/CLAUDE.md +3 -3
  158. package/skills/autoconverge/SKILL.md +9 -3
  159. package/skills/autoconverge/reference/CLAUDE.md +2 -2
  160. package/skills/autoconverge/reference/convergence.md +33 -11
  161. package/skills/autoconverge/reference/stop-conditions.md +16 -5
  162. package/skills/autoconverge/workflow/CLAUDE.md +2 -1
  163. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +7 -2
  164. package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +300 -0
  165. package/skills/autoconverge/workflow/converge.contract.test.mjs +5 -5
  166. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +29 -29
  167. package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
  168. package/skills/autoconverge/workflow/converge.mjs +200 -16
  169. package/skills/bugteam/CLAUDE.md +2 -2
  170. package/skills/bugteam/CONSTRAINTS.md +3 -2
  171. package/skills/bugteam/PROMPTS.md +7 -6
  172. package/skills/bugteam/SKILL.md +18 -13
  173. package/skills/bugteam/reference/audit-and-teammates.md +215 -35
  174. package/skills/bugteam/reference/design-rationale.md +1 -1
  175. package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -1
  176. package/skills/bugteam/reference/team-setup.md +8 -2
  177. package/skills/codex-review/CLAUDE.md +46 -0
  178. package/skills/codex-review/SKILL.md +181 -0
  179. package/skills/codex-review/reference/CLAUDE.md +15 -0
  180. package/skills/codex-review/reference/cli-contract.md +253 -0
  181. package/skills/codex-review/reference/loop-integration.md +118 -0
  182. package/skills/codex-review/scripts/codex_down_classifier.py +98 -0
  183. package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +18 -0
  184. package/skills/codex-review/scripts/codex_review_scripts_constants/__init__.py +1 -0
  185. package/skills/codex-review/scripts/codex_review_scripts_constants/classifier_constants.py +35 -0
  186. package/skills/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +86 -0
  187. package/skills/codex-review/scripts/codex_review_scripts_constants/findings_constants.py +18 -0
  188. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +45 -0
  189. package/skills/codex-review/scripts/codex_usage_probe.py +573 -0
  190. package/skills/codex-review/scripts/fixtures/auth_failure_synthetic.txt +1 -0
  191. package/skills/codex-review/scripts/fixtures/config_load_failure_v0.125.0.txt +1 -0
  192. package/skills/codex-review/scripts/fixtures/freeform_findings_v0.144.3.txt +6 -0
  193. package/skills/codex-review/scripts/fixtures/model_rejection_v0.125.0.jsonl +5 -0
  194. package/skills/codex-review/scripts/fixtures/structured_findings.txt +13 -0
  195. package/skills/codex-review/scripts/fixtures/success_stream_v0.144.3.jsonl +6 -0
  196. package/skills/codex-review/scripts/fixtures/unknown_failure_synthetic.txt +1 -0
  197. package/skills/codex-review/scripts/fixtures/usage_limit_synthetic.txt +1 -0
  198. package/skills/codex-review/scripts/parse_codex_findings.py +207 -0
  199. package/skills/codex-review/scripts/run_codex_review.py +415 -0
  200. package/skills/codex-review/scripts/test_codex_down_classifier.py +143 -0
  201. package/skills/codex-review/scripts/test_codex_usage_probe.py +678 -0
  202. package/skills/codex-review/scripts/test_parse_codex_findings.py +130 -0
  203. package/skills/codex-review/scripts/test_run_codex_review.py +812 -0
  204. package/skills/codex-review/test_skill_scaffold.py +192 -0
  205. package/skills/grok-spawn/CLAUDE.md +28 -0
  206. package/skills/grok-spawn/SKILL.md +226 -0
  207. package/skills/grok-spawn/reference/flag-profiles.md +132 -0
  208. package/skills/grok-spawn/reference/worker-briefs.md +152 -0
  209. package/skills/grokify/SKILL.md +9 -1
  210. package/skills/grokify/capability-claims.test.mjs +28 -0
  211. package/skills/grokify/evals/README.md +72 -0
  212. package/skills/grokify/evals/parse-payload.test.mjs +171 -0
  213. package/skills/grokify/evals/run-capability-evals.mjs +545 -0
  214. package/skills/orchestrator/SKILL.md +15 -11
  215. package/skills/orchestrator-refresh/SKILL.md +5 -5
  216. package/skills/pr-converge/SKILL.md +34 -13
  217. package/skills/pr-converge/reference/convergence-gates.md +42 -15
  218. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  219. package/skills/pr-converge/reference/ground-rules.md +1 -1
  220. package/skills/pr-converge/reference/per-tick.md +130 -42
  221. package/skills/pr-converge/reference/state-schema.md +10 -0
  222. package/skills/pr-converge/scripts/CLAUDE.md +2 -0
  223. package/skills/pr-converge/scripts/_pr_converge_path_setup.py +5 -1
  224. package/skills/pr-converge/scripts/check_convergence.py +605 -29
  225. package/skills/pr-converge/scripts/check_convergence_availability.py +232 -0
  226. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -235
  227. package/skills/pr-converge/scripts/check_convergence_thread_gates.py +1 -1
  228. package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -2
  229. package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +4 -0
  230. package/skills/pr-converge/scripts/test_check_convergence.py +71 -3
  231. package/skills/pr-converge/scripts/test_check_convergence_availability.py +326 -0
  232. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -0
  233. package/skills/pr-converge/scripts/test_check_convergence_contract.py +89 -17
  234. package/skills/pr-converge/scripts/test_check_convergence_fixture.py +179 -0
  235. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -68
  236. package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +24 -0
  237. package/skills/pr-converge/test_step5_host_branch.py +106 -0
  238. package/skills/pr-loop-cloud-transport/SKILL.md +2 -0
  239. package/skills/reviewer-gates/SKILL.md +7 -5
  240. package/skills/team-advisor/SKILL.md +7 -7
@@ -48,6 +48,7 @@ PLUGIN_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__
48
48
  HOOKS_DIR = os.path.join(PLUGIN_ROOT, "hooks") + os.sep
49
49
  PYTHON_FORMAT_TIMEOUT_SECONDS = 12
50
50
  JS_FORMAT_TIMEOUT_SECONDS = 30
51
+ GIT_LS_FILES_TIMEOUT_SECONDS = 5
51
52
  PRETTIER_CONFIG_NAMES = {
52
53
  ".prettierrc",
53
54
  ".prettierrc.json",
@@ -99,10 +100,10 @@ def is_untracked_in_git(file_path: str) -> bool:
99
100
  try:
100
101
  git_check = subprocess.run(
101
102
  ["git", "ls-files", "--error-unmatch", file_path],
102
- capture_output=True,
103
+ check=False, capture_output=True,
103
104
  text=True,
104
105
  cwd=containing_directory,
105
- timeout=5,
106
+ timeout=GIT_LS_FILES_TIMEOUT_SECONDS,
106
107
  )
107
108
  return git_check.returncode != 0
108
109
  except (FileNotFoundError, subprocess.TimeoutExpired):
@@ -150,7 +151,7 @@ def main() -> None:
150
151
  [sys.executable, "-m", "black", file_path],
151
152
  ]:
152
153
  try:
153
- format_run = subprocess.run(each_formatter_command, capture_output=True, text=True, timeout=PYTHON_FORMAT_TIMEOUT_SECONDS)
154
+ format_run = subprocess.run(each_formatter_command, check=False, capture_output=True, text=True, timeout=PYTHON_FORMAT_TIMEOUT_SECONDS)
154
155
  if format_run.returncode == 0:
155
156
  formatter_name = each_formatter_command[0] if each_formatter_command[0] != sys.executable else each_formatter_command[2]
156
157
  send_format_notification(file_path, formatter_name)
@@ -165,7 +166,7 @@ def main() -> None:
165
166
  try:
166
167
  prettier_run = subprocess.run(
167
168
  ["npx", "--yes", "prettier", "--write", file_path],
168
- capture_output=True,
169
+ check=False, capture_output=True,
169
170
  text=True,
170
171
  timeout=JS_FORMAT_TIMEOUT_SECONDS,
171
172
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "1.95.0",
3
+ "version": "2.0.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
package/scripts/CLAUDE.md CHANGED
@@ -8,9 +8,13 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
8
8
  |---|---|
9
9
  | `claude_chain_runner.py` | Runs a `claude` invocation through a config-driven fallback chain (`~/.claude/claude-chain.json`): the leading binary serves the call, and only a usage-limit failure falls over to the next logged-in binary; usable as an imported module (`run_claude`) or a CLI. Copy `claude-chain.example.json` to `~/.claude/claude-chain.json` and list your binaries in fallback order |
10
10
  | `gh_artifact_upload.py` | Uploads a file to a repo's durable `artifacts` prerelease under a timestamped asset name and prints the permanent download URL a GitHub post can link |
11
+ | `grok_headless_runner.py` | Runs one worker as headless `grok`: builds argv, mints a unique leader socket, captures streams, kills on timeout with grace, classifies ok/usage_limit/auth_failure/timeout/error; imported by `spawn_grok_batch.py` |
12
+ | `grok_worker_preflight.py` | Soft gate for the headless grok tier: binary on PATH, `grok models` auth, install manifest + role agents, opt-in cached live ping; non-zero exit is fallthrough, not failure |
11
13
  | `setup_project_paths.py` | One-time bootstrap: discovers git repos via `es.exe` (Everything) and writes `~/.claude/project-paths.json`; never hardcodes scan roots |
14
+ | `spawn_grok_batch.py` | Launches a fleet of headless grok workers from a JSON batch spec: gates once through the preflight, assembles each prompt from part files, staggers starts, runs each through `grok_headless_runner.py`, and emits one batch summary JSON |
12
15
  | `sweep_empty_dirs.py` | Deletes empty directories older than a configurable age under a given root; runs once (`--once`) or in continuous-watch mode |
13
16
  | `sync_to_cursor.py` | Entry point for syncing Claude rules to Cursor `.mdc` files; delegates to the `sync_to_cursor/` package |
17
+ | `resolve_worker_spawn.py` | Dispatches a worker role through grok then claude fallback tiers (preflight, headless grok, `claude_agent_required` handoff, optional claude headless); protocol: [`../_shared/pr-loop/worker-spawn.md`](../_shared/pr-loop/worker-spawn.md) |
14
18
 
15
19
  ## PowerShell scripts
16
20
 
@@ -6,11 +6,13 @@ Named constants for scripts in `scripts/`. Follows the project convention that t
6
6
 
7
7
  | File | Constants for |
8
8
  |---|---|
9
- | `timing.py` | `sweep_empty_dirs.py` `DEFAULT_AGE_SECONDS` (smallest age before an empty directory is eligible for removal) and `DEFAULT_POLL_INTERVAL` (seconds between sweep passes in continuous-watch mode) |
10
- | `gh_artifact_upload_constants.py` | `gh_artifact_upload.py` the `artifacts` release tag, title, and notes body, the GitHub CLI binary name, the asset-name timestamp format and template, the asset download URL template, the notes-file suffix, and the text encoding |
11
- | `claude_chain_constants.py` | `claude_chain_runner.py` the chain config filename and home subdirectory, the usage-limit signature text, the per-binary status labels, the default timeout, CLI flag and separator tokens, config JSON keys, invalid-shape reason text, config-error and exhausted-chain message templates, and CLI exit codes |
9
+ | `timing.py` | `sweep_empty_dirs.py` - `DEFAULT_AGE_SECONDS` (smallest age before an empty directory is eligible for removal) and `DEFAULT_POLL_INTERVAL` (seconds between sweep passes in continuous-watch mode); `spawn_grok_batch.py` - `WORKER_STAGGER_SECONDS` (seconds between staggered headless grok worker starts); `invoke_code_review.py` - `DEFAULT_CODE_REVIEW_TIMEOUT_SECONDS` (timeout for one headless `/code-review` chain run) |
10
+ | `gh_artifact_upload_constants.py` | `gh_artifact_upload.py` - the `artifacts` release tag, title, and notes body, the GitHub CLI binary name, the asset-name timestamp format and template, the asset download URL template, the notes-file suffix, and the text encoding |
11
+ | `claude_chain_constants.py` | `claude_chain_runner.py` - the chain config filename and home subdirectory, the usage-limit signature text, the per-binary status labels, the default timeout, CLI flag and separator tokens, config JSON keys, invalid-shape reason text, config-error and exhausted-chain message templates, and CLI exit codes |
12
+ | `grok_worker_constants.py` | `grok_worker_preflight.py`, `grok_headless_runner.py`, and `spawn_grok_batch.py` - the `grok` binary name and CLI flags, model and subcommand tokens, leader-socket and scratch-file name parts, auth and usage-limit signature lists, outcome classifications, fallthrough reasons, tool-profile names and prompt headers, timeouts and turn caps (including launch-failure return code and post-kill grace), ping-cache keys and TTL, batch-spec and summary JSON keys, the prompt-part and report-stream join separators, and the CLI launch-error stderr prefix |
13
+ | `code_review_constants.py` | `invoke_code_review.py` - the `/code-review high --fix` prompt, opus model alias, permission-mode flag and value, result mode and JSON keys, session-model CLI flag, git dirty-check tokens, and in-session return markers |
12
14
  | `__init__.py` | Empty package marker |
13
15
 
14
16
  ## Convention
15
17
 
16
- Every constant is `UPPER_SNAKE_CASE` with an explicit type annotation and a docstring. Scripts import from here rather than embedding literal values in their bodies.
18
+ Every constant is `UPPER_SNAKE_CASE` with an explicit type annotation and a docstring. Scripts import from here rather than embedding literal values in their bodies.
@@ -0,0 +1,71 @@
1
+ """Named constants for the host-aware `/code-review` invoker.
2
+
3
+ `invoke_code_review.py` imports every scalar and structural constant it
4
+ needs from this module (and shared flag tokens from
5
+ `grok_worker_constants`) so the prompt, model alias, and JSON keys are
6
+ never hardcoded twice.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ CODE_REVIEW_SLASH_COMMAND: str = "/code-review"
12
+ """Built-in Claude Code slash command that runs the repository review."""
13
+
14
+ CODE_REVIEW_EFFORT: str = "high"
15
+ """Effort level passed to the built-in review slash command."""
16
+
17
+ CODE_REVIEW_FIX_FLAG: str = "--fix"
18
+ """Slash-command flag that applies automatic fixes for review findings."""
19
+
20
+ CODE_REVIEW_PROMPT: str = (
21
+ f"{CODE_REVIEW_SLASH_COMMAND} {CODE_REVIEW_EFFORT} {CODE_REVIEW_FIX_FLAG}"
22
+ )
23
+ """Single-turn prompt that runs the built-in review slash command with fixes."""
24
+
25
+ CODE_REVIEW_MODEL_ALIAS: str = "opus"
26
+ """CLI `--model` short alias the review always pins to."""
27
+
28
+ PERMISSION_MODE_FLAG: str = "--permission-mode"
29
+ """CLI flag that selects how the headless claude process handles tool permission prompts."""
30
+
31
+ PERMISSION_MODE_BYPASS: str = "bypassPermissions"
32
+ """Permission-mode value that auto-approves tools for unattended chain runs."""
33
+
34
+ MODE_IN_SESSION: str = "in_session"
35
+ """Result mode when the host is Claude and the session already runs opus."""
36
+
37
+ MODE_CHAIN: str = "chain"
38
+ """Result mode when the helper spawns a headless claude chain for the review."""
39
+
40
+ RESULT_KEY_MODE: str = "mode"
41
+ """JSON result key naming the review mode (`in_session` or `chain`)."""
42
+
43
+ RESULT_KEY_SERVED_COMMAND: str = "served_command"
44
+ """JSON result key naming the chain binary that served the call, or null."""
45
+
46
+ RESULT_KEY_RETURNCODE: str = "returncode"
47
+ """JSON result key holding the process return code from the chain run."""
48
+
49
+ RESULT_KEY_DIRTY_TREE: str = "dirty_tree"
50
+ """JSON result key holding whether the working tree is dirty after the review."""
51
+
52
+ CLI_SESSION_MODEL_FLAG: str = "--session-model"
53
+ """CLI flag naming the caller's current session model short alias."""
54
+
55
+ GIT_BINARY: str = "git"
56
+ """Executable name resolved on PATH for working-tree dirty checks."""
57
+
58
+ GIT_STATUS_SUBCOMMAND: str = "status"
59
+ """Git subcommand used to detect an uncommitted dirty working tree."""
60
+
61
+ GIT_PORCELAIN_FLAG: str = "--porcelain"
62
+ """Git status flag that prints machine-readable dirty-path lines."""
63
+
64
+ IN_SESSION_RETURNCODE: int = 0
65
+ """Return code reported when the helper hands the review back to the in-session skill."""
66
+
67
+ HOST_PROFILE_ERROR_RETURNCODE: int = 1
68
+ """Return code when host-profile detection raises ValueError at the CLI boundary."""
69
+
70
+ SUCCESSFUL_REVIEW_RETURNCODE: int = 0
71
+ """Return code required before a clean stamp may advance past CODE_REVIEW."""
@@ -0,0 +1,435 @@
1
+ """Named constants for the grok worker preflight, headless runner, and batch launcher.
2
+
3
+ ``grok_worker_preflight.py``, ``grok_headless_runner.py``, and
4
+ ``spawn_grok_batch.py`` share this module. Per project configuration
5
+ conventions, every scalar and structural constant those scripts need lives
6
+ here rather than inline in the modules.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ GROK_BINARY_NAME: str = "grok"
12
+ """Executable name resolved on PATH for the headless grok tier."""
13
+
14
+ MODELS_SUBCOMMAND: str = "models"
15
+ """Subcommand that prints login state and model list without agent tokens."""
16
+
17
+ LEADER_SOCKET_FLAG: str = "--leader-socket"
18
+ """CLI flag that points grok at a dedicated leader socket path."""
19
+
20
+ SINGLE_TURN_FLAG: str = "-p"
21
+ """CLI flag that runs one single-turn prompt and exits."""
22
+
23
+ MAX_TURNS_FLAG: str = "--max-turns"
24
+ """CLI flag that caps agent turns for the opt-in live ping."""
25
+
26
+ PING_MAX_TURNS: str = "1"
27
+ """Turn cap passed with the opt-in live ping so the call stays single-turn."""
28
+
29
+ AUTH_LEADER_SOCKET_FILENAME: str = "grok-preflight-auth.sock"
30
+ """Leader socket filename used only by the auth ``models`` probe."""
31
+
32
+ PING_LEADER_SOCKET_FILENAME: str = "grok-preflight-ping.sock"
33
+ """Leader socket filename used only by the opt-in live ping."""
34
+
35
+ PING_CACHE_FILENAME: str = "grok_preflight_ping_cache.json"
36
+ """Cache file name under the caller-supplied run state directory."""
37
+
38
+ PING_CACHE_CHECKED_AT_KEY: str = "checked_at"
39
+ """JSON key holding the unix timestamp of the last successful ping."""
40
+
41
+ PING_CACHE_IS_OK_KEY: str = "is_ok"
42
+ """JSON key holding whether the last ping completed successfully."""
43
+
44
+ PING_TTL_SECONDS: int = 300
45
+ """Run-scoped TTL for a successful ping cache entry, in seconds."""
46
+
47
+ PING_PROMPT: str = "reply with the single word ok"
48
+ """Single-turn prompt text used by the opt-in live ping."""
49
+
50
+ DEFAULT_AUTH_TIMEOUT_SECONDS: int = 30
51
+ """Timeout applied to the ``grok models`` auth probe."""
52
+
53
+ DEFAULT_PING_TIMEOUT_SECONDS: int = 120
54
+ """Timeout applied to the opt-in live single-turn ping."""
55
+
56
+ CLAUDE_HOME_SUBDIRECTORY: str = ".claude"
57
+ """Per-user directory under the home directory that holds Claude config."""
58
+
59
+ MANIFEST_FILENAME: str = ".claude-dev-env-manifest.json"
60
+ """Install manifest written by ``claude-dev-env`` into the user Claude home."""
61
+
62
+ AGENTS_SUBDIRECTORY: str = "agents"
63
+ """Subdirectory of the user Claude home that holds agent definition files."""
64
+
65
+ ROLE_BUGTEAM: str = "bugteam"
66
+ """Role name whose agent definition set the preflight validates by default."""
67
+
68
+ ROLE_CLEAN_CODER: str = "clean-coder"
69
+ """Role name that maps to the clean-coder agent for FIX and standards-fix."""
70
+
71
+ DEFAULT_ROLE: str = ROLE_BUGTEAM
72
+ """Role applied when the caller does not pass ``--role``."""
73
+
74
+ ALL_AGENT_FILENAMES_BY_ROLE: dict[str, tuple[str, ...]] = {
75
+ ROLE_BUGTEAM: ("code-quality-agent.md", "clean-coder.md"),
76
+ ROLE_CLEAN_CODER: ("clean-coder.md",),
77
+ }
78
+ """Agent definition filenames required under ``agents/`` for each known role."""
79
+
80
+ REASON_GROK_BINARY_MISSING: str = "grok_binary_missing"
81
+ """Fallthrough reason when the grok binary is not resolvable on PATH."""
82
+
83
+ REASON_GROK_AUTH_FAILED: str = "grok_auth_failed"
84
+ """Catch-all fallthrough for every non-usage failure of the auth or ping probe.
85
+
86
+ Covers a probe that exits non-zero, one whose launch raises, one that times out,
87
+ and one whose streams do not decode.
88
+ """
89
+
90
+ REASON_CLAUDE_DEV_ENV_CONFIG_MISSING: str = "claude_dev_env_config_missing"
91
+ """Fallthrough reason when the install manifest or role agents are absent."""
92
+
93
+ REASON_GROK_USAGE_EXHAUSTED: str = "grok_usage_exhausted"
94
+ """Fallthrough reason when a live ping fails with a usage-exhaustion signature."""
95
+
96
+ STDOUT_OK_LINE: str = "grok_preflight: ok"
97
+ """Machine-readable stdout line when tier 1 is usable."""
98
+
99
+ STDOUT_FALLTHROUGH_TEMPLATE: str = "grok_preflight: fallthrough reason={reason}"
100
+ """Machine-readable stdout line when the soft gate falls through."""
101
+
102
+ EXIT_USABLE: int = 0
103
+ """Process exit code when tier 1 is usable."""
104
+
105
+ EXIT_FALLTHROUGH: int = 1
106
+ """Process exit code when the soft gate falls through (callers continue the chain)."""
107
+
108
+ CLI_ROLE_FLAG: str = "--role"
109
+ """CLI flag naming the role whose agent definition set must be present."""
110
+
111
+ CLI_PING_FLAG: str = "--ping"
112
+ """CLI flag that enables the opt-in cached live single-turn ping."""
113
+
114
+ CLI_RUN_STATE_DIR_FLAG: str = "--run-temp-dir"
115
+ """CLI flag naming the run-scoped state directory for sockets and the ping cache."""
116
+
117
+ UTF8_ENCODING: str = "utf-8"
118
+ """Encoding used for subprocess text mode and the ping cache file."""
119
+
120
+ UTF8_DECODE_ERRORS: str = "replace"
121
+ """``errors=`` value for subprocess text decode so invalid bytes never yield None streams."""
122
+
123
+ ALL_USAGE_LIMIT_SIGNATURES: tuple[str, ...] = (
124
+ "rate limit",
125
+ "usage limit",
126
+ "out of usage",
127
+ "rate quota exceeded",
128
+ "usage quota exceeded",
129
+ "api quota exceeded",
130
+ "usage exhausted",
131
+ "insufficient credit",
132
+ "http 429",
133
+ "status 429",
134
+ )
135
+ """Case-insensitive multi-token phrases that mark a non-zero exit as a usage-limit failure."""
136
+
137
+ ALL_USAGE_EXHAUSTION_SIGNATURES: tuple[str, ...] = ALL_USAGE_LIMIT_SIGNATURES
138
+ """Alias used by the preflight soft gate for the same usage-limit signatures."""
139
+
140
+ ALL_AUTH_FAILURE_SIGNATURES: tuple[str, ...] = (
141
+ "http 401",
142
+ "status 401",
143
+ "error: unauthorized",
144
+ "unauthorized: please login",
145
+ "invalid api key",
146
+ "not logged in",
147
+ "not authenticated",
148
+ "unauthenticated",
149
+ "authentication failed",
150
+ "please log in",
151
+ "login required",
152
+ )
153
+ """Case-insensitive multi-token phrases that mark a non-zero completion as an auth failure."""
154
+
155
+ PROMPT_FILE_FLAG: str = "--prompt-file"
156
+ """CLI flag that points grok at a prompt file for headless single-turn work."""
157
+
158
+ CWD_FLAG: str = "--cwd"
159
+ """CLI flag that sets the working directory for the headless grok process."""
160
+
161
+ OUTPUT_FORMAT_FLAG: str = "--output-format"
162
+ """CLI flag that selects the headless output format."""
163
+
164
+ OUTPUT_FORMAT_JSON: str = "json"
165
+ """Output-format value that requests machine-readable JSON from grok."""
166
+
167
+ ALWAYS_APPROVE_FLAG: str = "--always-approve"
168
+ """CLI flag that auto-approves tool executions in the headless worker."""
169
+
170
+ AGENT_FLAG: str = "--agent"
171
+ """CLI flag that names the role agent definition the worker should load."""
172
+
173
+ MODEL_FLAG: str = "--model"
174
+ """CLI flag that pins a model id when ``GROK_MODEL_PIN`` is non-empty."""
175
+
176
+ GROK_MODEL_PIN: str = ""
177
+ """Optional model id pin. Empty string leaves the CLI default (``grok-4.5``)."""
178
+
179
+ LEADER_SOCKET_FILENAME_PREFIX: str = "grok-leader-"
180
+ """Filename prefix for each unique per-invocation leader socket under the run state directory."""
181
+
182
+ LEADER_SOCKET_FILENAME_SUFFIX: str = ".sock"
183
+ """Filename suffix for each unique per-invocation leader socket."""
184
+
185
+ CLASSIFICATION_OK: str = "ok"
186
+ """Outcome classification when the headless process exits zero."""
187
+
188
+ CLASSIFICATION_USAGE_LIMIT: str = "usage_limit"
189
+ """Outcome classification when stdout/stderr match a usage-limit signature."""
190
+
191
+ CLASSIFICATION_AUTH_FAILURE: str = "auth_failure"
192
+ """Outcome classification when stdout/stderr match an auth-failure signature."""
193
+
194
+ CLASSIFICATION_TIMEOUT: str = "timeout"
195
+ """Outcome classification when the headless process exceeds the timeout and is killed."""
196
+
197
+ CLASSIFICATION_ERROR: str = "error"
198
+ """Outcome classification for a non-zero exit that matches no known signature."""
199
+
200
+ CLASSIFICATION_STREAM_JOIN_SEPARATOR: str = "\n"
201
+ """Separator placed between stdout and stderr before signature matching so a phrase never forms or splits across the stream boundary."""
202
+
203
+ DEFAULT_WORKER_TIMEOUT_SECONDS: int = 600
204
+ """Default timeout applied to one headless worker invocation, in seconds."""
205
+
206
+ DEFAULT_WORKER_MAX_TURNS: int = 8
207
+ """Default max-turns value applied to one headless worker invocation."""
208
+
209
+ TIMEOUT_RETURN_CODE: int = -1
210
+ """Return code recorded on the outcome when a timed-out process leaves no return code."""
211
+
212
+ LAUNCH_FAILURE_RETURN_CODE: int = -2
213
+ """Return code when the grok process cannot be launched (missing binary, permission, etc.)."""
214
+
215
+ LAUNCH_FAILURE_STDERR_PREFIX: str = "failed to launch: "
216
+ """Prefix for the non-empty stderr diagnostic returned on a launch OSError."""
217
+
218
+ KILL_GRACE_TIMEOUT_SECONDS: int = 10
219
+ """Seconds to wait for a killed process to reap its pipes before giving up on its streams."""
220
+
221
+ MIN_WORKER_TIMEOUT_SECONDS: int = 1
222
+ """Minimum accepted worker timeout_seconds in a batch specification."""
223
+
224
+ MIN_WORKER_MAX_TURNS: int = 1
225
+ """Minimum accepted worker max_turns in a batch specification."""
226
+
227
+ WORKER_EXCEPTION_RETURN_CODE: int = -3
228
+ """Return code recorded on a WorkerReport when the worker body raises before a process runs.
229
+
230
+ Negative like the other no-process sentinels, so a launcher-side failure never
231
+ reads as a grok process that ran and exited ``1``.
232
+ """
233
+
234
+ TOOL_PROFILE_READONLY: str = "readonly"
235
+ """Tool profile that removes write, edit, and shell tools from the worker."""
236
+
237
+ TOOL_PROFILE_BUILD: str = "build"
238
+ """Tool profile that keeps full tools and forbids commit, push, and gh via prompt."""
239
+
240
+ ALL_KNOWN_TOOL_PROFILES: frozenset[str] = frozenset(
241
+ {TOOL_PROFILE_READONLY, TOOL_PROFILE_BUILD}
242
+ )
243
+ """Accepted tool-profile names on a batch worker specification."""
244
+
245
+ DISALLOWED_TOOLS_FLAG: str = "--disallowed-tools"
246
+ """CLI flag that names tools the headless worker must not use."""
247
+
248
+ ALL_READONLY_DISALLOWED_TOOLS: tuple[str, ...] = ("Write", "Edit", "Bash")
249
+ """Tools removed under the readonly tool profile."""
250
+
251
+ READONLY_DISALLOWED_TOOLS_VALUE: str = ",".join(ALL_READONLY_DISALLOWED_TOOLS)
252
+ """Comma-joined argument value for ``--disallowed-tools`` under readonly."""
253
+
254
+ DISABLE_WEB_SEARCH_FLAG: str = "--disable-web-search"
255
+ """CLI flag that turns off web search for repo-only readonly workers."""
256
+
257
+ DEBUG_FILE_FLAG: str = "--debug-file"
258
+ """CLI flag that points grok at a per-worker debug log path."""
259
+
260
+ OUTPUT_FILENAME_PREFIX: str = "grok-worker-output-"
261
+ """Filename prefix for each per-worker report file under the run state directory."""
262
+
263
+ OUTPUT_FILENAME_SUFFIX: str = ".txt"
264
+ """Filename suffix for each per-worker report file."""
265
+
266
+ PROMPT_FILENAME_PREFIX: str = "grok-worker-prompt-"
267
+ """Filename prefix for each assembled per-worker prompt file."""
268
+
269
+ PROMPT_FILENAME_SUFFIX: str = ".txt"
270
+ """Filename suffix for each assembled per-worker prompt file."""
271
+
272
+ DEBUG_FILENAME_PREFIX: str = "grok-worker-debug-"
273
+ """Filename prefix for each per-worker debug log file."""
274
+
275
+ DEBUG_FILENAME_SUFFIX: str = ".log"
276
+ """Filename suffix for each per-worker debug log file."""
277
+
278
+ PROMPT_PART_JOIN_SEPARATOR: str = "\n\n"
279
+ """Separator inserted between prompt part file bodies when assembling a worker prompt."""
280
+
281
+ REPORT_STREAM_JOIN_SEPARATOR: str = "\n\n"
282
+ """Separator between the stdout and stderr bodies of a failed worker's report text."""
283
+
284
+ BATCH_LAUNCH_ERROR_STDERR_PREFIX: str = "batch launch failed: "
285
+ """Prefix on the stderr line the CLI prints when a spec cannot load or a batch cannot start."""
286
+
287
+ BUILD_PROFILE_PROMPT_HEADER: str = (
288
+ "Tool profile: build. Never commit, push, or call gh.\n\n"
289
+ )
290
+ """Leading instruction block prepended to every build-profile worker prompt."""
291
+
292
+ READONLY_PROFILE_PROMPT_HEADER: str = (
293
+ "Tool profile: readonly. Do not write, edit, or run shell commands.\n\n"
294
+ )
295
+ """Leading instruction block prepended to every readonly-profile worker prompt."""
296
+
297
+ BATCH_SPEC_ROLE_KEY: str = "role"
298
+ """JSON key for the preflight role on a batch specification."""
299
+
300
+ BATCH_SPEC_SHOULD_PING_KEY: str = "should_ping"
301
+ """JSON key for the opt-in preflight ping flag on a batch specification."""
302
+
303
+ BATCH_SPEC_WORKERS_KEY: str = "workers"
304
+ """JSON key for the worker list on a batch specification."""
305
+
306
+ WORKER_SPEC_ROLE_NAME_KEY: str = "role_name"
307
+ """JSON key for one worker's role name."""
308
+
309
+ WORKER_SPEC_PROMPT_PARTS_KEY: str = "prompt_parts"
310
+ """JSON key for one worker's ordered prompt-part file paths."""
311
+
312
+ WORKER_SPEC_CWD_KEY: str = "cwd"
313
+ """JSON key for one worker's working directory."""
314
+
315
+ WORKER_SPEC_TOOL_PROFILE_KEY: str = "tool_profile"
316
+ """JSON key for one worker's tool profile name."""
317
+
318
+ WORKER_SPEC_TIMEOUT_KEY: str = "timeout_seconds"
319
+ """JSON key for one worker's timeout in seconds."""
320
+
321
+ WORKER_SPEC_IS_REPO_ONLY_KEY: str = "is_repo_only"
322
+ """JSON key for whether a readonly worker also disables web search."""
323
+
324
+ WORKER_SPEC_MAX_TURNS_KEY: str = "max_turns"
325
+ """JSON key for one worker's max-turns cap."""
326
+
327
+ WORKER_SPEC_AGENT_NAME_KEY: str = "agent_name"
328
+ """JSON key for one worker's optional agent definition name."""
329
+
330
+ CLI_BATCH_SPEC_FLAG: str = "--spec"
331
+ """CLI flag that points the batch launcher at a JSON batch specification file."""
332
+
333
+ SUMMARY_IS_PREFLIGHT_USABLE_KEY: str = "is_preflight_usable"
334
+ """Batch summary JSON key for the preflight usability flag."""
335
+
336
+ SUMMARY_PREFLIGHT_REASON_KEY: str = "preflight_reason"
337
+ """Batch summary JSON key for the preflight fallthrough reason."""
338
+
339
+ SUMMARY_WORKERS_KEY: str = "workers"
340
+ """Batch summary JSON key for the list of per-worker reports."""
341
+
342
+ SUMMARY_ROLE_NAME_KEY: str = "role_name"
343
+ """Per-worker report JSON key for the worker role name."""
344
+
345
+ SUMMARY_RETURNCODE_KEY: str = "returncode"
346
+ """Per-worker report JSON key for the process exit code."""
347
+
348
+ SUMMARY_CLASSIFICATION_KEY: str = "classification"
349
+ """Per-worker report JSON key for the runner classification string."""
350
+
351
+ SUMMARY_IS_OK_KEY: str = "is_ok"
352
+ """Per-worker report JSON key for whether the worker completed successfully."""
353
+
354
+ SUMMARY_REPORT_TEXT_KEY: str = "report_text"
355
+ """Per-worker report JSON key for the captured worker report text."""
356
+
357
+ SUMMARY_OUTPUT_FILE_KEY: str = "output_file"
358
+ """Per-worker report JSON key for the report file path."""
359
+
360
+ SUMMARY_LEADER_SOCKET_KEY: str = "leader_socket"
361
+ """Per-worker report JSON key for the leader socket path."""
362
+
363
+ SUMMARY_PROMPT_FILE_KEY: str = "prompt_file"
364
+ """Per-worker report JSON key for the assembled prompt file path."""
365
+
366
+ SUMMARY_DEBUG_FILE_KEY: str = "debug_file"
367
+ """Per-worker report JSON key for the ``--debug-file`` log path."""
368
+
369
+ SUMMARY_TOOL_PROFILE_KEY: str = "tool_profile"
370
+ """Per-worker report JSON key for the tool profile used."""
371
+
372
+ MISSING_BINARY_RETURN_CODE: int = 127
373
+ """Return code recorded when the grok binary is not found on PATH."""
374
+
375
+ GROK_BINARY_NOT_FOUND_STDERR: str = f"{GROK_BINARY_NAME} not found"
376
+ """Stderr text returned when the grok binary cannot be resolved on PATH."""
377
+ TIER_GROK: int = 1
378
+ """Dispatcher tier number for the headless grok worker path."""
379
+
380
+ TIER_CLAUDE_AGENT: int = 2
381
+ """Dispatcher tier number for the in-host claude_agent_required handoff."""
382
+
383
+ TIER_CLAUDE_HEADLESS: int = 3
384
+ """Dispatcher tier number for the headless claude chain path."""
385
+
386
+ REASON_CLAUDE_AGENT_REQUIRED: str = "claude_agent_required"
387
+ """Fallthrough reason when the caller must run claude_agent_required itself."""
388
+
389
+ REASON_PROMPT_FILE_MISSING: str = "prompt_file_missing"
390
+ """Config reason when the dispatcher CLI prompt file path is absent or unreadable."""
391
+
392
+ DEFAULT_SPAWN_MAX_TURNS: int = 8
393
+ """Default max-turns applied to the headless grok worker when the caller names none."""
394
+
395
+ SPAWN_SERVED_EXIT_CODE: int = 0
396
+ """CLI exit code when a dispatcher tier served the call."""
397
+
398
+ SPAWN_EXHAUSTED_EXIT_CODE: int = 2
399
+ """CLI exit code when no dispatcher tier served the call."""
400
+
401
+ SPAWN_CONFIG_ERROR_EXIT_CODE: int = 3
402
+ """CLI exit code when the claude chain configuration is missing or invalid."""
403
+
404
+ RESULT_KEY_TIER_USED: str = "tier_used"
405
+ """JSON result key naming the tier that served the call, or null."""
406
+
407
+ RESULT_KEY_OK: str = "ok"
408
+ """JSON result key holding whether the served call completed successfully."""
409
+
410
+ RESULT_KEY_ATTEMPTS: str = "attempts"
411
+ """JSON result key holding the ordered list of tier attempts."""
412
+
413
+ RESULT_KEY_OUTPUT: str = "output"
414
+ """JSON result key holding captured worker stdout from the serving tier."""
415
+
416
+ RESULT_KEY_RETURNCODE: str = "returncode"
417
+ """JSON result key holding the process return code from the last tier run."""
418
+
419
+ ATTEMPT_KEY_TIER: str = "tier"
420
+ """JSON attempt key naming the tier number tried."""
421
+
422
+ ATTEMPT_KEY_OK: str = "ok"
423
+ """JSON attempt key holding whether that tier completed successfully."""
424
+
425
+ ATTEMPT_KEY_REASON: str = "reason"
426
+ """JSON attempt key holding the fallthrough or handoff reason string."""
427
+
428
+ CLI_TIMEOUT_FLAG: str = "--timeout-seconds"
429
+ """CLI flag naming the per-tier timeout in seconds."""
430
+
431
+ CLI_ENABLE_CLAUDE_TIER_FLAG: str = "--enable-claude-tier"
432
+ """CLI flag that enables the headless claude chain tier on a Claude host."""
433
+
434
+ EMPTY_OUTPUT: str = ""
435
+ """Empty captured output when no tier produced stdout."""
@@ -1,4 +1,4 @@
1
- """Timing constants for sweep_empty_dirs.
1
+ """Timing constants for sweep_empty_dirs, the grok batch launcher, and code-review.
2
2
 
3
3
  Per the project's configuration conventions, timeouts, delays, and retries
4
4
  live in dev_env_scripts_constants/timing.py.
@@ -9,3 +9,9 @@ DEFAULT_AGE_SECONDS: int = 120
9
9
 
10
10
  DEFAULT_POLL_INTERVAL: int = 30
11
11
  """Seconds between sweep passes in continuous-watch mode."""
12
+
13
+ WORKER_STAGGER_SECONDS: int = 15
14
+ """Seconds between staggered headless grok worker process starts in a batch."""
15
+
16
+ DEFAULT_CODE_REVIEW_TIMEOUT_SECONDS: int = 600
17
+ """Default timeout applied to one headless `/code-review` chain invocation, in seconds."""