@tyroneross/build-loop 0.30.3 → 0.35.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.
- package/.agents/plugins/marketplace.json +2 -2
- package/.claude-plugin/marketplace.json +4 -4
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/AGENTS.md +11 -2
- package/README.md +8 -7
- package/agents/advisor.md +111 -0
- package/agents/alignment-checker.md +11 -0
- package/agents/assessment-orchestrator.md +1 -1
- package/agents/build-orchestrator.md +28 -33
- package/agents/fact-checker.md +1 -1
- package/agents/fix-critique.md +1 -1
- package/agents/independent-auditor.md +1 -1
- package/agents/overfitting-reviewer.md +1 -1
- package/agents/plan-critic.md +8 -6
- package/agents/promotion-reviewer.md +1 -1
- package/agents/retrospective-synthesizer.md +20 -3
- package/agents/scope-auditor.md +1 -1
- package/agents/security-reviewer.md +1 -1
- package/agents/self-improvement-architect.md +1 -1
- package/commands/{handoff.md → compose-handoff.md} +4 -4
- package/commands/{optimize.md → optimize-run.md} +1 -1
- package/commands/{agent-rally-point.md → rally-point.md} +3 -3
- package/commands/{research.md → research-run.md} +1 -1
- package/commands/setup-memory.md +32 -0
- package/commands/{plan-verify.md → verify-plan.md} +1 -1
- package/docs/agent-surface-policy.md +38 -20
- package/docs/memory-setup.md +19 -14
- package/hooks/_resolve_python.sh +28 -0
- package/hooks/closeout.sh +58 -0
- package/hooks/git/pre-push +69 -6
- package/hooks/hooks.json +34 -13
- package/hooks/post-push-closeout.sh +73 -0
- package/hooks/session-start-closeout.sh +69 -0
- package/hooks/session-start-memory.sh +27 -0
- package/hooks/session-start-plugin-heal.sh +33 -0
- package/hooks/test_closeout.sh +124 -0
- package/package.json +7 -4
- package/plugin-artifacts/codex/.codex-plugin/plugin.json +41 -0
- package/plugin-artifacts/codex/AGENTS.md +507 -0
- package/plugin-artifacts/codex/BUILD-ARTIFACT.md +5 -0
- package/plugin-artifacts/codex/LICENSE +202 -0
- package/plugin-artifacts/codex/README.md +404 -0
- package/plugin-artifacts/codex/docs/agent-surface-policy.md +63 -0
- package/plugin-artifacts/codex/references/advisor-dispatch-ladder.md +62 -0
- package/plugin-artifacts/codex/references/agent-role-taxonomy.md +135 -0
- package/plugin-artifacts/codex/references/autonomous-and-per-commit-modes.md +161 -0
- package/plugin-artifacts/codex/references/autonomy-config.md +231 -0
- package/plugin-artifacts/codex/references/capability-routing.md +182 -0
- package/plugin-artifacts/codex/references/codex-subagents.md +106 -0
- package/plugin-artifacts/codex/references/coordination-file-template.md +181 -0
- package/plugin-artifacts/codex/references/coordination-rules.md +283 -0
- package/plugin-artifacts/codex/references/dogfood-reload-checkpoint.md +112 -0
- package/plugin-artifacts/codex/references/halt-and-ask-protocol.md +102 -0
- package/plugin-artifacts/codex/references/implementer-envelope-schema.md +302 -0
- package/plugin-artifacts/codex/references/intent-capability-pack.md +257 -0
- package/plugin-artifacts/codex/references/intent-exploration-prompts.md +96 -0
- package/plugin-artifacts/codex/references/leadership.md +72 -0
- package/plugin-artifacts/codex/references/memory-systems.md +238 -0
- package/plugin-artifacts/codex/references/memory.md +299 -0
- package/plugin-artifacts/codex/references/model-tier-mapping.md +257 -0
- package/plugin-artifacts/codex/references/modular-systems-pack.md +96 -0
- package/plugin-artifacts/codex/references/phase-1-assess.md +231 -0
- package/plugin-artifacts/codex/references/phase-2-plan.md +78 -0
- package/plugin-artifacts/codex/references/phase-3-execute.md +49 -0
- package/plugin-artifacts/codex/references/phase-4-review.md +322 -0
- package/plugin-artifacts/codex/references/phase-5-iterate.md +71 -0
- package/plugin-artifacts/codex/references/phase-6-learn.md +56 -0
- package/plugin-artifacts/codex/references/recent-design-structures.md +274 -0
- package/plugin-artifacts/codex/references/research-trigger-policy.md +140 -0
- package/plugin-artifacts/codex/references/runtime-smoke-triggers.md +42 -0
- package/plugin-artifacts/codex/references/self-review.md +234 -0
- package/plugin-artifacts/codex/references/single-writer-commit-protocol.md +90 -0
- package/plugin-artifacts/codex/references/task-capture-policy.md +68 -0
- package/plugin-artifacts/codex/references/ui-io-contract.md +116 -0
- package/plugin-artifacts/codex/references/ui-spotcheck-protocol.md +65 -0
- package/plugin-artifacts/codex/skills/build-loop/SKILL.md +372 -0
- package/plugin-artifacts/codex/skills/build-loop/detect-plugins.mjs +82 -0
- package/plugin-artifacts/codex/skills/build-loop/eval-guide.md +65 -0
- package/plugin-artifacts/codex/skills/build-loop/fallbacks.md +549 -0
- package/plugin-artifacts/codex/skills/build-loop/phases/fact-check.md +42 -0
- package/plugin-artifacts/codex/skills/build-loop/phases/ui-validation.md +267 -0
- package/plugin-artifacts/codex/skills/build-loop/references/advisor-dispatch-ladder.md +62 -0
- package/plugin-artifacts/codex/skills/build-loop/references/apple-native-planning.md +439 -0
- package/plugin-artifacts/codex/skills/build-loop/references/autonomous-and-per-commit-modes.md +161 -0
- package/plugin-artifacts/codex/skills/build-loop/references/capability-routing.md +182 -0
- package/plugin-artifacts/codex/skills/build-loop/references/codex-subagents.md +106 -0
- package/plugin-artifacts/codex/skills/build-loop/references/coordination.md +161 -0
- package/plugin-artifacts/codex/skills/build-loop/references/correction-aware-capture.md +177 -0
- package/plugin-artifacts/codex/skills/build-loop/references/independent-auditor.md +72 -0
- package/plugin-artifacts/codex/skills/build-loop/references/intent-capability-pack.md +257 -0
- package/plugin-artifacts/codex/skills/build-loop/references/intent-exploration-prompts.md +96 -0
- package/plugin-artifacts/codex/skills/build-loop/references/leadership.md +72 -0
- package/plugin-artifacts/codex/skills/build-loop/references/memory.md +299 -0
- package/plugin-artifacts/codex/skills/build-loop/references/modular-systems-pack.md +96 -0
- package/plugin-artifacts/codex/skills/build-loop/references/output-style.md +129 -0
- package/plugin-artifacts/codex/skills/build-loop/references/pay-it-forward-arch.md +98 -0
- package/plugin-artifacts/codex/skills/build-loop/references/phase-1-assess.md +231 -0
- package/plugin-artifacts/codex/skills/build-loop/references/phase-2-plan.md +78 -0
- package/plugin-artifacts/codex/skills/build-loop/references/phase-3-execute.md +49 -0
- package/plugin-artifacts/codex/skills/build-loop/references/phase-4-review.md +322 -0
- package/plugin-artifacts/codex/skills/build-loop/references/phase-5-iterate.md +71 -0
- package/plugin-artifacts/codex/skills/build-loop/references/phase-6-learn.md +56 -0
- package/plugin-artifacts/codex/skills/build-loop/references/recent-design-structures.md +274 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/ASSESSMENT.md +85 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/STANDALONE_TEST_RUN.md +149 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/01-simple-bugfix.md +32 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/02-ui-build-with-iteration.md +48 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/03-multi-failure-escalation.md +60 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/04-ui-build-ibr-absent.md +51 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/05-refactor-navgator-absent.md +71 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/scenarios/06-recurring-bug-debugger-absent.md +52 -0
- package/plugin-artifacts/codex/skills/build-loop/references/refactor-history/trace-comparison.md +202 -0
- package/plugin-artifacts/codex/skills/build-loop/references/self-recursive-dev.md +77 -0
- package/plugin-artifacts/codex/skills/build-loop/references/self-review.md +234 -0
- package/plugin-artifacts/codex/skills/build-loop/references/ui-io-contract.md +116 -0
- package/plugin-artifacts/codex/skills/build-loop/scanners/audit-design-rules.mjs +476 -0
- package/plugin-artifacts/codex/skills/build-loop/scanners/require-visual-evidence.mjs +239 -0
- package/plugin-artifacts/codex/skills/build-loop/templates/backlog-item.md +35 -0
- package/plugin-artifacts/codex/skills/build-loop/templates/codex-worker-prompt.md +100 -0
- package/plugin-artifacts/codex/skills/build-loop/templates/ui-subagent-prompt.md +179 -0
- package/plugin-artifacts/codex/skills/build-loop/templates/ux-fix-plan.md +40 -0
- package/scripts/_paths.py +59 -13
- package/scripts/build_codex_plugin_artifact.py +314 -0
- package/scripts/check_cache_sync.py +1 -1
- package/scripts/install_memory.py +11 -3
- package/scripts/prune_plugin_cache.py +225 -11
- package/scripts/sync_navgator_lessons.py +25 -0
- package/scripts/sync_plugin_cache.py +66 -36
- package/skills/agent-rally-point/SKILL.md +1 -1
- package/skills/agent-rally-watcher/SKILL.md +1 -1
- package/skills/build-loop/SKILL.md +11 -155
- package/skills/build-loop/references/advisor-dispatch-ladder.md +62 -0
- package/skills/build-loop/references/autonomous-and-per-commit-modes.md +161 -0
- package/skills/build-loop/references/capability-routing.md +4 -3
- package/skills/build-loop/references/codex-subagents.md +8 -0
- package/skills/build-loop/references/coordination.md +1 -1
- package/skills/build-loop/references/intent-capability-pack.md +88 -1
- package/skills/build-loop/references/memory.md +17 -2
- package/skills/build-loop/references/phase-1-assess.md +13 -0
- package/skills/build-loop/references/phase-2-plan.md +2 -1
- package/skills/build-loop/references/phase-3-execute.md +4 -2
- package/skills/build-loop/references/phase-4-review.md +12 -0
- package/skills/build-loop/references/phase-6-learn.md +1 -1
- package/skills/build-loop/references/self-review.md +4 -2
- package/skills/build-loop/templates/codex-worker-prompt.md +45 -34
- package/skills/handoff/SKILL.md +3 -3
- package/skills/loop-builder/SKILL.md +98 -0
- package/skills/loop-builder/presets/active-project-evidence.yaml +97 -0
- package/skills/loop-builder/presets/generic-artifact-loop.yaml +95 -0
- package/skills/loop-builder/presets/presentation-audit.yaml +96 -0
- package/skills/loop-builder/presets/research-synthesis.yaml +96 -0
- package/skills/loop-builder/presets/source-ingestion-raw-data-audit.yaml +96 -0
- package/skills/loop-builder/references/spec-format.md +80 -0
- package/skills/loop-builder/scripts/loop_builder.py +346 -0
- package/skills/model-tiering/SKILL.md +65 -40
- package/skills/optimize/SKILL.md +2 -2
- package/skills/plan-verify/SKILL.md +1 -1
- package/skills/plugin-builder/references/distribution.md +8 -0
- package/skills/research/SKILL.md +33 -6
- package/skills/runtime-parity-verification/SKILL.md +51 -0
- package/skills/spec-writing/SKILL.md +19 -0
- package/templates/memory/README.md +65 -0
- package/templates/memory/charter.md.template +46 -0
- package/templates/memory/manifest.json +24 -4
- package/codex-skills/debug-loop/SKILL.md +0 -18
- package/codex-skills/handoff/SKILL.md +0 -22
- package/codex-skills/knowledge/SKILL.md +0 -21
- package/codex-skills/optimize/SKILL.md +0 -18
- package/codex-skills/research/SKILL.md +0 -18
- /package/commands/{knowledge-review.md → review-knowledge.md} +0 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
"""Generate focused-loop packs from preset specs.
|
|
5
|
+
|
|
6
|
+
Preset files use YAML-compatible JSON so this tool stays stdlib-only while the
|
|
7
|
+
generated loop spec remains readable YAML.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import copy
|
|
13
|
+
import json
|
|
14
|
+
import re
|
|
15
|
+
import shutil
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
HERE = Path(__file__).resolve().parent
|
|
21
|
+
SKILL_ROOT = HERE.parent
|
|
22
|
+
PRESETS_DIR = SKILL_ROOT / "presets"
|
|
23
|
+
|
|
24
|
+
IDENTIFIER_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LoopBuilderError(RuntimeError):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def slugify(value: str) -> str:
|
|
32
|
+
slug = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
|
|
33
|
+
slug = re.sub(r"-+", "-", slug)
|
|
34
|
+
if not slug:
|
|
35
|
+
raise LoopBuilderError("loop id cannot be empty")
|
|
36
|
+
return slug
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def require_identifier(value: str, *, field: str) -> str:
|
|
40
|
+
slug = slugify(value)
|
|
41
|
+
if not IDENTIFIER_RE.match(slug):
|
|
42
|
+
raise LoopBuilderError(f"{field} must be kebab-case: {value!r}")
|
|
43
|
+
return slug
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def preset_paths() -> list[Path]:
|
|
47
|
+
return sorted(PRESETS_DIR.glob("*.yaml"))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def available_presets() -> list[str]:
|
|
51
|
+
return [path.stem for path in preset_paths()]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def load_preset(name: str) -> dict[str, Any]:
|
|
55
|
+
preset_id = require_identifier(name, field="preset")
|
|
56
|
+
path = PRESETS_DIR / f"{preset_id}.yaml"
|
|
57
|
+
if not path.is_file():
|
|
58
|
+
choices = ", ".join(available_presets()) or "(none)"
|
|
59
|
+
raise LoopBuilderError(f"unknown preset {preset_id!r}; available: {choices}")
|
|
60
|
+
try:
|
|
61
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
62
|
+
except json.JSONDecodeError as exc:
|
|
63
|
+
raise LoopBuilderError(f"invalid preset JSON in {path}: {exc}") from exc
|
|
64
|
+
validate_preset(data, source=path)
|
|
65
|
+
return data
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def validate_preset(data: dict[str, Any], *, source: Path | None = None) -> None:
|
|
69
|
+
required = ("id", "title", "summary", "inputs", "outputs", "phases", "validators", "gates", "skill_chain", "learn")
|
|
70
|
+
missing = [key for key in required if key not in data]
|
|
71
|
+
if missing:
|
|
72
|
+
label = str(source) if source else data.get("id", "<preset>")
|
|
73
|
+
raise LoopBuilderError(f"{label} missing required fields: {', '.join(missing)}")
|
|
74
|
+
require_identifier(str(data["id"]), field="preset id")
|
|
75
|
+
if not isinstance(data["phases"], dict) or not data["phases"]:
|
|
76
|
+
raise LoopBuilderError(f"{data['id']} phases must be a non-empty object")
|
|
77
|
+
if not isinstance(data["validators"], list) or not data["validators"]:
|
|
78
|
+
raise LoopBuilderError(f"{data['id']} validators must be a non-empty list")
|
|
79
|
+
if not isinstance(data["skill_chain"], dict):
|
|
80
|
+
raise LoopBuilderError(f"{data['id']} skill_chain must be an object")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def scalar_to_yaml(value: Any) -> str:
|
|
84
|
+
if value is True:
|
|
85
|
+
return "true"
|
|
86
|
+
if value is False:
|
|
87
|
+
return "false"
|
|
88
|
+
if value is None:
|
|
89
|
+
return "null"
|
|
90
|
+
if isinstance(value, (int, float)):
|
|
91
|
+
return str(value)
|
|
92
|
+
return json.dumps(str(value), ensure_ascii=False)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def to_yaml(value: Any, indent: int = 0) -> str:
|
|
96
|
+
pad = " " * indent
|
|
97
|
+
if isinstance(value, dict):
|
|
98
|
+
if not value:
|
|
99
|
+
return pad + "{}"
|
|
100
|
+
lines: list[str] = []
|
|
101
|
+
for key, item in value.items():
|
|
102
|
+
if isinstance(item, (dict, list)):
|
|
103
|
+
if not item:
|
|
104
|
+
lines.append(f"{pad}{key}: {to_yaml(item, 0).strip()}")
|
|
105
|
+
else:
|
|
106
|
+
lines.append(f"{pad}{key}:")
|
|
107
|
+
lines.append(to_yaml(item, indent + 2))
|
|
108
|
+
else:
|
|
109
|
+
lines.append(f"{pad}{key}: {scalar_to_yaml(item)}")
|
|
110
|
+
return "\n".join(lines)
|
|
111
|
+
if isinstance(value, list):
|
|
112
|
+
if not value:
|
|
113
|
+
return pad + "[]"
|
|
114
|
+
lines = []
|
|
115
|
+
for item in value:
|
|
116
|
+
if isinstance(item, (dict, list)):
|
|
117
|
+
lines.append(f"{pad}-")
|
|
118
|
+
lines.append(to_yaml(item, indent + 2))
|
|
119
|
+
else:
|
|
120
|
+
lines.append(f"{pad}- {scalar_to_yaml(item)}")
|
|
121
|
+
return "\n".join(lines)
|
|
122
|
+
return pad + scalar_to_yaml(value)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def build_loop_spec(preset: dict[str, Any], *, loop_id: str, title: str | None, preset_name: str) -> dict[str, Any]:
|
|
126
|
+
spec = copy.deepcopy(preset)
|
|
127
|
+
spec["schema_version"] = 1
|
|
128
|
+
spec["id"] = loop_id
|
|
129
|
+
spec["source_preset"] = preset_name
|
|
130
|
+
if title:
|
|
131
|
+
spec["title"] = title
|
|
132
|
+
return spec
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def render_loop_yaml(spec: dict[str, Any]) -> str:
|
|
136
|
+
header = [
|
|
137
|
+
"# Generated focused-loop spec.",
|
|
138
|
+
"# Edit the artifact contract, validators, and skill_chain before using on high-stakes work.",
|
|
139
|
+
"",
|
|
140
|
+
]
|
|
141
|
+
return "\n".join(header) + to_yaml(spec) + "\n"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def render_rubric(spec: dict[str, Any]) -> str:
|
|
145
|
+
lines = [
|
|
146
|
+
f"# {spec['title']} Rubric",
|
|
147
|
+
"",
|
|
148
|
+
spec["summary"],
|
|
149
|
+
"",
|
|
150
|
+
"## Binary Validators",
|
|
151
|
+
"",
|
|
152
|
+
"| Validator | Pass Condition | Method |",
|
|
153
|
+
"|---|---|---|",
|
|
154
|
+
]
|
|
155
|
+
for validator in spec["validators"]:
|
|
156
|
+
lines.append(
|
|
157
|
+
f"| `{validator['id']}` | {validator['pass_condition']} | {validator.get('method', 'review')} |"
|
|
158
|
+
)
|
|
159
|
+
lines.extend(
|
|
160
|
+
[
|
|
161
|
+
"",
|
|
162
|
+
"## Confirmation Gates",
|
|
163
|
+
"",
|
|
164
|
+
]
|
|
165
|
+
)
|
|
166
|
+
for gate_name, gate_items in spec.get("gates", {}).items():
|
|
167
|
+
lines.append(f"### {gate_name}")
|
|
168
|
+
lines.append("")
|
|
169
|
+
for item in gate_items:
|
|
170
|
+
lines.append(f"- `{item}`")
|
|
171
|
+
lines.append("")
|
|
172
|
+
return "\n".join(lines).rstrip() + "\n"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def render_report_template(spec: dict[str, Any]) -> str:
|
|
176
|
+
validator_rows = "\n".join(f"| `{item['id']}` | pass/fail | evidence |" for item in spec["validators"])
|
|
177
|
+
outputs = "\n".join(f"- {item}" for item in spec["outputs"])
|
|
178
|
+
return f"""# {spec['title']} Report
|
|
179
|
+
|
|
180
|
+
## Bottom Line
|
|
181
|
+
|
|
182
|
+
[One sentence: what changed, what decision/artifact is ready, and what remains open.]
|
|
183
|
+
|
|
184
|
+
## Outputs
|
|
185
|
+
|
|
186
|
+
{outputs}
|
|
187
|
+
|
|
188
|
+
## Evidence
|
|
189
|
+
|
|
190
|
+
- [source path / transcript timestamp / row or slide reference]
|
|
191
|
+
|
|
192
|
+
## Validator Results
|
|
193
|
+
|
|
194
|
+
| Validator | Verdict | Evidence |
|
|
195
|
+
|---|---|---|
|
|
196
|
+
{validator_rows}
|
|
197
|
+
|
|
198
|
+
## Gates
|
|
199
|
+
|
|
200
|
+
- External send/publish: [clear/confirm]
|
|
201
|
+
- Sensitive data exposure: [clear/confirm]
|
|
202
|
+
- Irreversible source-of-truth change: [clear/confirm]
|
|
203
|
+
|
|
204
|
+
## Learn
|
|
205
|
+
|
|
206
|
+
- Reusable artifact:
|
|
207
|
+
- Source quirks:
|
|
208
|
+
- Rubric failures:
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def render_validator(spec: dict[str, Any]) -> str:
|
|
213
|
+
required_tokens = ["schema_version", "id", "phases", "validators", "gates", "skill_chain", "learn"]
|
|
214
|
+
token_literal = repr(required_tokens)
|
|
215
|
+
return f'''#!/usr/bin/env python3
|
|
216
|
+
# SPDX-FileCopyrightText: 2025-2026 Tyrone Ross, Jr <46267523+tyroneross@users.noreply.github.com>
|
|
217
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
218
|
+
"""Basic generated validator for the {spec["id"]} loop pack."""
|
|
219
|
+
from __future__ import annotations
|
|
220
|
+
|
|
221
|
+
import sys
|
|
222
|
+
from pathlib import Path
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
226
|
+
REQUIRED_FILES = [
|
|
227
|
+
ROOT / "loop.yaml",
|
|
228
|
+
ROOT / "rubric.md",
|
|
229
|
+
ROOT / "templates" / "report.md",
|
|
230
|
+
]
|
|
231
|
+
REQUIRED_TOKENS = {token_literal}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def main() -> int:
|
|
235
|
+
missing = [str(path.relative_to(ROOT)) for path in REQUIRED_FILES if not path.is_file()]
|
|
236
|
+
if missing:
|
|
237
|
+
print("missing required files: " + ", ".join(missing), file=sys.stderr)
|
|
238
|
+
return 1
|
|
239
|
+
text = (ROOT / "loop.yaml").read_text(encoding="utf-8")
|
|
240
|
+
absent = [token for token in REQUIRED_TOKENS if token + ":" not in text]
|
|
241
|
+
if absent:
|
|
242
|
+
print("loop.yaml missing required fields: " + ", ".join(absent), file=sys.stderr)
|
|
243
|
+
return 1
|
|
244
|
+
print("loop pack ok: " + str(ROOT))
|
|
245
|
+
return 0
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
if __name__ == "__main__":
|
|
249
|
+
raise SystemExit(main())
|
|
250
|
+
'''
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def write_file(path: Path, content: str, *, executable: bool = False) -> None:
|
|
254
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
255
|
+
path.write_text(content, encoding="utf-8")
|
|
256
|
+
if executable:
|
|
257
|
+
path.chmod(0o755)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def create_loop(
|
|
261
|
+
*,
|
|
262
|
+
loop_id_raw: str,
|
|
263
|
+
preset_name: str,
|
|
264
|
+
output: Path | None,
|
|
265
|
+
title: str | None,
|
|
266
|
+
force: bool,
|
|
267
|
+
) -> Path:
|
|
268
|
+
loop_id = require_identifier(loop_id_raw, field="loop id")
|
|
269
|
+
preset_id = require_identifier(preset_name, field="preset")
|
|
270
|
+
preset = load_preset(preset_id)
|
|
271
|
+
spec = build_loop_spec(preset, loop_id=loop_id, title=title, preset_name=preset_id)
|
|
272
|
+
target = output.expanduser().resolve() if output else (Path.cwd() / ".build-loop" / "loops" / loop_id).resolve()
|
|
273
|
+
if target.exists():
|
|
274
|
+
if not force:
|
|
275
|
+
raise LoopBuilderError(f"target already exists: {target}; pass --force to replace")
|
|
276
|
+
shutil.rmtree(target)
|
|
277
|
+
write_file(target / "loop.yaml", render_loop_yaml(spec))
|
|
278
|
+
write_file(target / "rubric.md", render_rubric(spec))
|
|
279
|
+
write_file(target / "templates" / "report.md", render_report_template(spec))
|
|
280
|
+
write_file(target / "validators" / "validate_loop.py", render_validator(spec), executable=True)
|
|
281
|
+
write_file(
|
|
282
|
+
target / "README.md",
|
|
283
|
+
f"# {spec['title']}\n\nGenerated from `{preset_id}`. Start with `loop.yaml`, then run `python3 validators/validate_loop.py`.\n",
|
|
284
|
+
)
|
|
285
|
+
return target
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def cmd_list(_args: argparse.Namespace) -> int:
|
|
289
|
+
for name in available_presets():
|
|
290
|
+
preset = load_preset(name)
|
|
291
|
+
print(f"{name}\t{preset['title']}")
|
|
292
|
+
return 0
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def cmd_inspect(args: argparse.Namespace) -> int:
|
|
296
|
+
preset = load_preset(args.preset)
|
|
297
|
+
print(render_loop_yaml(build_loop_spec(preset, loop_id=preset["id"], title=None, preset_name=preset["id"])))
|
|
298
|
+
return 0
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def cmd_create(args: argparse.Namespace) -> int:
|
|
302
|
+
target = create_loop(
|
|
303
|
+
loop_id_raw=args.loop_id,
|
|
304
|
+
preset_name=args.preset,
|
|
305
|
+
output=Path(args.output) if args.output else None,
|
|
306
|
+
title=args.title,
|
|
307
|
+
force=args.force,
|
|
308
|
+
)
|
|
309
|
+
print(f"created loop pack: {target}")
|
|
310
|
+
return 0
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
314
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
315
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
316
|
+
|
|
317
|
+
list_parser = sub.add_parser("list", help="List available loop presets.")
|
|
318
|
+
list_parser.set_defaults(func=cmd_list)
|
|
319
|
+
|
|
320
|
+
inspect_parser = sub.add_parser("inspect", help="Print a preset as generated loop YAML.")
|
|
321
|
+
inspect_parser.add_argument("preset")
|
|
322
|
+
inspect_parser.set_defaults(func=cmd_inspect)
|
|
323
|
+
|
|
324
|
+
create_parser = sub.add_parser("create", help="Create a focused-loop pack.")
|
|
325
|
+
create_parser.add_argument("loop_id")
|
|
326
|
+
create_parser.add_argument("--preset", required=True, help="Preset name from `list`.")
|
|
327
|
+
create_parser.add_argument("--output", help="Target directory. Defaults to .build-loop/loops/<loop-id>.")
|
|
328
|
+
create_parser.add_argument("--title", help="Override generated title.")
|
|
329
|
+
create_parser.add_argument("--force", action="store_true", help="Replace an existing target directory.")
|
|
330
|
+
create_parser.set_defaults(func=cmd_create)
|
|
331
|
+
|
|
332
|
+
return parser
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def main(argv: list[str] | None = None) -> int:
|
|
336
|
+
parser = build_parser()
|
|
337
|
+
args = parser.parse_args(argv)
|
|
338
|
+
try:
|
|
339
|
+
return int(args.func(args))
|
|
340
|
+
except LoopBuilderError as exc:
|
|
341
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
342
|
+
return 1
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
if __name__ == "__main__":
|
|
346
|
+
raise SystemExit(main())
|
|
@@ -17,18 +17,21 @@ skill answers "which tier should run the role?", not "who owns the work?".
|
|
|
17
17
|
|
|
18
18
|
| Tier | Anthropic default | Role | Equivalents (advisory — verify benchmarks before swapping) |
|
|
19
19
|
|---|---|---|---|
|
|
20
|
-
| **
|
|
21
|
-
| **
|
|
20
|
+
| **Frontier** | Fable 5 | **Phase 2 Plan synthesis (frame goal, draft spec/ADRs, F-criteria, MECE partition) via the Advisor dispatch ladder when stakes-gated** — `advisor` agent / peer host / already-Fable session; honestly-labeled inline-Opus fallback otherwise (`references/advisor-dispatch-ladder.md`). (Advisor v1 = Phase 2 only; Phase 1 Assess synthesis runs inline as today until v2.) AND verification judgment (plan-critic, scope-auditor, independent-auditor, fix-critique, fact-checker, security-reviewer, overfitting-reviewer, promotion-reviewer) | GPT-5.5 Thinking (or whichever tier scores above the prior Thinking-tier ceiling), future Claude tier above Opus; any model that benchmarks above the Thinking-tier contract on SWE-bench Verified AND ARC-AGI / GPQA Diamond |
|
|
21
|
+
| **Thinking** | Opus 4.8 | Coordination — build-orchestrator, assessment-orchestrator — and the escalation target for execution (ambiguous spec, 2 consecutive failures, cross-file surprise) and audit/learnings synthesis when Frontier is unavailable | GPT-5 Thinking, Gemini 2.5 Pro; any model >= Opus 4.6 on SWE-bench Verified + Frontier-class on ARC-AGI / MMLU-Pro |
|
|
22
|
+
| **Code** | Sonnet 4.6 | Application — apply rule to bounded input, scoped implementation, mechanical refactor, bounded domain assessment | Sonnet 4.7+, GPT-5 Codex, qwen2.5-coder-32B (local); any model with SWE-bench Verified within ~5pt of Sonnet 4.6 (currently ~79.6%) |
|
|
22
23
|
| **Pattern** | Haiku 4.5 | Recognition — regex/syntactic match, classification into known buckets, log scan, deterministic checklist | Haiku 4.6, GPT-5 Mini, llama3.2-3b (local); any small/fast model that handles structured pattern matching |
|
|
23
24
|
|
|
24
|
-
**Rule of substitution:** tier A's swap target must score within tolerance of the default on the benchmark relevant to its role. For Code tier that's SWE-bench Verified ≥75% AND tool-use accuracy ≥85%; for Thinking tier that's SWE-bench ≥78% AND ARC-AGI / GPQA Diamond competitive; for Pattern tier no benchmark — just "fast and cheap, doesn't hallucinate on bounded structured tasks."
|
|
25
|
+
**Rule of substitution:** tier A's swap target must score within tolerance of the default on the benchmark relevant to its role. For Code tier that's SWE-bench Verified ≥75% AND tool-use accuracy ≥85%; for Thinking tier that's SWE-bench ≥78% AND ARC-AGI / GPQA Diamond competitive; for Frontier tier that's clearing the Thinking-tier contract AND scoring above the prior-generation Thinking-tier ceiling on at least one of SWE-bench Verified / ARC-AGI / GPQA Diamond; for Pattern tier no benchmark — just "fast and cheap, doesn't hallucinate on bounded structured tasks."
|
|
26
|
+
|
|
27
|
+
**Why Frontier sits above Thinking for plan + verification (and not for execution):** wrong plans and wrong verdicts compound — a bad plan dispatches N implementers into the wrong work, and a bad verdict ships a regression. The user's standing priority is Accuracy > Speed > Cost (`feedback_accuracy_speed_cost_priority.md`), so the planning and verification surfaces — where one miscall poisons everything downstream — pay the Frontier premium. Execution and coordination stay on Sonnet/Opus because they're either bounded application (Sonnet implementer applies a settled plan) or routing (Opus orchestrator chooses which subagent runs next, with deterministic gates as the safety net).
|
|
25
28
|
|
|
26
29
|
## Provider-swap recipe
|
|
27
30
|
|
|
28
|
-
Build-loop's agent frontmatter uses Anthropic model aliases (`opus`, `sonnet`, `haiku`) because Claude Code is the primary host. To run on a different provider:
|
|
31
|
+
Build-loop's agent frontmatter uses Anthropic model aliases (`fable`, `opus`, `sonnet`, `haiku`) because Claude Code is the primary host. To run on a different provider:
|
|
29
32
|
|
|
30
|
-
1. **One-time edit per agent:** open each `agents/*.md` and change the `model:` field to your provider's equivalent. The tier (Thinking/Code/Pattern) determines the substitution target.
|
|
31
|
-
2. **Runtime override:** `.build-loop/config.json.modelOverrides` accepts `{ thinking: "<id>", code: "<id>", pattern: "<id>" }`. The orchestrator resolves this through `scripts/model_overrides.py` before dispatching subagents (see `references/model-tier-mapping.md` for full schema).
|
|
33
|
+
1. **One-time edit per agent:** open each `agents/*.md` and change the `model:` field to your provider's equivalent. The tier (Frontier/Thinking/Code/Pattern) determines the substitution target.
|
|
34
|
+
2. **Runtime override:** `.build-loop/config.json.modelOverrides` accepts `{ frontier: "<id>", thinking: "<id>", code: "<id>", pattern: "<id>" }`. The orchestrator resolves this through `scripts/model_overrides.py` before dispatching subagents (see `references/model-tier-mapping.md` for full schema). Configs without `frontier` resolve frontier → `fable` by default.
|
|
32
35
|
3. **Per-dispatch override:** any orchestrator dispatch may pass `model: <id>` in the subagent prompt to force that call.
|
|
33
36
|
|
|
34
37
|
The role-and-task table below uses tier names. The Anthropic-default mapping in the right column is illustrative; substitute your equivalents at swap time.
|
|
@@ -41,7 +44,7 @@ The role-and-task table below uses tier names. The Anthropic-default mapping in
|
|
|
41
44
|
- Deciding whether to escalate mid-flow after failures
|
|
42
45
|
- Evaluating whether to swap providers (use the Tier abstraction table above as the contract)
|
|
43
46
|
|
|
44
|
-
## Evidence base (2026 Q1)
|
|
47
|
+
## Evidence base (2026 Q1–Q2)
|
|
45
48
|
|
|
46
49
|
| Claim | Source | Certainty |
|
|
47
50
|
|-------|--------|-----------|
|
|
@@ -49,43 +52,57 @@ The role-and-task table below uses tier names. The Anthropic-default mapping in
|
|
|
49
52
|
| Opus 4.6: 80.8% SWE-bench Verified (1.2pt gap — smallest in Claude history) | Same | ⚠️ T2, single-source |
|
|
50
53
|
| Sonnet 4.6 uses 70% fewer tokens than 4.5 on complex file ops with +38% accuracy | Anthropic Sonnet 4.6 announcement | ⚠️ T2, single-source |
|
|
51
54
|
| Pricing: Sonnet $3/$15 per MTok input/output | Anthropic pricing page | ⚠️ verify before billing |
|
|
52
|
-
| Pricing: Opus $
|
|
55
|
+
| Pricing: Opus 4.8 $5/$25 per MTok input/output | Anthropic pricing page | ⚠️ verify before billing |
|
|
56
|
+
| Pricing: Fable 5 $10/$50 per MTok input/output (1M context, capability tier above Opus 4.8) | claude-api skill cache 2026-05-26 (T1 — Anthropic) | ✅ T1 source, advisory until re-confirmed at next billing audit |
|
|
53
57
|
|
|
54
58
|
## MECE primitive: cognitive type of the task
|
|
55
59
|
|
|
56
|
-
Before consulting the role table, classify the task by reasoning shape. The MECE cut is the kind of thinking the task requires; lifecycle stage (plan/execute/review) is a second-order cut that often mixes types.
|
|
60
|
+
Before consulting the role table, classify the task by reasoning shape. The MECE cut is the kind of thinking the task requires; lifecycle stage (plan/execute/review) is a second-order cut that often mixes types. Within Synthesis, a second-order cut decides whether the task is a planning/verification decision (Frontier) or coordination/escalation/learnings (Thinking).
|
|
57
61
|
|
|
58
62
|
| Reasoning shape | Model | What it means | Example tasks |
|
|
59
63
|
|---|---|---|---|
|
|
60
|
-
| **
|
|
61
|
-
| **
|
|
62
|
-
| **
|
|
64
|
+
| **Planning + Verification synthesis** — frame the goal, draft the spec/ADRs, define F-criteria, MECE-partition the work, then later judge whether a plan, a commit, a fix, a claim, or a security/scope boundary actually holds | **Fable (Frontier)** | The "what to do" and "did it actually work" calls. Wrong calls poison every downstream dispatch. | Phase 2 Plan drafting (reaches Fable via the stakes-gated Advisor ladder; Phase 1 Assess synthesis stays inline until v2), plan-critic, scope-auditor, independent-auditor, fix-critique, fact-checker, security-reviewer, overfitting-reviewer, promotion-reviewer |
|
|
65
|
+
| **Coordination + escalation synthesis** — route work between subagents, ladder severity, run causal-tree on stuck iterations, write audit/learnings | **Opus (Thinking)** | The "who runs next" + "why did the rule run out" calls. Deterministic gates backstop the routing. | build-orchestrator, assessment-orchestrator, severity ranking after critic findings, causal-tree after 2 consecutive failures, Phase 6 Learn audit synthesis (when no Frontier escalation needed) |
|
|
66
|
+
| **Application** — apply a known rule, spec, or pattern to bounded input; produce an artifact that matches a contract | **Sonnet (Code)** | The "how" call when "what" is decided. Single-correct-answer derivable from a rule. | Implement a commit's owned files per spec, write tests for given F-criteria, mechanical simplify, bounded domain assessment (api/db/frontend/perf), design-contract reconciliation, ui-validator, retrospective-synthesizer, self-improvement-architect drafting |
|
|
67
|
+
| **Recognition** — pure regex/syntactic match; classify into known buckets; no judgment | **Haiku (Pattern)** | No gradient — matches or doesn't. | Mock-data scan, log pattern detection, file inventory, cross-run pattern detection, deterministic checklist verification |
|
|
63
68
|
|
|
64
|
-
**Decision tree:** "Does this task have a single-correct answer derivable from a rule applied to bounded input?" → Yes = Application/Sonnet. Else "Is the answer pure pattern-match?" → Yes = Recognition/Haiku. Else =
|
|
69
|
+
**Decision tree:** "Does this task have a single-correct answer derivable from a rule applied to bounded input?" → Yes = Application/Sonnet. Else "Is the answer pure pattern-match?" → Yes = Recognition/Haiku. Else, Synthesis. Then ask: "Is this a planning decision (what to build) or a verification verdict (did it hold)?" → Yes = Frontier/Fable. Else (routing, escalation, audit-synthesis when no verdict is being rendered) = Thinking/Opus.
|
|
65
70
|
|
|
66
71
|
## Default assignments
|
|
67
72
|
|
|
68
73
|
| Task | Reasoning shape | Model | effort | Why |
|
|
69
74
|
|------|------|-------|--------|-----|
|
|
70
|
-
| Frame & plan: goal, ADRs, scope, F-criteria, MECE partition |
|
|
75
|
+
| Frame & plan: goal, ADRs, scope, F-criteria, MECE partition | Planning synthesis | Fable | medium | A wrong plan dispatches N implementers into the wrong work; user's standing priority Accuracy > Speed > Cost |
|
|
71
76
|
| Plan-verify deterministic checklist | Recognition | (script) | — | No model; runs `plan_verify.py` |
|
|
72
|
-
| Plan-critic adversarial review against rubric+checklist |
|
|
73
|
-
|
|
|
74
|
-
| Code execution — bounded chunk, spec clear | Application | Sonnet | medium | Default.
|
|
75
|
-
| Code execution — ambiguous spec |
|
|
76
|
-
|
|
|
77
|
-
|
|
|
77
|
+
| Plan-critic adversarial review against rubric+checklist | Verification synthesis | Fable | high | Verification verdict — separation drives quality; verdict gates Phase 3 dispatch |
|
|
78
|
+
| Scope auditor (Plan→Execute boundary): trace callers of every modified-API symbol; annotate `caller_audit:` per commit | Verification synthesis | Fable | medium | Cross-file call-path tracing AND a gating verdict on whether a commit is `internal_only`; verification compound risk |
|
|
79
|
+
| Code execution — bounded chunk, spec clear | Application | Sonnet | medium | Default workhorse. Spec is settled; apply the rule |
|
|
80
|
+
| Code execution — ambiguous spec or cross-file surprise mid-execution | Coordination synthesis | Opus | medium | Escalation target; interpretation cost cheaper than rework |
|
|
81
|
+
| Independent-auditor adversarial pass (read-only diff vs rubric at chunk + build scope) | Verification synthesis | Fable | high | Verdict gates the build's outcome line; a missed regression in production-impacting work is the most expensive miss in the loop |
|
|
82
|
+
| Severity ranking + recommendation order (given findings) | Coordination synthesis | Opus | medium | Cross-finding routing; no per-finding verdict being rendered, the verdicts are upstream |
|
|
78
83
|
| Mock data scanning | Recognition | Haiku | low | Regex only |
|
|
79
|
-
| Fact-checking — trace metric → source, judge accuracy |
|
|
80
|
-
|
|
|
84
|
+
| Fact-checking — trace metric → source, judge accuracy | Verification synthesis | Fable | medium | Final read on "is this number real" before report ships; user-trust verdict |
|
|
85
|
+
| Fix-critique — pressure-test a proposed fix before "resolved" | Verification synthesis | Fable | medium | Verdict on whether the fix addresses root cause vs symptom; wrong verdict reopens the bug downstream |
|
|
86
|
+
| Security-reviewer — adversarial OWASP/ATLAS pass | Verification synthesis | Fable | high | Verdict gates riskSurfaceChange dispatch; missed exposure is the most expensive verification miss |
|
|
87
|
+
| Overfitting-reviewer — Goodhart / test-gaming verdict on optimize runs | Verification synthesis | Fable | medium | Verdict on whether optimization is genuine; cheap to wrong-call into a regression |
|
|
88
|
+
| Promotion-reviewer — Phase 6 Learn experimental promotion verdict | Verification synthesis | Fable | medium | Gates the move from `experimental/` to `active/`; durable surface |
|
|
81
89
|
| Simplify — apply known simplifications | Application | Sonnet | medium | Inline single-use helper, delete dead branch — bounded |
|
|
82
90
|
| Debugging — symptom-to-known-pattern match | Application | Sonnet | high | Memory-first gate's "Application until the rule runs out" |
|
|
83
|
-
| Debugging — causal-tree after 2 consecutive failures |
|
|
84
|
-
| Novel architecture decision |
|
|
85
|
-
| Writing user-facing prose (copy, microcopy, errors) |
|
|
86
|
-
| Audit / learnings / Phase 6
|
|
91
|
+
| Debugging — causal-tree after 2 consecutive failures | Coordination synthesis | Opus | high | Synthesis takes over routing when rule-match exhausts |
|
|
92
|
+
| Novel architecture decision | Planning synthesis | Fable | medium | Cross-file impact; wrong call compounds |
|
|
93
|
+
| Writing user-facing prose (copy, microcopy, errors) | Coordination synthesis | Opus | medium | Tone, restraint, and nuance matter; no verification verdict being rendered |
|
|
94
|
+
| Audit / learnings / Phase 6 audit synthesis | Coordination synthesis | Opus | medium | Cross-run routing; promotion-reviewer carries the gating verdict separately |
|
|
87
95
|
| Recurring-pattern detection across runs[] | Recognition | Haiku | low | Pattern-match across structured logs |
|
|
88
96
|
|
|
97
|
+
### Deliberate exceptions (Sonnet retained for cost where the surface is high-frequency advisory)
|
|
98
|
+
|
|
99
|
+
Two verification-shaped agents stay on Sonnet rather than escalating to Fable. The tension with round-2 evidence ("rubric-application = Sonnet is robust") is real; the user chose Fable for the rest of the verification surface anyway because the compound risk of a wrong verification verdict outweighs the per-call premium. Pins are defaults, not locks — these can be overridden per dispatch or re-tiered after telemetry.
|
|
100
|
+
|
|
101
|
+
| Agent | Pin | Why retained on Sonnet |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `alignment-checker` | Sonnet | Called once per queue item during autonomous iterate (up to 25× per run). Advisory only — flags drift, doesn't gate. Cost dominates value at this fan-out frequency. |
|
|
104
|
+
| `synthesis-critic` | Sonnet | Per-UI-commit WARN-only check. Advisory only — never gates. Frequency × non-gating shape means a cheaper tier is the right tradeoff. |
|
|
105
|
+
|
|
89
106
|
## Round 2 evidence (2026-05-07, example-app news-podcast iteration 2)
|
|
90
107
|
|
|
91
108
|
n=2 dispatch-pattern A/B comparison on a 6-commit feature reversed the round-1 belief that Skill-path (Sonnet fan-out) is materially cheaper across the board:
|
|
@@ -105,16 +122,20 @@ Findings that updated the model tiering:
|
|
|
105
122
|
3. **Inline-Opus is faster wall-clock** when there's no real parallelism to exploit. Fan-out parallelism is only a win when ≥3 chunks are truly independent.
|
|
106
123
|
4. **Plan-critic on Sonnet caught 17 substantive findings** on a written spec — confirms "rubric-application = Sonnet" is robust.
|
|
107
124
|
|
|
108
|
-
These findings
|
|
125
|
+
These findings informed the earlier rubric-application=Sonnet split for code review. The current org overrides that for the verification surface specifically — the user chose Fable for verification because a missed verdict at this stage compounds, even though round-2 showed Sonnet rubric-application was substantively robust on a 17-finding plan-critic pass. The exceptions table above (alignment-checker, synthesis-critic) preserves the Sonnet split where the surface is high-frequency advisory and non-gating.
|
|
109
126
|
|
|
110
|
-
## Escalation triggers (
|
|
127
|
+
## Escalation triggers (Sonnet execution → Opus, NOT to Fable)
|
|
111
128
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
129
|
+
Execution escalates to **Opus**, not Fable. Fable is reserved for planning and verification; execution under genuine ambiguity is a coordination call (interpret the spec, route to a new chunk, decide whether to re-plan) that the orchestrator owns.
|
|
130
|
+
|
|
131
|
+
- 2 consecutive failures on the same chunk after a retry at effort=high → respawn implementer at Opus
|
|
132
|
+
- Spec is ambiguous and interpretation will materially change implementation → Opus
|
|
133
|
+
- A cross-file architectural decision surfaces mid-execution that wasn't in the plan → Opus, then route back to Plan if the decision changes the MECE partition
|
|
134
|
+
- Critic flags a "strong-checkpoint" finding that requires judgment, not just a fix → Opus
|
|
135
|
+
- Novel error pattern not found in `.build-loop/issues/` or debugging memory → Opus
|
|
136
|
+
- Task produces user-visible prose where tone and restraint are load-bearing → Opus
|
|
137
|
+
|
|
138
|
+
If the ambiguity surfaces a **planning** problem (the original plan no longer fits) rather than an execution problem, route back to Phase 2 Plan — Fable re-plans, then execution resumes on Sonnet/Opus.
|
|
118
139
|
|
|
119
140
|
## Techniques that work
|
|
120
141
|
|
|
@@ -149,19 +170,21 @@ These findings inform the role assignments, especially the rubric-application=So
|
|
|
149
170
|
|
|
150
171
|
## How the build-loop uses this
|
|
151
172
|
|
|
152
|
-
|
|
173
|
+
**Fable plans (when stakes-gated) and verifies. Opus coordinates. Sonnet executes. Haiku recognizes.**
|
|
153
174
|
|
|
154
|
-
|
|
175
|
+
Phase 2 Plan synthesis reaches **Fable** through the **Advisor dispatch ladder** when stakes-gating trips (`synthesisDensity > 5`, `riskSurfaceChange`, `stakes >= medium`, or `dispatch_tier: frontier`): the orchestrator dispatches the `advisor` agent (Rung 1), routes to a peer host (Rung 2), or — if its own session is already Fable — synthesizes inline at Frontier (Rung 0). When no trigger fires or no dispatch path is reachable, the orchestrator synthesizes the plan **inline on its own model (Opus)** and labels it honestly (Rung 3 = today's behavior; the floor equals current state). So "Fable plans" is the *guarantee on high-stakes plans*, with an honestly-labeled inline fallback otherwise — not unconditional. Full protocol: `references/advisor-dispatch-ladder.md`. The Advisor frames the goal, drafts the spec/ADRs, sets F-criteria, and MECE-partitions the work. The orchestrator (**Opus**, `build-orchestrator`, `assessment-orchestrator`) coordinates: it routes dispatches, runs deterministic gates, manages parallel fan-out, walks the Advisor ladder, and handles the escalation ladder. Phase 3 implementer subagents run on **Sonnet** at effort=medium (default workhorse) → external verification gate (tests/lint/types) → adversarial **Fable** verification surface (`plan-critic`, `scope-auditor`, `independent-auditor`, `fix-critique`, `fact-checker`, `security-reviewer`, `overfitting-reviewer`, `promotion-reviewer`). If a strong-checkpoint finding or 2 consecutive chunk failures surface, execution escalates to **Opus** for judgment; if the failure traces back to a planning miss, route back to Fable to re-plan. See `agents/build-orchestrator.md §Escalation Triggers`. The **tier mapping** is the policy; the cost numbers above are advisory context, not the basis for overrides.
|
|
176
|
+
|
|
177
|
+
Haiku is only used for Phase 7B mock scanning and recurring-pattern detection across `runs[]`. Never for reasoning tasks.
|
|
155
178
|
|
|
156
179
|
## Pin vs inherit in agent frontmatter
|
|
157
180
|
|
|
158
181
|
Not every agent should hard-pin its model. Use this rule:
|
|
159
182
|
|
|
160
|
-
- **Pin** (`model: opus | sonnet | haiku`) when the task has a clear right tier and cost/quality drift from user's session choice would be a bug. Examples: `independent-auditor`
|
|
161
|
-
- **Inherit** (`model: inherit`) when user intent should flow through. The user's main-session choice is itself a cost/speed preference; respect it. Pair with a "recommended: X" note in this skill rather than forcing via frontmatter. Example: `
|
|
162
|
-
- **Override mechanism**: users can override any pin by passing `model:` when spawning the agent or by editing the frontmatter. Pins are defaults, not locks.
|
|
183
|
+
- **Pin** (`model: fable | opus | sonnet | haiku`) when the task has a clear right tier and cost/quality drift from user's session choice would be a bug. Examples: `plan-critic` / `independent-auditor` / `scope-auditor` / `fact-checker` / `fix-critique` / `security-reviewer` / `overfitting-reviewer` / `promotion-reviewer` (Fable — verification verdicts gate downstream work), `mock-scanner` (Haiku, pattern matching only), `build-orchestrator` and `assessment-orchestrator` (Opus, coordination at plan/review boundaries), `implementer` (Sonnet, default execution workhorse).
|
|
184
|
+
- **Inherit** (`model: inherit`) when user intent should flow through. The user's main-session choice is itself a cost/speed preference; respect it. Pair with a "recommended: X" note in this skill rather than forcing via frontmatter. Example: `root-cause-investigator` — recommended Opus on causal-tree work, but inherit honors whatever tier the user picked upstream.
|
|
185
|
+
- **Override mechanism**: users can override any pin by passing `model:` when spawning the agent or by editing the frontmatter. Pins are defaults, not locks. The deliberate exceptions documented above (`alignment-checker`, `synthesis-critic` on Sonnet despite being verification-shaped) are exactly this kind of cost-vs-judgment pin and can be lifted if telemetry says so.
|
|
163
186
|
|
|
164
|
-
Forward-compat note: pinned family aliases (`sonnet`, `opus`) auto-track latest versions (e.g., 4.6 → 4.7). `inherit` additionally picks up brand-new tiers (e.g., a future Flash-class model) without frontmatter edits.
|
|
187
|
+
Forward-compat note: pinned family aliases (`fable`, `sonnet`, `opus`) auto-track latest versions in their tier (e.g., Sonnet 4.6 → 4.7, Opus 4.7 → 4.8, Fable 5 → 6). `inherit` additionally picks up brand-new tiers (e.g., a future Flash-class model) without frontmatter edits.
|
|
165
188
|
|
|
166
189
|
## Limitations of this guidance
|
|
167
190
|
|
|
@@ -213,4 +236,6 @@ python3 ${CLAUDE_PLUGIN_ROOT}/scripts/model_overrides.py \
|
|
|
213
236
|
--json
|
|
214
237
|
```
|
|
215
238
|
|
|
239
|
+
Accepted tiers: `frontier` (default `fable`), `thinking` (default `opus`), `code` (default `sonnet`), `pattern` (default `haiku`). Configs without `frontier` resolve frontier → `fable` so older repos keep working without edits.
|
|
240
|
+
|
|
216
241
|
Full contract and routing matrix: `~/dev/research/topics/llm/llm.build-loop-router-integration-2026-04.md`
|
package/skills/optimize/SKILL.md
CHANGED
|
@@ -40,7 +40,7 @@ Highest-leverage phase. Wrong metric = Goodhart's Law. Wrong factors = wasted ru
|
|
|
40
40
|
|---|---|---|
|
|
41
41
|
| **A. Power-user explicit** | User supplied factors via CLI flag, `.build-loop/optimize/factors.json`, or inline ("optimize batch_size, retries, workers for throughput") | Skip suggestion; use the user's factors directly |
|
|
42
42
|
| **B. Vague optimization** *(default)* | "run optimization", "make my app faster", "improve performance", "speed up", "reduce <metric>" without naming factors | Run factor-identification scan; propose candidates; **AskUserQuestion to confirm before running** |
|
|
43
|
-
| **C. Single-variable explicit** | "simplify this file", "reduce build time", scoped `/build-loop:optimize <known-target>` | Skip DOE; run autoresearch (existing behavior, Phase 2 LOOP unchanged) |
|
|
43
|
+
| **C. Single-variable explicit** | "simplify this file", "reduce build time", scoped `/build-loop:optimize-run <known-target>` | Skip DOE; run autoresearch (existing behavior, Phase 2 LOOP unchanged) |
|
|
44
44
|
|
|
45
45
|
### Step 1.2 — Branch A or B: factor identification
|
|
46
46
|
|
|
@@ -186,7 +186,7 @@ Dispatch the `optimize-runner` agent. It executes:
|
|
|
186
186
|
|
|
187
187
|
Phase 4.7 (AUTO-OPTIMIZE): after Phase 4 Execute completes and commits, check for optimization targets. Run sequentially (not parallel with Phase 4).
|
|
188
188
|
|
|
189
|
-
Standalone: `/build-loop:optimize [target]`
|
|
189
|
+
Standalone: `/build-loop:optimize-run [target]`
|
|
190
190
|
|
|
191
191
|
## State Files
|
|
192
192
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan-verify
|
|
3
|
-
description: Use when build-loop Phase 2 wraps plan drafting, the user runs `/build-loop:plan
|
|
3
|
+
description: Use when build-loop Phase 2 wraps plan drafting, the user runs `/build-loop:verify-plan`, asks to "verify the plan" or "lint the plan", or any plan markdown change touches evidence, synthesis-density, risk_reason, or modifies_api fields. Runs deterministic plan-verify rules and emits findings JSON.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -213,6 +213,10 @@ mapping is valid. A real publish can still fail after a successful dry-run when
|
|
|
213
213
|
the npm package settings do not match the GitHub workflow. After publishing,
|
|
214
214
|
verify the registry metadata includes
|
|
215
215
|
`dist.attestations.provenance.predicateType = https://slsa.dev/provenance/v1`.
|
|
216
|
+
If the real publish step prints the final `+ @scope/package@version` line but
|
|
217
|
+
the immediate metadata check returns `E404`, do not rerun the same publish.
|
|
218
|
+
npmjs metadata can lag for a few minutes after acceptance; poll `npm view` or
|
|
219
|
+
use a verify-only workflow path.
|
|
216
220
|
|
|
217
221
|
### Access Token Fallback Gate
|
|
218
222
|
|
|
@@ -286,6 +290,10 @@ npm audit signatures
|
|
|
286
290
|
gh run rerun <run-id> --failed
|
|
287
291
|
```
|
|
288
292
|
|
|
293
|
+
- If npmjs succeeds through the final `+ @scope/package@version` line but the
|
|
294
|
+
post-publish metadata check returns `E404`, treat it as a visibility lag until
|
|
295
|
+
registry polling proves otherwise. Do not rerun the publish for that version;
|
|
296
|
+
rerun a verify-only path or poll `npm view`.
|
|
289
297
|
- Use local npm login or token publishing only as an explicit fallback decision,
|
|
290
298
|
because it bypasses the trusted-publisher/provenance path.
|
|
291
299
|
|