cc-codeconductor 1.1.0 → 1.2.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 (143) hide show
  1. package/README.md +4 -2
  2. package/dist/core/verification/verification-runner.d.ts +7 -0
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1413 -309
  5. package/dist/library.js +29 -1
  6. package/dist/validation/schemas.d.ts +97 -26
  7. package/package.json +1 -1
  8. package/presets/agy/AGENTS.md +10 -9
  9. package/presets/agy/hooks.json +2 -2
  10. package/presets/agy/scripts/invoke-hook.cjs +115 -0
  11. package/presets/agy/skills/backlog/SKILL.md +40 -70
  12. package/presets/agy/skills/cc-spec-mutation/SKILL.md +165 -0
  13. package/presets/agy/skills/cc-tdd-cycle/SKILL.md +3 -0
  14. package/presets/agy/skills/evaluation/SKILL.md +61 -2
  15. package/presets/agy/skills/openspec/SKILL.md +49 -19
  16. package/presets/agy/skills/testing-tdd/SKILL.md +53 -0
  17. package/presets/agy/skills/using-cc-skills/SKILL.md +48 -0
  18. package/presets/agy/workflows/cc-api-contract.md +14 -0
  19. package/presets/agy/workflows/cc-db-migration.md +14 -0
  20. package/presets/agy/workflows/cc-feature.md +18 -0
  21. package/presets/agy/workflows/cc-fix.md +14 -0
  22. package/presets/agy/workflows/cc-iterative.md +14 -0
  23. package/presets/agy/workflows/cc-openspec.md +14 -0
  24. package/presets/agy/workflows/cc-scorecard.md +2 -0
  25. package/presets/agy/workflows/cc-spec-mutation.md +191 -0
  26. package/presets/agy/workflows/cc-tdd-cycle.md +14 -0
  27. package/presets/claude/commands/cc/api-contract.md +14 -0
  28. package/presets/claude/commands/cc/db-migration.md +14 -0
  29. package/presets/claude/commands/cc/feature.md +18 -0
  30. package/presets/claude/commands/cc/fix.md +17 -0
  31. package/presets/claude/commands/cc/iterative.md +14 -0
  32. package/presets/claude/commands/cc/openspec.md +14 -0
  33. package/presets/claude/commands/cc/review.md +3 -0
  34. package/presets/claude/commands/cc/scorecard.md +2 -0
  35. package/presets/claude/commands/cc/spec-mutation.md +190 -0
  36. package/presets/claude/commands/cc/tdd-cycle.md +17 -0
  37. package/presets/claude/settings.json +13 -11
  38. package/presets/claude/skills/backlog/SKILL.md +40 -70
  39. package/presets/claude/skills/evaluation/SKILL.md +47 -24
  40. package/presets/claude/skills/openspec/SKILL.md +46 -38
  41. package/presets/claude/skills/testing-tdd/SKILL.md +53 -0
  42. package/presets/claude/skills/using-cc-skills/SKILL.md +48 -0
  43. package/presets/codex/AGENTS.md +16 -12
  44. package/presets/codex/skills/backlog/SKILL.md +61 -0
  45. package/presets/codex/skills/cc-api-contract/SKILL.md +87 -0
  46. package/presets/codex/skills/cc-backlog/SKILL.md +108 -0
  47. package/presets/codex/skills/cc-clarify/SKILL.md +36 -0
  48. package/presets/codex/skills/cc-council/SKILL.md +92 -0
  49. package/presets/codex/skills/cc-db-migration/SKILL.md +88 -0
  50. package/presets/codex/skills/cc-explore/SKILL.md +40 -0
  51. package/presets/codex/skills/cc-feature/SKILL.md +154 -0
  52. package/presets/codex/skills/cc-fix/SKILL.md +165 -0
  53. package/presets/codex/skills/cc-handoff/SKILL.md +45 -0
  54. package/presets/codex/skills/cc-iterative/SKILL.md +150 -0
  55. package/presets/codex/skills/cc-openspec/SKILL.md +191 -0
  56. package/presets/codex/skills/cc-pagespeed/SKILL.md +124 -0
  57. package/presets/codex/skills/cc-prototype/SKILL.md +42 -0
  58. package/presets/codex/skills/cc-refactor/SKILL.md +163 -0
  59. package/presets/codex/skills/cc-review/SKILL.md +152 -0
  60. package/presets/codex/skills/cc-scorecard/SKILL.md +82 -0
  61. package/presets/codex/skills/cc-security/SKILL.md +182 -0
  62. package/presets/codex/skills/cc-spec-mutation/SKILL.md +192 -0
  63. package/presets/codex/skills/cc-tdd-cycle/SKILL.md +266 -0
  64. package/presets/codex/skills/cc-test-plan/SKILL.md +153 -0
  65. package/presets/codex/skills/cc-triage/SKILL.md +38 -0
  66. package/presets/codex/skills/evaluation/SKILL.md +65 -0
  67. package/presets/codex/skills/openspec/SKILL.md +66 -0
  68. package/presets/codex/skills/testing-tdd/SKILL.md +53 -0
  69. package/presets/codex/skills/using-cc-skills/SKILL.md +48 -0
  70. package/presets/cursor/commands/cc/api-contract.md +14 -0
  71. package/presets/cursor/commands/cc/db-migration.md +14 -0
  72. package/presets/cursor/commands/cc/feature.md +18 -0
  73. package/presets/cursor/commands/cc/fix.md +17 -0
  74. package/presets/cursor/commands/cc/iterative.md +14 -0
  75. package/presets/cursor/commands/cc/openspec.md +14 -0
  76. package/presets/cursor/commands/cc/scorecard.md +2 -0
  77. package/presets/cursor/commands/cc/spec-mutation.md +190 -0
  78. package/presets/cursor/commands/cc/tdd-cycle.md +14 -0
  79. package/presets/cursor/skills/backlog/SKILL.md +40 -70
  80. package/presets/cursor/skills/evaluation/SKILL.md +61 -4
  81. package/presets/cursor/skills/openspec/SKILL.md +46 -36
  82. package/presets/cursor/skills/testing-tdd/SKILL.md +35 -574
  83. package/presets/cursor/skills/using-cc-skills/SKILL.md +48 -0
  84. package/presets/gemini/commands/cc/api-contract.toml +82 -0
  85. package/presets/gemini/commands/cc/ask.toml +54 -0
  86. package/presets/gemini/commands/cc/backlog.toml +103 -0
  87. package/presets/gemini/commands/cc/clarify.toml +31 -0
  88. package/presets/gemini/commands/cc/council.toml +87 -0
  89. package/presets/gemini/commands/cc/db-migration.toml +83 -0
  90. package/presets/gemini/commands/cc/explore.toml +35 -0
  91. package/presets/gemini/commands/cc/feature.toml +153 -0
  92. package/presets/gemini/commands/cc/fix.toml +163 -0
  93. package/presets/gemini/commands/cc/handoff.toml +40 -0
  94. package/presets/gemini/commands/cc/iterative.toml +145 -0
  95. package/presets/gemini/commands/cc/openspec.toml +186 -0
  96. package/presets/gemini/commands/cc/pagespeed.toml +119 -0
  97. package/presets/gemini/commands/cc/prototype.toml +37 -0
  98. package/presets/gemini/commands/cc/refactor.toml +158 -0
  99. package/presets/gemini/commands/cc/review.toml +150 -0
  100. package/presets/gemini/commands/cc/scorecard.toml +77 -0
  101. package/presets/gemini/commands/cc/security.toml +177 -0
  102. package/presets/gemini/commands/cc/spec-mutation.toml +187 -0
  103. package/presets/gemini/commands/cc/tdd-cycle.toml +264 -0
  104. package/presets/gemini/commands/cc/test-plan.toml +148 -0
  105. package/presets/gemini/commands/cc/triage.toml +33 -0
  106. package/presets/opencode/README.md +24 -21
  107. package/presets/opencode/agents/architect.md +6 -0
  108. package/presets/opencode/agents/implementer.md +7 -0
  109. package/presets/opencode/agents/reviewer.md +6 -0
  110. package/presets/opencode/agents/tester.md +6 -0
  111. package/presets/opencode/commands/cc-api-contract.md +14 -0
  112. package/presets/opencode/commands/cc-db-migration.md +14 -0
  113. package/presets/opencode/commands/cc-feature.md +18 -0
  114. package/presets/opencode/commands/cc-fix.md +17 -0
  115. package/presets/opencode/commands/cc-iterative.md +14 -0
  116. package/presets/opencode/commands/cc-openspec.md +14 -0
  117. package/presets/opencode/commands/cc-scorecard.md +2 -0
  118. package/presets/opencode/commands/cc-spec-mutation.md +190 -0
  119. package/presets/opencode/commands/cc-tdd-cycle.md +14 -0
  120. package/presets/opencode/opencode.jsonc +1 -1
  121. package/presets/opencode/prompts/v1.0.0/architect.md +6 -0
  122. package/presets/opencode/prompts/v1.0.0/implementer.md +7 -0
  123. package/presets/opencode/prompts/v1.0.0/reviewer.md +6 -0
  124. package/presets/opencode/prompts/v1.0.0/tester.md +6 -0
  125. package/presets/opencode/skills/backlog/SKILL.md +40 -70
  126. package/presets/opencode/skills/evaluation/SKILL.md +61 -2
  127. package/presets/opencode/skills/openspec/SKILL.md +46 -34
  128. package/presets/opencode/skills/testing-tdd/SKILL.md +35 -574
  129. package/presets/opencode/skills/using-cc-skills/SKILL.md +48 -0
  130. package/presets/shared/__pycache__/mutation_runner.cpython-314.pyc +0 -0
  131. package/presets/shared/invoke-hook.cjs +115 -0
  132. package/presets/shared/mutation_runner.py +273 -0
  133. package/src/presets/manifests/agy.yml +2 -0
  134. package/src/presets/manifests/claude.yml +3 -0
  135. package/src/presets/manifests/gemini.yml +15 -0
  136. package/src/presets/models/agy.yml +24 -24
  137. package/src/presets/models/claude.yml +10 -10
  138. package/src/presets/models/codex.yml +10 -10
  139. package/src/presets/models/cursor.yml +10 -10
  140. package/src/presets/models/gemini.yml +10 -10
  141. package/src/presets/models/opencode.yml +10 -10
  142. package/presets/agy/scripts/post-tool.sh +0 -25
  143. package/presets/agy/scripts/pre-tool.sh +0 -56
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { spawnSync } = require('node:child_process');
5
+ const { existsSync } = require('node:fs');
6
+ const { join, resolve } = require('node:path');
7
+
8
+ const VALID_EVENTS = ['pre-tool', 'post-tool', 'session-start'];
9
+ const SPAWN_TIMEOUT = 10000;
10
+
11
+ const rawArgs = process.argv.slice(1);
12
+ const args = rawArgs.filter((arg) => {
13
+ if (VALID_EVENTS.includes(arg) || arg.startsWith('-')) return true;
14
+ return false;
15
+ });
16
+
17
+ const event = args.find((a) => VALID_EVENTS.includes(a)) || 'pre-tool';
18
+ const extra = args.filter((a) => a !== event);
19
+ const isAgy = process.argv.some((a) => a === '--format=agy') || extra.includes('--format=agy');
20
+
21
+ function findProjectRoot() {
22
+ const candidates = [
23
+ process.env.PROJECT_ROOT,
24
+ process.env.WORKSPACE_DIR,
25
+ resolve(__dirname, '..', '..'),
26
+ process.cwd(),
27
+ ].filter(Boolean);
28
+
29
+ for (const dir of candidates) {
30
+ if (
31
+ existsSync(join(dir, 'package.json')) ||
32
+ existsSync(join(dir, '.git')) ||
33
+ existsSync(join(dir, '.agents')) ||
34
+ existsSync(join(dir, '.claude'))
35
+ ) {
36
+ return dir;
37
+ }
38
+ }
39
+ return resolve(__dirname, '..', '..');
40
+ }
41
+
42
+ const projectRoot = findProjectRoot();
43
+
44
+ function canRun(bin) {
45
+ try {
46
+ const result = spawnSync(bin, ['--version'], {
47
+ encoding: 'utf8',
48
+ windowsHide: true,
49
+ stdio: 'ignore',
50
+ timeout: SPAWN_TIMEOUT,
51
+ });
52
+ return result.status === 0;
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ function tryRun(bin, runArgs) {
59
+ try {
60
+ const result = spawnSync(bin, runArgs, {
61
+ cwd: projectRoot,
62
+ stdio: 'inherit',
63
+ windowsHide: true,
64
+ env: process.env,
65
+ timeout: SPAWN_TIMEOUT,
66
+ });
67
+ if (result.error) {
68
+ return false;
69
+ }
70
+ if (result.status === 0) {
71
+ process.exit(0);
72
+ }
73
+ if (!isAgy && result.status === 2) {
74
+ process.exit(2);
75
+ }
76
+ return false;
77
+ } catch {
78
+ return false;
79
+ }
80
+ }
81
+
82
+ function fallback() {
83
+ if (isAgy) {
84
+ if (event === 'post-tool' || event === 'session-start') {
85
+ process.stdout.write('{}\n');
86
+ } else {
87
+ process.stdout.write('{"decision":"allow"}\n');
88
+ }
89
+ }
90
+ process.exit(0);
91
+ }
92
+
93
+ try {
94
+ const srcMain = join(projectRoot, 'src', 'cli', 'main.ts');
95
+ if (existsSync(srcMain) && canRun('bun')) {
96
+ tryRun('bun', ['run', srcMain, 'hook', event, ...extra]);
97
+ }
98
+
99
+ const packaged = join(projectRoot, 'node_modules', 'cc-codeconductor', 'dist', 'index.js');
100
+ if (existsSync(packaged)) {
101
+ tryRun(process.execPath, [packaged, 'hook', event, ...extra]);
102
+ }
103
+
104
+ const localDist = join(projectRoot, 'dist', 'index.js');
105
+ if (existsSync(localDist)) {
106
+ tryRun(process.execPath, [localDist, 'hook', event, ...extra]);
107
+ }
108
+
109
+ tryRun('npx', ['--no-install', 'cc-codeconductor', 'hook', event, ...extra]);
110
+ } catch {
111
+ // Ignore errors in runner attempts
112
+ }
113
+
114
+ fallback();
115
+
@@ -0,0 +1,273 @@
1
+ #!/usr/bin/env python3
2
+ """Deterministic mutation-testing runner (stdlib only).
3
+
4
+ Applies single syntactic mutations over comparison operators in a Python
5
+ production file and re-runs the test suite per mutant. If a mutant survives
6
+ (tests still pass), the runner writes a handoff for the `tdd_craftsman` agent
7
+ (`specs/handover.md`, appended to `specs/implementation-summary.md`, optional
8
+ Engram/MCP memory hook) and exits with code 2 (HANDS_OFF). If every mutant is
9
+ killed, it exits 0 (PASS). The original source is always restored.
10
+
11
+ Usage:
12
+ python3 mutation_runner.py --target src/billing.py \
13
+ --test-command "pytest tests/test_billing.py" [--spec-folder specs]
14
+ """
15
+ import argparse
16
+ import ast
17
+ import difflib
18
+ import json
19
+ import os
20
+ import shutil
21
+ import subprocess
22
+ import sys
23
+ from dataclasses import asdict, dataclass
24
+ from pathlib import Path
25
+ from typing import Dict, List, Optional, Tuple
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class MutationRecord:
30
+ mutant_id: str
31
+ target_file: str
32
+ line_number: int
33
+ original_op: str
34
+ mutated_op: str
35
+ diff: str
36
+ survived: bool
37
+ details: str
38
+
39
+
40
+ class DeterministicOperatorMutator(ast.NodeTransformer):
41
+ """Applies one deterministic syntactic mutation over a comparison operator."""
42
+
43
+ OP_MAP = {
44
+ ast.Gt: ast.LtE, # > -> <=
45
+ ast.Lt: ast.GtE, # < -> >=
46
+ ast.GtE: ast.Lt, # >= -> <
47
+ ast.LtE: ast.Gt, # <= -> >
48
+ ast.Eq: ast.NotEq, # == -> !=
49
+ ast.NotEq: ast.Eq, # != -> ==
50
+ ast.Is: ast.IsNot, # is -> is not
51
+ ast.IsNot: ast.Is, # is not -> is
52
+ }
53
+
54
+ def __init__(self, target_index: int):
55
+ super().__init__()
56
+ self.target_index = target_index
57
+ self.current_index = 0
58
+ self.applied_mutation: Optional[Tuple[int, str, str]] = None
59
+
60
+ def visit_Compare(self, node: ast.Compare) -> ast.AST:
61
+ mutated_ops = []
62
+ modified = False
63
+
64
+ for op in node.ops:
65
+ op_type = type(op)
66
+ if op_type in self.OP_MAP:
67
+ if self.current_index == self.target_index:
68
+ new_op = self.OP_MAP[op_type]()
69
+ mutated_ops.append(new_op)
70
+ modified = True
71
+ self.applied_mutation = (
72
+ node.lineno,
73
+ op_type.__name__,
74
+ type(new_op).__name__,
75
+ )
76
+ else:
77
+ mutated_ops.append(op)
78
+ self.current_index += 1
79
+ else:
80
+ mutated_ops.append(op)
81
+
82
+ if modified:
83
+ node.ops = mutated_ops
84
+ return node
85
+ return self.generic_visit(node)
86
+
87
+
88
+ class MutationEngine:
89
+ def __init__(self, target_file: str, test_command: str, spec_folder: str = "specs"):
90
+ self.target_file = Path(target_file).resolve()
91
+ self.test_command = test_command
92
+ self.spec_folder = Path(spec_folder)
93
+ self.original_source = self.target_file.read_text(encoding="utf-8")
94
+ self.spec_folder.mkdir(parents=True, exist_ok=True)
95
+
96
+ def _count_mutation_points(self) -> int:
97
+ tree = ast.parse(self.original_source)
98
+ count = 0
99
+ for node in ast.walk(tree):
100
+ if isinstance(node, ast.Compare):
101
+ for op in node.ops:
102
+ if type(op) in DeterministicOperatorMutator.OP_MAP:
103
+ count += 1
104
+ return count
105
+
106
+ def _clear_bytecode_cache(self) -> None:
107
+ """Removes cached bytecode for the target so mutants are not shadowed
108
+ by a stale .pyc with an equal-mtimestamp source."""
109
+ cache_dir = self.target_file.parent / "__pycache__"
110
+ if cache_dir.is_dir():
111
+ for pyc in cache_dir.glob(f"{self.target_file.stem}.*.pyc"):
112
+ pyc.unlink(missing_ok=True)
113
+
114
+ def _run_test_suite(self) -> bool:
115
+ """Runs the test suite. Returns True if every test passes."""
116
+ self._clear_bytecode_cache()
117
+ env = {**os.environ, "PYTHONDONTWRITEBYTECODE": "1"}
118
+ result = subprocess.run(
119
+ self.test_command,
120
+ shell=True,
121
+ stdout=subprocess.PIPE,
122
+ stderr=subprocess.PIPE,
123
+ text=True,
124
+ env=env,
125
+ )
126
+ return result.returncode == 0
127
+
128
+ def _create_diff(self, mutated_source: str) -> str:
129
+ return "\n".join(
130
+ difflib.unified_diff(
131
+ self.original_source.splitlines(),
132
+ mutated_source.splitlines(),
133
+ fromfile=f"a/{self.target_file.name}",
134
+ tofile=f"b/{self.target_file.name}",
135
+ lineterm="",
136
+ )
137
+ )
138
+
139
+ def _persist_to_engram_or_markdown(self, record: MutationRecord) -> None:
140
+ """Documents the handoff in handover.md and implementation-summary.md."""
141
+ markdown_summary = self.spec_folder / "implementation-summary.md"
142
+ handover_file = self.spec_folder / "handover.md"
143
+
144
+ payload_md = f"""## Mutation Gate: Survivor Detected (TDD Gap)
145
+ - **Target File**: `{record.target_file}`
146
+ - **Line**: {record.line_number}
147
+ - **Mutant ID**: `{record.mutant_id}`
148
+ - **Operator Change**: `{record.original_op}` -> `{record.mutated_op}`
149
+ - **Status**: SURVIVED (Scorecard Real Coverage: 0)
150
+
151
+ ### Reproduction Diff
152
+ ```diff
153
+ {record.diff}
154
+ ```
155
+
156
+ ### Action Required by `tdd_craftsman`
157
+
158
+ 1. Do NOT touch production implementation.
159
+ 2. Write a minimal failing test (TDD Law 1 & 2) that asserts this branch condition.
160
+ 3. Verify the test turns red before re-verifying production code.
161
+ """
162
+ # Handover update for continuity
163
+ handover_file.write_text(payload_md, encoding="utf-8")
164
+
165
+ with markdown_summary.open("a", encoding="utf-8") as f:
166
+ f.write(f"\n\n{payload_md}")
167
+
168
+ # Optional Engram / MCP memory integration
169
+ self._notify_engram(record)
170
+
171
+ def _notify_engram(self, record: MutationRecord) -> None:
172
+ """Invokes the local Engram/Memory Engine hook or CLI if present."""
173
+ if shutil.which("engram"):
174
+ try:
175
+ subprocess.run(
176
+ [
177
+ "engram",
178
+ "memory:save",
179
+ "--tag",
180
+ "mutation_testing",
181
+ "--title",
182
+ f"Survivor {record.mutant_id}",
183
+ "--body",
184
+ json.dumps(asdict(record)),
185
+ ],
186
+ check=False,
187
+ stdout=subprocess.DEVNULL,
188
+ stderr=subprocess.DEVNULL,
189
+ )
190
+ except Exception:
191
+ pass
192
+
193
+ def run(self) -> Dict[str, object]:
194
+ # 1. Pre-flight check: tests must pass on the clean base code
195
+ if not self._run_test_suite():
196
+ raise RuntimeError("The test suite is already failing on unmutated base code.")
197
+
198
+ total_points = self._count_mutation_points()
199
+ survivors: List[MutationRecord] = []
200
+
201
+ try:
202
+ for idx in range(total_points):
203
+ mutator = DeterministicOperatorMutator(target_index=idx)
204
+ tree = ast.parse(self.original_source)
205
+ mutated_tree = mutator.visit(tree)
206
+ ast.fix_missing_locations(mutated_tree)
207
+
208
+ mutated_source = ast.unparse(mutated_tree)
209
+ diff = self._create_diff(mutated_source)
210
+
211
+ # Apply mutant to disk
212
+ self.target_file.write_text(mutated_source, encoding="utf-8")
213
+
214
+ # Run tests against the mutant
215
+ passed = self._run_test_suite()
216
+
217
+ if passed:
218
+ # The mutant survived: tests are blind to this change
219
+ lineno, orig, mut = mutator.applied_mutation or (0, "Unknown", "Unknown")
220
+ survivor = MutationRecord(
221
+ mutant_id=f"MUT_{idx:03d}_L{lineno}",
222
+ target_file=str(self.target_file),
223
+ line_number=lineno,
224
+ original_op=orig,
225
+ mutated_op=mut,
226
+ diff=diff,
227
+ survived=True,
228
+ details="Tests passed with inverted comparison logic. Missing explicit assert.",
229
+ )
230
+ survivors.append(survivor)
231
+
232
+ # Safe Fail-Fast protocol: immediate handoff to the craftsman
233
+ self._persist_to_engram_or_markdown(survivor)
234
+ return {
235
+ "status": "HANDS_OFF_TRIGGERED",
236
+ "target_agent": "tdd_craftsman",
237
+ "surviving_mutant": asdict(survivor),
238
+ }
239
+
240
+ finally:
241
+ # Unconditional deterministic rollback: restore original source
242
+ self.target_file.write_text(self.original_source, encoding="utf-8")
243
+
244
+ return {
245
+ "status": "PASS",
246
+ "total_mutants_killed": total_points,
247
+ "survivors_count": 0,
248
+ }
249
+
250
+
251
+ def main(argv: Optional[List[str]] = None) -> int:
252
+ parser = argparse.ArgumentParser(description="Deterministic stdlib mutation runner.")
253
+ parser.add_argument("--target", required=True, help="Python production file to mutate.")
254
+ parser.add_argument("--test-command", required=True, help="Shell command that runs the test suite.")
255
+ parser.add_argument("--spec-folder", default="specs", help="Folder for handoff artifacts.")
256
+ args = parser.parse_args(argv)
257
+
258
+ engine = MutationEngine(
259
+ target_file=args.target,
260
+ test_command=args.test_command,
261
+ spec_folder=args.spec_folder,
262
+ )
263
+ outcome = engine.run()
264
+ print(json.dumps(outcome, indent=2))
265
+
266
+ if outcome["status"] == "HANDS_OFF_TRIGGERED":
267
+ # Exit code 2 tells the orchestrator (craftsman_lead) to reroute to tdd_craftsman
268
+ return 2
269
+ return 0
270
+
271
+
272
+ if __name__ == "__main__":
273
+ sys.exit(main())
@@ -19,12 +19,14 @@ entries:
19
19
  - src: agy/hooks.json
20
20
  dest: .agents/hooks.json
21
21
  strategy: overwrite
22
+ globalStrategy: skip
22
23
  - src: agy/mcp_config.json
23
24
  dest: .agents/mcp_config.json
24
25
  strategy: overwrite
25
26
  - src: agy/scripts
26
27
  dest: .agents/scripts
27
28
  strategy: overwrite
29
+ globalStrategy: skip
28
30
  - src: opencode/skills
29
31
  dest: .agents/skills
30
32
  strategy: overwrite
@@ -9,6 +9,9 @@ entries:
9
9
  dest: .claude/settings.json
10
10
  strategy: overwrite
11
11
  globalStrategy: merge-json
12
+ - src: shared/invoke-hook.cjs
13
+ dest: .claude/hooks/invoke-hook.cjs
14
+ strategy: overwrite
12
15
  - src: claude/claude.json
13
16
  dest: .claude.json
14
17
  strategy: merge-json
@@ -8,3 +8,18 @@ entries:
8
8
  dest: .gemini/prompts/v1.0.0
9
9
  strategy: overwrite
10
10
  template: true
11
+ - src: gemini/commands
12
+ dest: .gemini/commands
13
+ strategy: overwrite
14
+ - src: claude/skills/openspec
15
+ dest: .gemini/skills/openspec
16
+ strategy: overwrite
17
+ - src: claude/skills/backlog
18
+ dest: .gemini/skills/backlog
19
+ strategy: overwrite
20
+ - src: claude/skills/evaluation
21
+ dest: .gemini/skills/evaluation
22
+ strategy: overwrite
23
+ - src: cursor/skills/testing-tdd
24
+ dest: .gemini/skills/testing-tdd
25
+ strategy: overwrite
@@ -8,15 +8,15 @@ agents:
8
8
  gemini: gemini-3.1-pro-preview
9
9
  cursor: claude-opus-5-thinking-high
10
10
  grok: cursor-grok-4.6-high-fast
11
- agy: gemini-3.1-pro-preview
11
+ agy: gemini-3.1-pro
12
12
  implementer:
13
13
  claude: claude-sonnet-5
14
- opencode: opencode-go/mimo-v2.5-pro
14
+ opencode: opencode-go/mimo-v2.5
15
15
  codex: gpt-5.6-terra
16
16
  gemini: gemini-3.7-flash
17
17
  cursor: composer-2.5-fast
18
18
  grok: cursor-grok-4.6-high-fast
19
- agy: gemini-3.7-flash
19
+ agy: claude-sonnet-4.6-thinking
20
20
  tester:
21
21
  claude: claude-sonnet-5
22
22
  opencode: opencode-go/minimax-m3
@@ -24,7 +24,7 @@ agents:
24
24
  gemini: gemini-3.7-flash
25
25
  cursor: composer-2.5-fast
26
26
  grok: cursor-grok-4.6-high-fast
27
- agy: gemini-3.7-flash
27
+ agy: claude-sonnet-4.6-thinking
28
28
  orchestrator:
29
29
  claude: claude-sonnet-5
30
30
  opencode: opencode-go/qwen3.7-plus
@@ -32,39 +32,39 @@ agents:
32
32
  gemini: gemini-3.7-flash
33
33
  cursor: composer-2.5
34
34
  grok: cursor-grok-4.6-high-fast
35
- agy: gemini-3.7-flash
35
+ agy: claude-sonnet-4.6-thinking
36
36
  reviewer:
37
37
  claude: claude-opus-5
38
- opencode: opencode-go/qwen3.7-plus
38
+ opencode: opencode-go/qwen3.8-max
39
39
  codex: gpt-5.6-sol
40
40
  gemini: gemini-3.1-pro-preview
41
41
  cursor: claude-sonnet-5-thinking-high
42
42
  grok: cursor-grok-4.6-high-fast
43
- agy: gemini-3.1-pro-preview
43
+ agy: gemini-3.1-pro
44
44
  docs:
45
45
  claude: claude-haiku-4-5-20251001
46
- opencode: opencode-go/qwen3.7-plus
46
+ opencode: opencode-go/hy3
47
47
  codex: gpt-5.6-luna
48
48
  gemini: gemini-3.7-flash
49
49
  cursor: claude-4.5-haiku-thinking
50
50
  grok: cursor-grok-4.6-high-fast
51
- agy: gemini-3.7-flash
51
+ agy: gemini-3.8-flash
52
52
  task-coach:
53
53
  claude: claude-haiku-4-5-20251001
54
- opencode: opencode-go/kimi-k2.7-code
54
+ opencode: opencode-go/gpt-5.6-luna
55
55
  codex: gpt-5.6-luna
56
56
  gemini: gemini-3.7-flash
57
57
  cursor: claude-4.5-haiku-thinking
58
58
  grok: cursor-grok-4.6-high-fast
59
- agy: gemini-3.7-flash
59
+ agy: gemini-3.8-flash
60
60
  repo-explorer:
61
61
  claude: claude-haiku-4-5-20251001
62
- opencode: opencode-go/deepseek-v4-flash
62
+ opencode: opencode-go/longcat-2.0
63
63
  codex: gpt-5.6-luna
64
64
  gemini: gemini-3.7-flash
65
65
  cursor: composer-2.5-fast
66
66
  grok: cursor-grok-4.6-high-fast
67
- agy: gemini-3.7-flash
67
+ agy: gemini-3.8-flash
68
68
  goal-planner:
69
69
  claude: claude-haiku-4-5-20251001
70
70
  opencode: opencode-go/deepseek-v4-flash
@@ -72,47 +72,47 @@ agents:
72
72
  gemini: gemini-3.7-flash
73
73
  cursor: claude-4.5-haiku-thinking
74
74
  grok: cursor-grok-4.6-high-fast
75
- agy: gemini-3.7-flash
75
+ agy: gemini-3.8-flash
76
76
  complexity-auditor:
77
77
  claude: claude-sonnet-5
78
- opencode: opencode-go/qwen3.7-plus
78
+ opencode: opencode-go/glm-5.3
79
79
  codex: gpt-5.6-terra
80
80
  gemini: gemini-3.7-flash
81
81
  cursor: claude-sonnet-5-thinking-high
82
82
  grok: cursor-grok-4.6-high-fast
83
- agy: gemini-3.7-flash
83
+ agy: claude-sonnet-4.6-thinking
84
84
  security-reviewer:
85
85
  claude: claude-opus-5
86
- opencode: opencode-go/deepseek-v4-pro
86
+ opencode: opencode-go/kimi-k3
87
87
  codex: gpt-5.6-sol
88
88
  gemini: gemini-3.1-pro-preview
89
89
  cursor: claude-opus-5-thinking-high
90
90
  grok: cursor-grok-4.6-high-fast
91
- agy: gemini-3.1-pro-preview
91
+ agy: gemini-3.1-pro
92
92
  contract-builder:
93
93
  claude: claude-opus-5
94
- opencode: opencode-go/qwen3.7-plus
94
+ opencode: opencode-go/qwen3.8-max
95
95
  codex: gpt-5.6-sol
96
96
  gemini: gemini-3.1-pro-preview
97
97
  cursor: claude-sonnet-5-thinking-high
98
98
  grok: cursor-grok-4.6-high-fast
99
- agy: gemini-3.1-pro-preview
99
+ agy: gemini-3.1-pro
100
100
  planner:
101
101
  claude: claude-haiku-4-5-20251001
102
- opencode: opencode-go/kimi-k2.7-code
102
+ opencode: opencode-go/gpt-5.6-luna
103
103
  codex: gpt-5.6-luna
104
104
  gemini: gemini-3.7-flash
105
105
  cursor: claude-4.5-haiku-thinking
106
106
  grok: cursor-grok-4.6-high-fast
107
- agy: gemini-3.7-flash
107
+ agy: gemini-3.8-flash
108
108
  devil:
109
109
  claude: claude-opus-5
110
- opencode: opencode-go/deepseek-v4-pro
110
+ opencode: opencode-go/glm-5.3
111
111
  codex: gpt-5.6-sol
112
112
  gemini: gemini-3.1-pro-preview
113
113
  cursor: claude-opus-5-thinking-high
114
114
  grok: cursor-grok-4.6-high-fast
115
- agy: gemini-3.1-pro-preview
115
+ agy: gemini-3.1-pro
116
116
  tools:
117
117
  Read:
118
118
  agy: view_file
@@ -12,7 +12,7 @@ agents:
12
12
  grok: cursor-grok-4.6-high-fast
13
13
  implementer:
14
14
  claude: claude-sonnet-5
15
- opencode: opencode-go/mimo-v2.5-pro
15
+ opencode: opencode-go/mimo-v2.5
16
16
  codex: gpt-5.6-terra
17
17
  gemini: gemini-3.7-flash
18
18
  cursor: composer-2.5-fast
@@ -33,28 +33,28 @@ agents:
33
33
  grok: cursor-grok-4.6-high-fast
34
34
  reviewer:
35
35
  claude: claude-opus-5
36
- opencode: opencode-go/qwen3.7-plus
36
+ opencode: opencode-go/qwen3.8-max
37
37
  codex: gpt-5.6-sol
38
38
  gemini: gemini-3.1-pro-preview
39
39
  cursor: claude-sonnet-5-thinking-high
40
40
  grok: cursor-grok-4.6-high-fast
41
41
  docs:
42
42
  claude: claude-haiku-4-5-20251001
43
- opencode: opencode-go/qwen3.7-plus
43
+ opencode: opencode-go/hy3
44
44
  codex: gpt-5.6-luna
45
45
  gemini: gemini-3.7-flash
46
46
  cursor: claude-4.5-haiku-thinking
47
47
  grok: cursor-grok-4.6-high-fast
48
48
  task-coach:
49
49
  claude: claude-haiku-4-5-20251001
50
- opencode: opencode-go/kimi-k2.7-code
50
+ opencode: opencode-go/gpt-5.6-luna
51
51
  codex: gpt-5.6-luna
52
52
  gemini: gemini-3.7-flash
53
53
  cursor: claude-4.5-haiku-thinking
54
54
  grok: cursor-grok-4.6-high-fast
55
55
  repo-explorer:
56
56
  claude: claude-haiku-4-5-20251001
57
- opencode: opencode-go/deepseek-v4-flash
57
+ opencode: opencode-go/longcat-2.0
58
58
  codex: gpt-5.6-luna
59
59
  gemini: gemini-3.7-flash
60
60
  cursor: composer-2.5-fast
@@ -68,35 +68,35 @@ agents:
68
68
  grok: cursor-grok-4.6-high-fast
69
69
  complexity-auditor:
70
70
  claude: claude-sonnet-5
71
- opencode: opencode-go/qwen3.7-plus
71
+ opencode: opencode-go/glm-5.3
72
72
  codex: gpt-5.6-terra
73
73
  gemini: gemini-3.7-flash
74
74
  cursor: claude-sonnet-5-thinking-high
75
75
  grok: cursor-grok-4.6-high-fast
76
76
  security-reviewer:
77
77
  claude: claude-opus-5
78
- opencode: opencode-go/deepseek-v4-pro
78
+ opencode: opencode-go/kimi-k3
79
79
  codex: gpt-5.6-sol
80
80
  gemini: gemini-3.1-pro-preview
81
81
  cursor: claude-opus-5-thinking-high
82
82
  grok: cursor-grok-4.6-high-fast
83
83
  contract-builder:
84
84
  claude: claude-opus-5
85
- opencode: opencode-go/qwen3.7-plus
85
+ opencode: opencode-go/qwen3.8-max
86
86
  codex: gpt-5.6-sol
87
87
  gemini: gemini-3.1-pro-preview
88
88
  cursor: claude-sonnet-5-thinking-high
89
89
  grok: cursor-grok-4.6-high-fast
90
90
  planner:
91
91
  claude: claude-haiku-4-5-20251001
92
- opencode: opencode-go/kimi-k2.7-code
92
+ opencode: opencode-go/gpt-5.6-luna
93
93
  codex: gpt-5.6-luna
94
94
  gemini: gemini-3.7-flash
95
95
  cursor: claude-4.5-haiku-thinking
96
96
  grok: cursor-grok-4.6-high-fast
97
97
  devil:
98
98
  claude: claude-opus-5
99
- opencode: opencode-go/deepseek-v4-pro
99
+ opencode: opencode-go/glm-5.3
100
100
  codex: gpt-5.6-sol
101
101
  gemini: gemini-3.1-pro-preview
102
102
  cursor: claude-opus-5-thinking-high