claude-dev-env 2.2.1 → 2.4.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 (170) hide show
  1. package/CLAUDE.md +3 -2
  2. package/_shared/advisor/advisor-protocol.md +2 -2
  3. package/_shared/pr-loop/scripts/CLAUDE.md +1 -0
  4. package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -284
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -0
  6. package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +3 -3
  7. package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -0
  8. package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +5 -0
  9. package/_shared/pr-loop/scripts/stale_worktree_rule_sweep.py +107 -0
  10. package/_shared/pr-loop/scripts/tests/CLAUDE.md +2 -0
  11. package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +55 -73
  12. package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +9 -15
  13. package/_shared/pr-loop/scripts/tests/test_grant_project_claude_permissions.py +91 -1
  14. package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +88 -1
  15. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -0
  16. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -0
  17. package/_shared/pr-loop/worker-spawn.md +1 -1
  18. package/agents/CLAUDE.md +1 -0
  19. package/agents/code-verifier.md +4 -4
  20. package/agents/skill-writer-agent.md +84 -0
  21. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +141 -41
  22. package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +29 -13
  23. package/docs/CLAUDE.md +1 -0
  24. package/docs/references/CLAUDE.md +1 -0
  25. package/docs/references/code-review-enforcement.md +97 -0
  26. package/docs/wsl-docker-cowork-starter-matrix.md +89 -0
  27. package/hooks/blocking/CLAUDE.md +8 -1
  28. package/hooks/blocking/code_review_enforcement_config_bootstrap.py +53 -0
  29. package/hooks/blocking/code_review_gate_deny.py +74 -0
  30. package/hooks/blocking/code_review_pr_create_gate.py +194 -0
  31. package/hooks/blocking/code_review_push_gate.py +140 -0
  32. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +340 -0
  33. package/hooks/blocking/code_review_stamp_store.py +233 -0
  34. package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +7 -0
  35. package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +15 -0
  36. package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +212 -0
  37. package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +138 -0
  38. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +49 -0
  39. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +38 -0
  40. package/hooks/blocking/code_verifier_spawn_preflight_gate.py +39 -27
  41. package/hooks/blocking/config/code_review_enforcement_constants.py +110 -0
  42. package/hooks/blocking/config/test_code_review_enforcement_constants.py +108 -0
  43. package/hooks/blocking/config/verified_commit_constants.py +24 -9
  44. package/hooks/blocking/conftest.py +2 -0
  45. package/hooks/blocking/convergence_gate_blocker.py +112 -23
  46. package/hooks/blocking/destructive_command_blocker.py +19 -6
  47. package/hooks/blocking/pr_description_proof_of_work.py +52 -34
  48. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +4 -1
  49. package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +62 -0
  50. package/hooks/blocking/test_code_review_gate_deny.py +54 -0
  51. package/hooks/blocking/test_code_review_pr_create_gate.py +185 -0
  52. package/hooks/blocking/test_code_review_push_gate.py +189 -0
  53. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +180 -0
  54. package/hooks/blocking/test_code_review_stamp_store.py +205 -0
  55. package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +124 -2
  56. package/hooks/blocking/test_code_verifier_tools_contract.py +28 -0
  57. package/hooks/blocking/test_convergence_gate_blocker.py +153 -5
  58. package/hooks/blocking/test_destructive_command_blocker.py +1 -1
  59. package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +45 -0
  60. package/hooks/blocking/test_pr_description_proof_of_work.py +151 -0
  61. package/hooks/blocking/test_pre_tool_use_dispatcher.py +8 -8
  62. package/hooks/blocking/test_verification_verdict_store.py +920 -810
  63. package/hooks/blocking/test_volatile_path_in_post_blocker.py +114 -2
  64. package/hooks/blocking/verification_verdict_store.py +118 -5
  65. package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +29 -17
  66. package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +35 -0
  67. package/hooks/blocking/volatile_path_in_post_blocker.py +69 -8
  68. package/hooks/git-hooks/git_hooks_constants/__init__.py +6 -0
  69. package/hooks/git-hooks/pre_push.py +89 -2
  70. package/hooks/git-hooks/test_pre_push.py +103 -0
  71. package/hooks/hooks.json +16 -1
  72. package/hooks/hooks_constants/CLAUDE.md +1 -0
  73. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +8 -0
  74. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
  75. package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +26 -11
  76. package/hooks/hooks_constants/convergence_gate_blocker_constants.py +20 -3
  77. package/hooks/hooks_constants/destructive_command_segment_constants.py +3 -1
  78. package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -4
  79. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
  80. package/hooks/hooks_constants/pyproject_config_discovery_constants.py +16 -0
  81. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +24 -0
  82. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +6 -0
  83. package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +8 -1
  84. package/hooks/validators/CLAUDE.md +1 -0
  85. package/hooks/validators/mypy_integration.py +63 -50
  86. package/hooks/validators/pyproject_config_discovery.py +101 -0
  87. package/hooks/validators/ruff_integration.py +211 -23
  88. package/hooks/validators/run_all_validators.py +21 -14
  89. package/hooks/validators/test_mypy_integration.py +32 -0
  90. package/hooks/validators/test_pyproject_config_discovery.py +94 -0
  91. package/hooks/validators/test_ruff_integration.py +68 -1
  92. package/hooks/validators/test_run_all_validators.py +25 -0
  93. package/hooks/validators/test_run_all_validators_config_discovery.py +123 -0
  94. package/package.json +1 -1
  95. package/rules/docstring-prose-matches-implementation.md +20 -43
  96. package/rules/durable-post-artifacts.md +7 -0
  97. package/scripts/CLAUDE.md +2 -1
  98. package/scripts/claude-chain.example.json +15 -3
  99. package/scripts/claude_chain_runner.py +130 -27
  100. package/scripts/claude_chain_usage.py +346 -0
  101. package/scripts/codec_forwarding_test_support.py +83 -0
  102. package/scripts/conftest.py +8 -0
  103. package/scripts/dev_env_scripts_constants/CLAUDE.md +4 -3
  104. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +57 -2
  105. package/scripts/dev_env_scripts_constants/claude_chain_usage_constants.py +58 -0
  106. package/scripts/dev_env_scripts_constants/code_review_constants.py +129 -12
  107. package/scripts/dev_env_scripts_constants/test_code_review_constants.py +55 -0
  108. package/scripts/dev_env_scripts_constants/timing.py +1 -1
  109. package/scripts/invoke_code_review.py +550 -38
  110. package/scripts/resolve_worker_spawn.py +8 -1
  111. package/scripts/test_claude_chain_runner.py +412 -6
  112. package/scripts/test_claude_chain_usage.py +534 -0
  113. package/scripts/test_invoke_code_review.py +298 -4
  114. package/scripts/test_invoke_code_review_codec.py +77 -0
  115. package/scripts/test_resolve_worker_spawn_codec.py +101 -0
  116. package/skills/autoconverge/SKILL.md +9 -3
  117. package/skills/autoconverge/reference/convergence.md +2 -1
  118. package/skills/autoconverge/reference/multi-pr.md +6 -1
  119. package/skills/autoconverge/reference/stop-conditions.md +16 -10
  120. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +1 -1
  121. package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +175 -3
  122. package/skills/autoconverge/workflow/converge.contract.test.mjs +19 -0
  123. package/skills/autoconverge/workflow/converge.mjs +24 -8
  124. package/skills/autoconverge/workflow/converge_multi.mjs +7 -3
  125. package/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +5 -0
  126. package/skills/fresh-branch/CLAUDE.md +2 -0
  127. package/skills/fresh-branch/SKILL.md +2 -0
  128. package/skills/fresh-branch/scripts/create_fresh_branch.py +78 -180
  129. package/skills/fresh-branch/scripts/fresh_branch_git_commands.py +285 -0
  130. package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -0
  131. package/skills/fresh-branch/scripts/pytest.ini +4 -0
  132. package/skills/fresh-branch/scripts/test_create_fresh_branch.py +98 -0
  133. package/skills/fresh-branch/scripts/test_fresh_branch_git_commands.py +310 -0
  134. package/skills/orchestrator/SKILL.md +1 -20
  135. package/skills/orchestrator-refresh/SKILL.md +1 -1
  136. package/skills/pr-converge/SKILL.md +3 -3
  137. package/skills/pr-converge/reference/examples.md +3 -3
  138. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  139. package/skills/pr-converge/reference/ground-rules.md +3 -3
  140. package/skills/pr-converge/reference/per-tick.md +5 -5
  141. package/skills/pr-converge/reference/progress-checklist.md +1 -1
  142. package/skills/pr-converge/test_step5_host_branch.py +1 -1
  143. package/skills/prototype/SKILL.md +86 -0
  144. package/skills/prototype/reference/honest-limitations.md +23 -0
  145. package/skills/prototype/reference/promotion-tasks.md +23 -0
  146. package/skills/prototype/scripts/build_sandbox_settings.py +249 -0
  147. package/skills/prototype/scripts/conftest.py +15 -0
  148. package/skills/prototype/scripts/launch_sandbox.py +205 -0
  149. package/skills/prototype/scripts/probe_sandbox_safety.py +311 -0
  150. package/skills/prototype/scripts/prototype_scripts_constants/__init__.py +1 -0
  151. package/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  152. package/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +41 -0
  153. package/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +23 -0
  154. package/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +45 -0
  155. package/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +10 -0
  156. package/skills/prototype/scripts/test_build_sandbox_settings.py +275 -0
  157. package/skills/prototype/scripts/test_launch_sandbox.py +303 -0
  158. package/skills/prototype/scripts/test_probe_sandbox_safety.py +284 -0
  159. package/skills/prototype/workflows/promotion.md +27 -0
  160. package/skills/prototype/workflows/sandbox.md +35 -0
  161. package/skills/skill-builder/CLAUDE.md +3 -3
  162. package/skills/skill-builder/SKILL.md +5 -5
  163. package/skills/skill-builder/references/CLAUDE.md +1 -1
  164. package/skills/skill-builder/references/delegation-map.md +3 -3
  165. package/skills/skill-builder/references/description-field.md +1 -1
  166. package/skills/skill-builder/references/skill-modularity.md +2 -3
  167. package/skills/skill-builder/workflows/CLAUDE.md +1 -1
  168. package/skills/skill-builder/workflows/improve-skill.md +1 -1
  169. package/skills/skill-builder/workflows/new-skill.md +2 -2
  170. package/skills/team-advisor/SKILL.md +5 -4
@@ -146,6 +146,21 @@ def build_repo_with_origin(workspace_path: Path) -> Path:
146
146
  return clone_path
147
147
 
148
148
 
149
+ def read_branch_config(
150
+ repository_path: Path,
151
+ branch_name: str,
152
+ config_leaf: str,
153
+ ) -> str:
154
+ completed = subprocess.run(
155
+ ["git", "config", "--get", f"branch.{branch_name}.{config_leaf}"],
156
+ cwd=str(repository_path),
157
+ check=False,
158
+ capture_output=True,
159
+ text=True,
160
+ )
161
+ return completed.stdout.strip()
162
+
163
+
149
164
  def read_head_branch(repository_path: Path) -> str:
150
165
  completed = run_git(["rev-parse", "--abbrev-ref", "HEAD"], repository_path)
151
166
  return completed.stdout.strip()
@@ -156,6 +171,14 @@ def read_head_commit(repository_path: Path) -> str:
156
171
  return completed.stdout.strip()
157
172
 
158
173
 
174
+ def read_remote_main_commit(repository_path: Path) -> str:
175
+ completed = run_git(
176
+ ["ls-remote", REMOTE_NAME, f"refs/heads/{MAIN_BRANCH_NAME}"],
177
+ repository_path,
178
+ )
179
+ return completed.stdout.split()[0]
180
+
181
+
159
182
  class TestResolveAgentSlug:
160
183
  def should_prefer_flag_over_environment(
161
184
  self,
@@ -512,6 +535,81 @@ class TestCreateFreshBranchIntegration:
512
535
  assert read_head_commit(worktree_path) != local_main_commit
513
536
 
514
537
 
538
+ class TestWorktreeBranchTracking:
539
+ def should_leave_new_branch_without_an_upstream(
540
+ self,
541
+ tmp_path: Path,
542
+ monkeypatch: pytest.MonkeyPatch,
543
+ ) -> None:
544
+ module = load_create_fresh_branch_module()
545
+ repository_path = build_repo_with_origin(tmp_path / "repo")
546
+ agent_scratch_parent = tmp_path / "agent-scratch"
547
+ monkeypatch.setattr(module.sys, "platform", "linux")
548
+ monkeypatch.setattr(
549
+ module.tempfile,
550
+ "gettempdir",
551
+ lambda: str(agent_scratch_parent),
552
+ )
553
+ success_payload = module.create_fresh_branch(
554
+ branch_name="fix/no-upstream",
555
+ repo_path=repository_path,
556
+ agent_slug="claude",
557
+ base_ref=DEFAULT_BASE_REF,
558
+ )
559
+ worktree_path = Path(success_payload[PAYLOAD_KEY_WORKTREE_PATH])
560
+ assert read_head_branch(worktree_path) == "fix/no-upstream"
561
+ assert read_branch_config(repository_path, "fix/no-upstream", "merge") == ""
562
+ assert read_branch_config(repository_path, "fix/no-upstream", "remote") == ""
563
+
564
+ def should_not_aim_a_bare_push_at_main_under_push_default_upstream(
565
+ self,
566
+ tmp_path: Path,
567
+ monkeypatch: pytest.MonkeyPatch,
568
+ ) -> None:
569
+ module = load_create_fresh_branch_module()
570
+ repository_path = build_repo_with_origin(tmp_path / "repo")
571
+ empty_hooks_path = tmp_path / "repo" / "empty-hooks"
572
+ run_git(
573
+ ["config", "push.default", "upstream"],
574
+ repository_path,
575
+ empty_hooks_path=empty_hooks_path,
576
+ )
577
+ agent_scratch_parent = tmp_path / "agent-scratch"
578
+ monkeypatch.setattr(module.sys, "platform", "linux")
579
+ monkeypatch.setattr(
580
+ module.tempfile,
581
+ "gettempdir",
582
+ lambda: str(agent_scratch_parent),
583
+ )
584
+ success_payload = module.create_fresh_branch(
585
+ branch_name="feature/silent-push",
586
+ repo_path=repository_path,
587
+ agent_slug="claude",
588
+ base_ref=DEFAULT_BASE_REF,
589
+ )
590
+ worktree_path = Path(success_payload[PAYLOAD_KEY_WORKTREE_PATH])
591
+ (worktree_path / SEED_FILE_NAME).write_text("drive-by\n", encoding="utf-8")
592
+ run_git(["add", SEED_FILE_NAME], worktree_path, empty_hooks_path=empty_hooks_path)
593
+ run_git(
594
+ ["commit", "-m", "work on the feature branch"],
595
+ worktree_path,
596
+ empty_hooks_path=empty_hooks_path,
597
+ )
598
+ origin_main_before = read_remote_main_commit(repository_path)
599
+ push_attempt = subprocess.run(
600
+ ["git", "-c", f"core.hooksPath={empty_hooks_path}", "push"],
601
+ cwd=str(worktree_path),
602
+ check=False,
603
+ capture_output=True,
604
+ text=True,
605
+ )
606
+ assert push_attempt.returncode != 0, (
607
+ "bare push should be refused, but it succeeded:\n"
608
+ f"{push_attempt.stdout}{push_attempt.stderr}"
609
+ )
610
+ assert read_remote_main_commit(repository_path) == origin_main_before
611
+
612
+
515
613
  class TestMainCli:
516
614
  def should_print_success_json_and_exit_zero(
517
615
  self,
@@ -0,0 +1,310 @@
1
+ """Behavioral tests for fresh_branch_git_commands using real temporary git repos."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import subprocess
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
12
+ if str(SCRIPTS_DIRECTORY) not in sys.path:
13
+ sys.path.insert(0, str(SCRIPTS_DIRECTORY))
14
+
15
+ from fresh_branch_git_commands import (
16
+ assert_git_accepts_branch_name,
17
+ build_worktree_add_arguments,
18
+ create_worktree_branch,
19
+ fetch_base_ref,
20
+ is_ref_present,
21
+ read_failure_text,
22
+ resolve_base_commit,
23
+ resolve_repo_root,
24
+ run_git,
25
+ split_remote_ref,
26
+ )
27
+
28
+ GIT_USER_NAME = "fresh-branch-test"
29
+ GIT_USER_EMAIL = "fresh-branch-test@example.com"
30
+ MAIN_BRANCH_NAME = "main"
31
+ SEED_FILE_NAME = "README.md"
32
+ SEED_FILE_CONTENTS = "seed\n"
33
+
34
+
35
+ def build_repo(workspace_path: Path) -> Path:
36
+ workspace_path.mkdir(parents=True, exist_ok=True)
37
+ empty_hooks_path = workspace_path / "empty-hooks"
38
+ empty_hooks_path.mkdir()
39
+ hooks_argument = ["-c", f"core.hooksPath={empty_hooks_path}"]
40
+ subprocess.run(
41
+ ["git", *hooks_argument, "init", "-b", MAIN_BRANCH_NAME, str(workspace_path)],
42
+ check=True,
43
+ capture_output=True,
44
+ text=True,
45
+ )
46
+ for each_pair in (
47
+ ("user.name", GIT_USER_NAME),
48
+ ("user.email", GIT_USER_EMAIL),
49
+ ("commit.gpgsign", "false"),
50
+ ):
51
+ subprocess.run(
52
+ ["git", *hooks_argument, "config", *each_pair],
53
+ cwd=str(workspace_path),
54
+ check=True,
55
+ capture_output=True,
56
+ text=True,
57
+ )
58
+ (workspace_path / SEED_FILE_NAME).write_text(SEED_FILE_CONTENTS, encoding="utf-8")
59
+ subprocess.run(
60
+ ["git", *hooks_argument, "add", SEED_FILE_NAME],
61
+ cwd=str(workspace_path),
62
+ check=True,
63
+ capture_output=True,
64
+ text=True,
65
+ )
66
+ subprocess.run(
67
+ ["git", *hooks_argument, "commit", "-m", "initial commit"],
68
+ cwd=str(workspace_path),
69
+ check=True,
70
+ capture_output=True,
71
+ text=True,
72
+ )
73
+ return workspace_path
74
+
75
+
76
+ def build_clone_with_origin(workspace_path: Path) -> tuple[Path, Path]:
77
+ seed_path = build_repo(workspace_path / "seed")
78
+ empty_hooks_path = seed_path / "empty-hooks"
79
+ hooks_argument = ["-c", f"core.hooksPath={empty_hooks_path}"]
80
+ bare_origin = workspace_path / "origin.git"
81
+ subprocess.run(
82
+ ["git", *hooks_argument, "clone", "--bare", str(seed_path), str(bare_origin)],
83
+ check=True,
84
+ capture_output=True,
85
+ text=True,
86
+ )
87
+ clone_path = workspace_path / "clone"
88
+ subprocess.run(
89
+ ["git", *hooks_argument, "clone", str(bare_origin), str(clone_path)],
90
+ check=True,
91
+ capture_output=True,
92
+ text=True,
93
+ )
94
+ for each_pair in (
95
+ ("user.name", GIT_USER_NAME),
96
+ ("user.email", GIT_USER_EMAIL),
97
+ ("commit.gpgsign", "false"),
98
+ ):
99
+ subprocess.run(
100
+ ["git", *hooks_argument, "config", *each_pair],
101
+ cwd=str(clone_path),
102
+ check=True,
103
+ capture_output=True,
104
+ text=True,
105
+ )
106
+ return clone_path, bare_origin
107
+
108
+
109
+ def advance_origin_main(workspace_path: Path, bare_origin: Path) -> str:
110
+ pusher_path = workspace_path / "pusher"
111
+ empty_hooks_path = workspace_path / "seed" / "empty-hooks"
112
+ hooks_argument = ["-c", f"core.hooksPath={empty_hooks_path}"]
113
+ subprocess.run(
114
+ ["git", *hooks_argument, "clone", str(bare_origin), str(pusher_path)],
115
+ check=True,
116
+ capture_output=True,
117
+ text=True,
118
+ )
119
+ for each_pair in (
120
+ ("user.name", GIT_USER_NAME),
121
+ ("user.email", GIT_USER_EMAIL),
122
+ ("commit.gpgsign", "false"),
123
+ ):
124
+ subprocess.run(
125
+ ["git", *hooks_argument, "config", *each_pair],
126
+ cwd=str(pusher_path),
127
+ check=True,
128
+ capture_output=True,
129
+ text=True,
130
+ )
131
+ (pusher_path / SEED_FILE_NAME).write_text("advanced\n", encoding="utf-8")
132
+ subprocess.run(
133
+ ["git", *hooks_argument, "commit", "-am", "advance main"],
134
+ cwd=str(pusher_path),
135
+ check=True,
136
+ capture_output=True,
137
+ text=True,
138
+ )
139
+ subprocess.run(
140
+ ["git", *hooks_argument, "push", "origin", MAIN_BRANCH_NAME],
141
+ cwd=str(pusher_path),
142
+ check=True,
143
+ capture_output=True,
144
+ text=True,
145
+ )
146
+ completed = subprocess.run(
147
+ ["git", "rev-parse", "HEAD"],
148
+ cwd=str(pusher_path),
149
+ check=True,
150
+ capture_output=True,
151
+ text=True,
152
+ )
153
+ return completed.stdout.strip()
154
+
155
+
156
+ def read_branch_config(
157
+ repository_path: Path,
158
+ branch_name: str,
159
+ config_leaf: str,
160
+ ) -> str:
161
+ completed = subprocess.run(
162
+ ["git", "config", "--get", f"branch.{branch_name}.{config_leaf}"],
163
+ cwd=str(repository_path),
164
+ check=False,
165
+ capture_output=True,
166
+ text=True,
167
+ )
168
+ return completed.stdout.strip()
169
+
170
+
171
+ class TestBuildWorktreeAddArguments:
172
+ def test_pass_no_track_so_the_new_branch_gets_no_upstream(self) -> None:
173
+ all_arguments = build_worktree_add_arguments(
174
+ "fix/x",
175
+ Path("/tmp/agent/fix/x"),
176
+ "origin/main",
177
+ )
178
+ assert "--no-track" in all_arguments
179
+
180
+ def test_order_arguments_the_way_git_worktree_add_expects(self) -> None:
181
+ all_arguments = build_worktree_add_arguments(
182
+ "fix/x",
183
+ Path("/tmp/agent/fix/x"),
184
+ "origin/main",
185
+ )
186
+ assert all_arguments[:4] == ["worktree", "add", "-b", "fix/x"]
187
+ assert all_arguments[-1] == "origin/main"
188
+ assert all_arguments[-2] == str(Path("/tmp/agent/fix/x"))
189
+
190
+
191
+ class TestSplitRemoteRef:
192
+ def test_split_an_origin_ref(self) -> None:
193
+ assert split_remote_ref("origin/main") == ("origin", "main")
194
+
195
+ def test_split_a_non_origin_remote_ref(self) -> None:
196
+ assert split_remote_ref("upstream/dev") == ("upstream", "dev")
197
+
198
+ def test_default_a_bare_name_to_origin(self) -> None:
199
+ assert split_remote_ref("main") == ("origin", "main")
200
+
201
+ def test_keep_slashes_inside_the_branch_name(self) -> None:
202
+ assert split_remote_ref("origin/fix/nested") == ("origin", "fix/nested")
203
+
204
+
205
+ class TestAssertGitAcceptsBranchName:
206
+ def test_accept_a_conventional_branch_name(self) -> None:
207
+ assert assert_git_accepts_branch_name("fix/example-one") is None
208
+
209
+ def test_reject_a_name_git_refuses(self) -> None:
210
+ with pytest.raises(ValueError, match="relative path"):
211
+ assert_git_accepts_branch_name("fix..example")
212
+
213
+
214
+ class TestResolveRepoRoot:
215
+ def test_return_the_toplevel_for_a_nested_path(self, tmp_path: Path) -> None:
216
+ repository_path = build_repo(tmp_path / "repo")
217
+ nested_path = repository_path / "nested"
218
+ nested_path.mkdir()
219
+ assert resolve_repo_root(nested_path).resolve() == repository_path.resolve()
220
+
221
+ def test_raise_outside_a_repository(self, tmp_path: Path) -> None:
222
+ plain_directory = tmp_path / "plain"
223
+ plain_directory.mkdir()
224
+ with pytest.raises(RuntimeError, match="git repository"):
225
+ resolve_repo_root(plain_directory)
226
+
227
+
228
+ class TestIsRefPresent:
229
+ def test_find_a_local_branch(self, tmp_path: Path) -> None:
230
+ repository_path = build_repo(tmp_path / "repo")
231
+ assert is_ref_present(repository_path, MAIN_BRANCH_NAME) is True
232
+
233
+ def test_not_find_an_absent_ref(self, tmp_path: Path) -> None:
234
+ repository_path = build_repo(tmp_path / "repo")
235
+ assert is_ref_present(repository_path, "origin/nowhere") is False
236
+
237
+
238
+ class TestReadFailureText:
239
+ def test_prefer_stderr(self, tmp_path: Path) -> None:
240
+ repository_path = build_repo(tmp_path / "repo")
241
+ completed = run_git(["rev-parse", "does-not-exist"], repository_path)
242
+ assert completed.returncode != 0
243
+ assert "does-not-exist" in read_failure_text(completed)
244
+
245
+
246
+ class TestFetchBaseRef:
247
+ def test_bring_the_remote_tip_into_the_clone(self, tmp_path: Path) -> None:
248
+ clone_path, bare_origin = build_clone_with_origin(tmp_path / "workspace")
249
+ advanced_commit = advance_origin_main(tmp_path / "workspace", bare_origin)
250
+ fetch_base_ref(clone_path, "origin/main")
251
+ assert is_ref_present(clone_path, "origin/main") is True
252
+ assert resolve_base_commit(clone_path, "origin/main") == advanced_commit
253
+
254
+ def test_raise_for_a_remote_branch_that_does_not_exist(
255
+ self,
256
+ tmp_path: Path,
257
+ ) -> None:
258
+ clone_path, _bare_origin = build_clone_with_origin(tmp_path / "workspace")
259
+ with pytest.raises(RuntimeError, match="git fetch failed"):
260
+ fetch_base_ref(clone_path, "origin/nowhere")
261
+
262
+
263
+ class TestResolveBaseCommit:
264
+ def test_return_the_sha_at_the_ref(self, tmp_path: Path) -> None:
265
+ repository_path = build_repo(tmp_path / "repo")
266
+ head_commit = run_git(["rev-parse", "HEAD"], repository_path).stdout.strip()
267
+ assert resolve_base_commit(repository_path, MAIN_BRANCH_NAME) == head_commit
268
+
269
+ def test_raise_for_an_unresolvable_ref(self, tmp_path: Path) -> None:
270
+ repository_path = build_repo(tmp_path / "repo")
271
+ with pytest.raises(RuntimeError, match="could not resolve base commit"):
272
+ resolve_base_commit(repository_path, "refs/heads/nowhere")
273
+
274
+
275
+ class TestCreateWorktreeBranch:
276
+ def test_create_the_branch_at_the_base_ref_with_no_upstream(
277
+ self,
278
+ tmp_path: Path,
279
+ ) -> None:
280
+ clone_path, _bare_origin = build_clone_with_origin(tmp_path / "workspace")
281
+ origin_tip = resolve_base_commit(clone_path, "origin/main")
282
+ worktree_path = tmp_path / "worktrees" / "fix" / "created"
283
+ create_worktree_branch(
284
+ clone_path,
285
+ branch_name="fix/created",
286
+ worktree_path=worktree_path,
287
+ base_ref="origin/main",
288
+ )
289
+ assert worktree_path.is_dir()
290
+ assert resolve_base_commit(worktree_path, "HEAD") == origin_tip
291
+ assert read_branch_config(clone_path, "fix/created", "merge") == ""
292
+ assert read_branch_config(clone_path, "fix/created", "remote") == ""
293
+
294
+ def test_raise_when_the_branch_already_exists(self, tmp_path: Path) -> None:
295
+ clone_path, _bare_origin = build_clone_with_origin(tmp_path / "workspace")
296
+ first_path = tmp_path / "worktrees" / "dup-one"
297
+ second_path = tmp_path / "worktrees" / "dup-two"
298
+ create_worktree_branch(
299
+ clone_path,
300
+ branch_name="fix/dup",
301
+ worktree_path=first_path,
302
+ base_ref="origin/main",
303
+ )
304
+ with pytest.raises(RuntimeError, match="worktree add failed"):
305
+ create_worktree_branch(
306
+ clone_path,
307
+ branch_name="fix/dup",
308
+ worktree_path=second_path,
309
+ base_ref="origin/main",
310
+ )
@@ -30,32 +30,13 @@ The moment it edits a file or runs a test itself, the pairing breaks —
30
30
  its own tool use stays orchestration, run-artifact writes, and light
31
31
  verification reads.
32
32
 
33
- ## Design rule — thin prompts, thick artifacts, thin skill
34
-
35
- Three faces of one rule (reading pinned by the audit spec on
36
- jl-cmd/claude-dev-env#174: thin means high-signal, not short; thick
37
- context lives outside the window, reachable by pointers):
38
-
39
- - **Thin prompts.** A spawn prompt is a dispatch ticket: one task,
40
- pointers to the artifacts that hold the context, one done-check, a thin
41
- return contract. The prompt can be thin because the context is thick
42
- elsewhere.
43
- - **Thick artifacts.** Durable run state lives in files — the run
44
- charter, one assignment file per task, result records — written once,
45
- read by every agent that needs them, and still there when any one
46
- agent's context is gone.
47
- - **Thin skill.** This file holds only what changes decisions at
48
- orchestration time. Standing policy lives where it loads once:
49
- [`_shared/advisor/advisor-protocol.md`](../../_shared/advisor/advisor-protocol.md)
50
- for everything advisor, the agent definitions for executor discipline.
51
-
52
33
  ## Process
53
34
 
54
35
  1. **Invocation guard.** One `/orchestrator` per session. When the
55
36
  refresh loop is already running, do not schedule a second one; reuse
56
37
  the live advisor bind and go to step 4.
57
38
  2. **Register the discipline reminder.** Schedule it with
58
- `ScheduleWakeup` at `delaySeconds: 1800`, prompt
39
+ `ScheduleWakeup` at `delaySeconds: 2700`, prompt
59
40
  `/orchestrator-refresh`, where each refresh re-schedules the next one.
60
41
  3. **Bind the shared advisor before any executor.** Follow
61
42
  [`_shared/advisor/advisor-protocol.md`](../../_shared/advisor/advisor-protocol.md)
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: orchestrator-refresh
3
3
  description: >-
4
- Fired by the /orchestrator loop reminder about every 20 minutes to
4
+ Fired by the /orchestrator loop reminder about every 45 minutes to
5
5
  re-assert the advisor discipline mid-run: orchestrate, route hard decisions
6
6
  to the shared advisor (ENDORSE / CORRECTION / PLAN / STOP — SendMessage on
7
7
  Claude, Claude CLI chain on a third-party host), reuse warm agents. Triggers:
@@ -195,7 +195,7 @@ the `persistent_agents` map
195
195
  record it, and continue the tick. Never abort a tick on a stale id;
196
196
  never retry the same dead id.
197
197
  - **Fresh every round (never persisted):** the Step 5 host-aware
198
- `invoke_code_review.py` / `/code-review high --fix` pass and the Step 6
198
+ `invoke_code_review.py` / `/code-review xhigh --fix` pass and the Step 6
199
199
  bugteam audit (unbiased eyes each round; the enforcer needs the formal
200
200
  Skill call), and every `code-verifier` — a named code-verifier never fires
201
201
  `SubagentStop`, so no verdict mints (see the named-`code-verifier` entry
@@ -253,7 +253,7 @@ post a fresh PR in a fresh branch based on origin main to the user.
253
253
  Windows is Git Bash which cannot execute PowerShell cmdlets. Route all
254
254
  PowerShell work through the PowerShell tool or `pwsh -NoProfile -File`.
255
255
  - **Cross-repo PR: route cwd into the PR worktree before Step 5 review** —
256
- `invoke_code_review.py` and `/code-review high --fix` audit the repo of the
256
+ `invoke_code_review.py` and `/code-review xhigh --fix` audit the repo of the
257
257
  cwd (the helper's `--cwd`). When the session is rooted in a different repo
258
258
  than the PR, `EnterWorktree` cannot re-root (it is scoped to the session's
259
259
  repo); resolve the PR worktree and `cd` into it per
@@ -351,7 +351,7 @@ round as converged. This rule holds every tick, every loop, every PR.
351
351
  - [ ] **Static sweep fails** → apply shared fix protocol → push → reset markers
352
352
  → stay CODE_REVIEW → Step 5
353
353
  - [ ] **`mode == in_session`** (Claude host, session model opus) → run
354
- `/code-review high --fix` in-session (no path args)
354
+ `/code-review xhigh --fix` in-session (no path args)
355
355
  - [ ] **`mode == chain`** (any other host or non-opus session) → helper
356
356
  already ran the headless review; read `returncode`,
357
357
  `served_command`, and `dirty_tree` from JSON
@@ -18,7 +18,7 @@ resets push-invalidated markers per [ground-rules.md](ground-rules.md) /
18
18
  at 270s, re-runs the sweep next tick]
19
19
  </example>
20
20
 
21
- <example> CODE_REVIEW tick, static sweep clean, `/code-review high --fix`
21
+ <example> CODE_REVIEW tick, static sweep clean, `/code-review xhigh --fix`
22
22
  applies fixes to the working tree. Claude: [commits the applied fixes in one
23
23
  commit, pushes, resets push-invalidated markers per
24
24
  [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md) (all
@@ -26,7 +26,7 @@ commit, pushes, resets push-invalidated markers per
26
26
  stays `phase = CODE_REVIEW`, Step 4 at 270s, returns]
27
27
  </example>
28
28
 
29
- <example> CODE_REVIEW tick, static sweep clean and `/code-review high --fix`
29
+ <example> CODE_REVIEW tick, static sweep clean and `/code-review xhigh --fix`
30
30
  clean (no changes applied). Claude: [sets `code_review_clean_at = HEAD`,
31
31
  `phase = BUGTEAM`, runs `Skill({skill: "bugteam", ...})` in same tick]
32
32
  </example>
@@ -94,7 +94,7 @@ applies **Convergence** from `workflows/schedule-wakeup-loop.md`]
94
94
 
95
95
  <example> CODE_REVIEW tick, review body says "found 3 potential issues"
96
96
  against HEAD (a stale prior finding) but the diff is clean. Claude: [the static
97
- sweep and `/code-review high --fix` both pass, sets `code_review_clean_at =
97
+ sweep and `/code-review xhigh --fix` both pass, sets `code_review_clean_at =
98
98
  HEAD`, `phase = BUGTEAM`]
99
99
  </example>
100
100
 
@@ -32,6 +32,6 @@ files during fix phase in multi-PR mode.
32
32
  regardless of phase. A new commit **resets the full convergence cycle**: a
33
33
  code-review clean, a bugteam clean, and a Bugbot clean on an older SHA do
34
34
  **not** count toward convergence on the new `HEAD`. Re-run the static sweep and
35
- `/code-review high --fix` on `current_head`, then bugteam, then the terminal
35
+ `/code-review xhigh --fix` on `current_head`, then bugteam, then the terminal
36
36
  Bugbot gate, all on the same `HEAD` with no intervening push. Re-entering in the
37
37
  same tick saves a wakeup cycle.
@@ -10,11 +10,11 @@
10
10
  - **All `*_clean_at`, `merge_state_status`, and `bugbot_down` / `codex_down` reset on every push.**
11
11
  - **`bugbot run` comment is load-bearing.** Literal phrase exactly —
12
12
  empirically the only re-trigger Cursor Bugbot recognizes.
13
- - **Production edits go through `clean-coder`, except `/code-review high --fix`.**
13
+ - **Production edits go through `clean-coder`, except `/code-review xhigh --fix`.**
14
14
  The lead never hand-edits production files. Every bugbot, bugteam,
15
15
  Copilot, or Claude finding spawns `Agent(subagent_type="clean-coder")` to
16
16
  apply the fix. The CODE_REVIEW phase is the one exception: `/code-review
17
- high --fix` applies its own findings to the working tree, which the next
17
+ xhigh --fix` applies its own findings to the working tree, which the next
18
18
  CODE_REVIEW/BUGTEAM cycle re-reviews after the loop resets.
19
19
  - **Adapt when reality contradicts on-disk state.** If `state.json`,
20
20
  `git`, or `gh` disagree with live PR, escalate as hard blocker per
@@ -22,7 +22,7 @@
22
22
  - **Cross-repo cwd routing is routine, not a fork.** When the PR under
23
23
  convergence lives in a different repo than the session is rooted in, route
24
24
  the working directory into a checkout of the PR's repo automatically —
25
- `/code-review high --fix`, `git`, and every `clean-coder` fix spawn act on the
25
+ `/code-review xhigh --fix`, `git`, and every `clean-coder` fix spawn act on the
26
26
  repo of the current working directory. The resolution is fixed
27
27
  ([per-tick.md § Step 1.5](per-tick.md)): resolve the PR worktree, `cd` into
28
28
  it, run local work there. Do not pause, ask, or raise it as a material fork.
@@ -71,7 +71,7 @@ Capture `number`, `head.sha` (= `current_head`), owner/repo, branch.
71
71
 
72
72
  The **PR worktree** is the local working tree of the PR's repo on its head
73
73
  branch. Every local operation this tick runs there: the CODE_REVIEW static sweep
74
- and `/code-review high --fix`, every `clean-coder` fix spawn, and every commit and
74
+ and `/code-review xhigh --fix`, every `clean-coder` fix spawn, and every commit and
75
75
  push. `/code-review` and `git` both act on the repo of the current working
76
76
  directory, so the working directory must be the PR worktree before any local
77
77
  work begins. Re-resolve it every tick — a rebase or a fresh HEAD can move the
@@ -180,7 +180,7 @@ CODE_REVIEW.
180
180
  ### `phase == CODE_REVIEW`
181
181
 
182
182
  The entry phase of every convergence tick, re-entered after any fix push. It runs
183
- a deterministic static sweep, then the built-in `/code-review high --fix` on the
183
+ a deterministic static sweep, then the built-in `/code-review xhigh --fix` on the
184
184
  full `origin/main...HEAD` diff at effort high on model opus. `/code-review`
185
185
  produces no GitHub review artifact, so there are no code-review threads to
186
186
  resolve.
@@ -196,7 +196,7 @@ a. **Static sweep — runs first, before `/code-review`.** Run the deterministic
196
196
  `phase = CODE_REVIEW`, and re-run the sweep. When the sweep is clean, run
197
197
  the host-aware review below.
198
198
 
199
- b. Run the built-in `/code-review high --fix` on the FULL `origin/main...HEAD`
199
+ b. Run the built-in `/code-review xhigh --fix` with OPUS on the FULL `origin/main...HEAD`
200
200
  diff — every file the PR touches — via the
201
201
  [local diff review](https://code.claude.com/docs/en/code-review#review-a-diff-locally).
202
202
  The review always runs at effort high on model opus. It reviews the diff and
@@ -231,14 +231,14 @@ b. Run the built-in `/code-review high --fix` on the FULL `origin/main...HEAD`
231
231
  Match the first mode whose predicate holds:
232
232
 
233
233
  - **`mode == "in_session"`** (Claude host and session model is opus): run
234
- `/code-review high --fix` in this session with no path arguments so it
234
+ `/code-review xhigh --fix` with OPUS in this session with no path arguments so it
235
235
  audits the whole branch diff against `origin/main`. After it returns, a
236
236
  non-empty `git status --porcelain` means fixes applied (`dirty_tree`
237
237
  equivalent). Treat a failed in-session slash command the same as a failed
238
238
  review: do not set `code_review_clean_at`.
239
239
  - **`mode == "chain"`** (any other host, or a Claude session on any model
240
240
  other than opus): the helper already ran the headless review
241
- (`claude -p "/code-review high --fix" --model opus` through the chain
241
+ (`claude -p "/code-review xhigh --fix" --model opus` through the chain
242
242
  runner) with cwd set to the PR worktree. Read `returncode`,
243
243
  `served_command`, and `dirty_tree` from the JSON. A successful serve is
244
244
  `returncode == 0` with a non-null `served_command`. `dirty_tree` true
@@ -91,7 +91,7 @@ round as converged. This rule holds every tick, every loop, every PR.
91
91
  - [ ] **Static sweep fails** → apply shared fix protocol → push → reset markers
92
92
  → stay CODE_REVIEW → Step 5
93
93
  - [ ] **`mode == in_session`** (Claude host, session model opus) → run
94
- `/code-review high --fix` in-session (no path args)
94
+ `/code-review xhigh --fix` in-session (no path args)
95
95
  - [ ] **`mode == chain`** (any other host or non-opus session) → helper
96
96
  already ran the headless review; read `returncode`,
97
97
  `served_command`, and `dirty_tree` from JSON
@@ -32,7 +32,7 @@ NEVER_PUSHES_PHRASE = "never pushes"
32
32
  EMPTY_STDIN_PHRASE = "empty"
33
33
  CWD_FLAG = "--cwd"
34
34
  OPUS_MODEL = "opus"
35
- HIGH_EFFORT_SLASH = "/code-review high --fix"
35
+ HIGH_EFFORT_SLASH = "/code-review xhigh --fix"
36
36
 
37
37
 
38
38
  def _read_markdown(markdown_path: Path) -> str: