@trycore/spec-build-harness 0.5.0 → 0.7.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 (52) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/GOVERNANCE.md +44 -4
  3. package/INSTALL.md +3 -1
  4. package/METODOLOGIA.md +89 -14
  5. package/README.md +8 -14
  6. package/VERSION +1 -1
  7. package/agents/build/api-contract-tester.md +8 -0
  8. package/agents/build/build-orchestrator.md +44 -9
  9. package/agents/build/change-epic-coherence.md +11 -2
  10. package/agents/build/coherence-three-way.md +12 -4
  11. package/agents/build/data-consistency-checker.md +7 -0
  12. package/agents/build/dor-dod-gatekeeper.md +26 -10
  13. package/agents/build/security-reviewer.md +11 -3
  14. package/agents/build/simple-design-reviewer.md +4 -3
  15. package/agents/build/stack-guardian.md +12 -4
  16. package/agents/build/ux-fidelity-reviewer.md +22 -15
  17. package/agents/build/ux-krug-reviewer.md +12 -3
  18. package/agents/build/wiring-adversarial-verifier.md +66 -0
  19. package/commands/build/onboard.md +36 -1
  20. package/commands/build/reflect.md +32 -8
  21. package/commands/build/release.md +84 -0
  22. package/commands/build/slice.md +93 -0
  23. package/commands/build/work.md +68 -0
  24. package/docs/agents.md +26 -3
  25. package/docs/customization/mcp-extensions.md +16 -5
  26. package/docs/getting-started.md +64 -209
  27. package/docs/super-power-workflows.md +281 -0
  28. package/hooks/build/build-gate-check.sh +3 -1
  29. package/hooks/build/load-build-state.sh +44 -6
  30. package/hooks/build/release-gate-nudge.sh +40 -0
  31. package/hooks/build/stack-guard.sh +30 -8
  32. package/hooks/build-harness.json +4 -0
  33. package/package.json +1 -1
  34. package/scripts/check-agnostic.sh +1 -1
  35. package/skills/building-a-slice/SKILL.md +62 -6
  36. package/skills/building-a-slice/references/dod.md +15 -3
  37. package/skills/building-a-slice/references/dor.md +6 -3
  38. package/skills/building-a-slice/references/exploration-fanout.md +36 -0
  39. package/skills/building-a-slice/references/integration-check.md +27 -0
  40. package/skills/building-a-slice/references/mcp-map.md +1 -1
  41. package/skills/building-a-slice/references/state-protocol.md +26 -4
  42. package/skills/building-a-slice/workflows/README.md +25 -0
  43. package/skills/building-a-slice/workflows/explore-fanout.workflow.js +77 -0
  44. package/skills/building-a-slice/workflows/wiring-verify.workflow.js +88 -0
  45. package/skills/releasing-a-version/SKILL.md +21 -0
  46. package/skills/releasing-a-version/references/release-dod.md +2 -1
  47. package/skills/releasing-a-version/workflows/README.md +19 -0
  48. package/skills/releasing-a-version/workflows/release-gate.workflow.js +104 -0
  49. package/state/README.md +23 -5
  50. package/state/build-state.schema.json +51 -4
  51. package/templates/CLAUDE.md.template +6 -2
  52. package/templates/integration-check.sh.template +65 -0
@@ -0,0 +1,281 @@
1
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6903d22e13864f88ea55c2d8_b5c98d26c46edc43193e7f7e28a00633a538bb9c-1000x1000.svg)
2
+
3
+ #
4
+
5
+ A
6
+
7
+ harness
8
+
9
+ for
10
+
11
+ every
12
+
13
+ task:
14
+
15
+ dynamic
16
+
17
+ workflows
18
+
19
+ in
20
+
21
+ Claude
22
+
23
+ Code
24
+
25
+ Claude Code can now write and orchestrate its own multi-agent harness on the fly. Here's how dynamic workflows work, and the patterns that get the most out of them.
26
+
27
+
28
+
29
+ [](#)
30
+
31
+ [](#)
32
+
33
+ Get Claude Code
34
+
35
+ curl -fsSL https://claude.ai/install.sh | bash
36
+
37
+ Copy command to clipboard
38
+
39
+ irm https://claude.ai/install.ps1 | iex
40
+
41
+ Copy command to clipboard
42
+
43
+ Or read the [documentation](https://code.claude.com/docs/en/overview)
44
+
45
+ Try Claude Code
46
+
47
+ [Try Claude Code](https://claude.ai/redirect/claudedotcom.v1.e9ed21ea-4023-46bb-ad88-1ac576336b09/code)Try Claude Code
48
+
49
+ Developer docs
50
+
51
+ [Developer docs](https://code.claude.com/docs/en/overview)Developer docs
52
+
53
+ * Category
54
+
55
+ [Claude Code](https://claude.com/blog/category/claude-code)
56
+
57
+ * Product
58
+
59
+ No items found.
60
+
61
+ * Date
62
+
63
+ June 2, 2026
64
+
65
+ * Reading time
66
+
67
+ 5
68
+
69
+ min
70
+
71
+ * Share
72
+
73
+ [Copy link](#)
74
+
75
+
76
+ Last week, we released [dynamic workflows](https://code.claude.com/docs/en/workflows) in Claude Code. Claude can now write its own  [harness](https://code.claude.com/docs/en/glossary#agentic-harness) on the fly, custom-built for the task at hand.
77
+
78
+ While the default Claude Code harness is built for coding, it is also useful for many other types of tasks because, as it turns out, many tasks resemble coding tasks. But there are certain classes of tasks where we have had to build custom harnesses on top of Claude Code to achieve peak performance such as [Research](https://support.claude.com/en/articles/11088861-using-research-on-claude), [security analysis](https://support.claude.com/en/articles/11932705-automated-security-reviews-in-claude-code), [agent teams](https://code.claude.com/docs/en/agent-teams), or [Code Review](https://code.claude.com/docs/en/code-review).
79
+
80
+ Workflows allow you to dynamically create harnesses built on top of Claude Code that enable Claude to solve all of those problems more natively. You can also share and reuse these workflows with others.
81
+
82
+ In this article, I’ll cover my initial workflows experiences and learnings so you can best take full advantage. Keep in mind, best practices are still developing: dynamic workflows often use more tokens and are best suited for complex, high value tasks.
83
+
84
+ ## Example prompts
85
+
86
+ Before diving into the technical details, I’d like to start with several example prompts to get you thinking about the possibilities with workflows:
87
+
88
+ "This test fails maybe 1 in 50 runs. Set up a workflow to reproduce it. Form competing theories about the race, and don't stop until one theory survives the evidence." 
89
+
90
+ "Using a workflow, go through my last 50 sessions and mine them for corrections I keep making and turn the recurring ones into `CLAUDE.md` rules"
91
+
92
+ “Use a workflow to dig through #incidents in Slack for the past six months and find recurring root causes where nobody has filed a ticket." 
93
+
94
+ "Take my business plan and run a workflow where different agents tear it apart from an investor's, a customer's, and a competitor's perspective." 
95
+
96
+ "Here's a folder of 80 resumes, use a workflow to rank them for the backend role and double-check the top ten. Interview me using the AskUserQuestion tool for a rubric."
97
+
98
+ "I need a name for this CLI tool. Use a workflow to brainstorm a bunch of options and run a tournament to pick the top 3." 
99
+
100
+ "Use a workflow to rename our User model to Account everywhere." 
101
+
102
+ “Go through my blog post draft and verify every technical claim against the codebase using a workflow, I don't want to ship anything wrong."
103
+
104
+ ## How dynamic workflows work
105
+
106
+ Dynamic workflows execute a javascript file with a few special functions that help spawn and coordinate [subagents](https://code.claude.com/docs/en/sub-agents):
107
+
108
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f1684f559cc83ff4b465b_image1.png)
109
+
110
+ Dynamic workflows also include standard JavaScript functions like JSON, Math, and Array, to help process data.
111
+
112
+ It’s particularly useful to know that dynamic workflows can decide which models an agent uses and whether subagents are run in their own worktree, allowing Claude to choose the intelligence level and isolation needed.
113
+
114
+ If a workflow is interrupted, for example by user action or quitting the terminal, resuming the session will allow the workflow to pick up where it left off.
115
+
116
+ ## Why dynamic workflows 
117
+
118
+ When you ask the default Claude Code harness to do a task, it needs to both plan and execute in the same context window. For many coding tasks, this is highly effective, but it can break down over long-running, massively parallel, highly structured and/or adversarial tasks.
119
+
120
+ This is because the longer Claude works on a complex task in a single context window, the more it becomes susceptible to a few specific failure modes:
121
+
122
+ * **Agentic laziness** refers to when Claude stops before finishing a particularly complex, multi-part task and declares the job done after partial progress, for example addressing 35 of the 50 items in a security review.
123
+ * **Self-preferential bias** refers to Claude’s tendency to prefer its own results or findings, especially when asked to verify or judge them against a rubric. 
124
+ * **Goal drift** refers to the gradual loss of fidelity to the original objective across many turns, especially after compaction. Each summarization step is lossy, and details like edge-case requirements or "don't do X" constraints can get lost.
125
+
126
+ Creating a workflow helps combat these by orchestrating separate Claude subagents with their own context windows and focused, isolated goals.
127
+
128
+ ## Dynamic vs static workflows
129
+
130
+ You may have previously created a static workflow using the Claude Agent SDK or `claude -p` to coordinate multiple instances of Claude Code together. 
131
+
132
+ But because static workflows need to work for all edge cases, they are usually more generic. With [Claude Opus 4.8](https://www.anthropic.com/news/claude-opus-4-8) and dynamic workflows, Claude is now intelligent enough to write a custom harness tailor-made for your use case.
133
+
134
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f3a0e17e2844bed86f22a_image9.png)
135
+
136
+ ## Helpful patterns when using dynamic workflows
137
+
138
+ You can start using dynamic workflows just by asking Claude to make one, or by using the trigger word “`ultracode`” to ensure that Claude Code creates a workflow. 
139
+
140
+ But building a mental model for how dynamic workflows work will help you understand when to use them and how you might nudge Claude via prompts.
141
+
142
+ There are a few common patterns that Claude might use and compose together when building workflows:
143
+
144
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f16d86247e586b929a407_image10.png)
145
+
146
+ ### Classify-and-act
147
+
148
+ Use a classifier agent to decide on the type of task, and then route to different agents or behavior based on the task. Or, use a classifier at the end to determine output.
149
+
150
+ ### Fan-out-and-synthesize
151
+
152
+ Split up a task into many smaller steps, run an agent on each step and then synthesize those results. This is particularly useful for when there are a large number of smaller steps, or when each step benefits from its own clean context window so they don't interfere or cross-contaminate. The synthesize step is a barrier—it waits for all the fan-out agents, then merges their structured outputs into one result.
153
+
154
+ ### Adversarial verification
155
+
156
+ For each spawned agent, run a separate spawned agent to adversarially verify its output against a rubric or criteria. 
157
+
158
+ ### Generate-and-filter
159
+
160
+ Generate a number of ideas on a topic and then filter them by a rubric or by verification, dedupe duplicates and return only the highest quality, tested ideas.
161
+
162
+ ### Tournament
163
+
164
+ Instead of dividing the work, have agents compete on it. Spawn N agents that each attempt the same task using different approaches. Prompts or models then judge the results in a pairwise fashion using a judging agent until you have a winner.
165
+
166
+ ### Loop until done
167
+
168
+ For tasks with an unknown amount of work, loop spawning agents until a stop condition is met (no new findings, or no more errors in the logs) instead of a fixed number of passes.
169
+
170
+ ## Use cases
171
+
172
+ Think creatively of when and how to ask Claude Code to make dynamic workflows. I’ve found that workflows are sometimes even more useful for non-technical work.
173
+
174
+ ### Migrations and refactors 
175
+
176
+ [Bun](https://bun.com/) was rewritten from Zig to Rust using workflows. You can read more about how that was done in [Jarred’s X thread](https://x.com/jarredsumner/status/2060050578026189172). 
177
+
178
+ The key is to break down the task into a series of steps that need to be operated on for example callsites, failing tests, modules, etc. Spin off a subagent for every fix in a worktree to make the fix, then have another agent adversarially review, and merge them. Consider telling the agent not to use resource intensive commands so that you can maximally parallelize without running out of resources on your machine.
179
+
180
+ ### Deep research
181
+
182
+ We published a deep research skill (`/deep-research`) inside Claude Code that uses dynamic workflows. Specifically, it fans-out web searches, fetches sources, adversarially verifies their claims, and synthesizes a cited report.
183
+
184
+ But you may do this sort of research for more than just web searches. For example, asking Claude to compile a status report from context in Slack or to research how a feature works by exploring a codebase in-depth.
185
+
186
+ ### Deep verification
187
+
188
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f1721824a27cf13da87f4_image2.png)
189
+
190
+ On the other hand, if you have a report where you want to check and source every factual claim that it references you may want to generate a workflow which has one agent identify all of the factual claims and then spin off a subagent to check each one in-detail. You could also have a verification agent check the source subagent to make sure its source is high quality. 
191
+
192
+ ### Sorting
193
+
194
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f173ce727a972001584cc_image3.png)
195
+
196
+ You may have a list of items that you want to sort by some qualitative measurement that you believe that Claude Code is good at evaluating, for example: support tickets sorted by severity of the bug. But if you try to sort 1000+ rows in one prompt, quality degrades and it won't fit in context. Instead run a tournament, a pipeline of pairwise-comparison agents (comparative judgment is more reliable than absolute scoring), or bucket-rank in parallel then merge. Each comparison is its own agent, so the deterministic loop holds the bracket and only the running order stays in context.
197
+
198
+ ### Memory and rule adherence
199
+
200
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f17517076bb59050d90bb_image8.png)
201
+
202
+ If you have a particular set of rules that you find Claude misses or struggles with, even when put into the `CLAUDE.mds`, create a workflow with a list of rules that must be checked by verifier agents—one verifier per rule. Creating a skeptic persona subagent to review the rules to make sure they are in line will help avoid too many false positives.
203
+
204
+ The reverse direction works too: mine your recent sessions and code review comments for corrections you keep making, cluster them with parallel agents, adversarially verify each candidate (would this rule have prevented a real mistake?), and then distill the survivors back into a `CLAUDE.md`.
205
+
206
+ ### Root-cause investigation 
207
+
208
+ Debugging works best when you come up with several independent hypotheses and test them, but if you’re only using one context window, Claude can run into self-preferential bias
209
+
210
+ A workflow can structurally prevent this by spinning up agents to generate hypotheses from disjoint evidence. For example, separate agents for logs, files, and data. Each hypothesis can then face a panel of verifiers and refuters.
211
+
212
+ This isn't just for code. Workflows can be used for sales (why did sales drop in March?), data engineering (why did this pipeline fail?), or any post-mortem exercise.
213
+
214
+ ### Triaging at scale
215
+
216
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f1778dc00d34cca70819d_image6.png)
217
+
218
+ Every team has a support queue, bug reports, or some other backlog that cannot be fully processed by humans. 
219
+
220
+ A triage workflow classifies each item, dedupes against what's already tracked, and takes action. This could mean attempting the fix or escalating to a human user.
221
+
222
+ A useful pattern for triage workflows is quarantine. This involves barring the agents that read untrusted public content from taking high-privilege actions, which are instead done by the agents in charge of acting on the information.
223
+
224
+ Pair triage workflows with /loop to have Claude do this continuously.
225
+
226
+ ### Exploration and taste
227
+
228
+ Workflows can be useful when exploring different approaches to a solution, especially when it is taste based, like design or naming, and would benefit from a rubric.
229
+
230
+ Try asking Claude to explore a bunch of solutions, and give a review agent  a rubric for what a good solution looks like. The task is complete when the review agent feels like it has met the criteria. Solutions can also be ordered or selected via a tournament based on the rubric.
231
+
232
+ ### Evals
233
+
234
+ You can run lightweight evals for particular tasks by spinning off separate agents in a worktree and then spinning off comparison agents to compare and grade the specific outputs against a rubric. For example, evaluating and then refining a skill you’ve created against a particular criteria.
235
+
236
+ ### Model and intelligence routing
237
+
238
+ Create a classifier agent tuned to your tasks that decides which model to use. This can be helpful when your task will involve many tool calls and conducting research prior to execution can identify the best model for the job. 
239
+
240
+ For example, the best model for the task “explain how the auth module works” depends on how many files in the auth module there are and the shape of the codebase. A classifier agent can do this research and then route to Sonnet or Opus based on the expected complexity of the task.
241
+
242
+ ## When not to use dynamic workflows
243
+
244
+ Workflows are new. While there are many use cases where it will create outsized results, they are not needed for every task and may end up using significantly more tokens.
245
+
246
+ It’s best to use workflows creatively to push Claude Code in ways that you haven’t previously. For regular coding tasks, try and ask yourself: does it really need more compute? For example, most traditional coding tasks do not need a panel of 5 reviewers.
247
+
248
+ ## Tips for building dynamic workflows
249
+
250
+ ### Prompting
251
+
252
+ Detailed prompting, using the specific techniques we described above, for dynamic workflows creates the best results.
253
+
254
+ Workflows are not just for large tasks. You can prompt the model to use a “quick workflow.” For example, you can create a quick adversarial review of an assumption.
255
+
256
+ ### Combine with `/goal` and `/loop`
257
+
258
+ When using workflows that can be repeated, for example triage, research, or verification, pair them with `/loop` to be run at regular intervals, and /goal to set a hard completion requirement.
259
+
260
+ ### Token usage budgets
261
+
262
+ You can set explicit token usage budgets for dynamic workflows to limit how many tokens a task uses. You can prompt it with a budget like: “use 10k tokens,” which will set the cap.
263
+
264
+ ### Saving and sharing dynamic workflows
265
+
266
+ You can save workflows by pressing “s” in the workflow menu. You can check these into `~/.claude/workflows` or distribute them via a skill. 
267
+
268
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f17b1ca20533e666c867c_image4.png)
269
+
270
+ To share them via a skill, put your JavaScript workflow files in the skill and folder and reference them in the [SKILL.MD](http://skill.md). To allow for more flexibility, you may want to prompt Claude to think of the workflows in the skill as a template instead of a script that needs to be run verbatim.
271
+
272
+ ![](https://cdn.prod.website-files.com/68a44d4040f98a4adf2207b6/6a1f17cb835cf4f9fd5da921_image7.png)
273
+
274
+ ## A new starting point for discovery 
275
+
276
+ Workflows are a helpful new way to extend Claude Code. I encourage you to think of them as a starting point to explore new ways to use Claude to help accomplish your tasks. There is still much to discover in how to use them best. Let me know what you find. 
277
+
278
+
279
+
280
+ *This article was written by Thariq Shihipar and Sid Bidasaria, members of technical staff at Anthropic working on Claude Code.*
281
+
@@ -18,7 +18,9 @@ if not s: sys.exit(0)
18
18
  g=s.get("gates",{})
19
19
  abiertos=[k for k,v in g.items() if v is False]
20
20
  if abiertos:
21
- print(f"build-gate-check: slice {s.get('hu')} en fase '{s.get('phase')}' con gates abiertos: {', '.join(abiertos)}.", file=sys.stderr)
21
+ epica=s.get('epica') or '?'
22
+ hus=', '.join(s.get('hus') or []) or '—'
23
+ print(f"build-gate-check: slice {epica} [{hus}] en fase '{s.get('phase')}' con gates abiertos: {', '.join(abiertos)}.", file=sys.stderr)
22
24
  print(" No archives ni abras PR hasta cerrarlos (ver building-a-slice / dod.md).", file=sys.stderr)
23
25
  PY
24
26
  exit 0
@@ -12,15 +12,37 @@ BRANCH="$(git -C "$ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'descon
12
12
  if [ -f "$ROOT/package.json" ]; then PHASE="active"; else PHASE="authoring"; fi
13
13
 
14
14
  # Sincroniza harness_phase en el estado (si python3 disponible y el archivo existe).
15
+ # Escritura ATÓMICA + validada: este hook corre en CADA SessionStart (alta frecuencia,
16
+ # headless incluido); una escritura no atómica que se interrumpa truncaría la ÚNICA
17
+ # fuente de verdad. Solo escribe si harness_phase cambia; si algo falla, deja el original
18
+ # intacto (fail-open) y nunca rompe el SessionStart.
15
19
  if [ -f "$STATE" ] && command -v python3 >/dev/null 2>&1; then
16
20
  python3 - "$STATE" "$PHASE" <<'PY' 2>/dev/null || true
17
- import json,sys
21
+ import json,sys,os,tempfile
18
22
  path,phase=sys.argv[1],sys.argv[2]
19
23
  try:
20
- d=json.load(open(path))
21
- if d.get("harness_phase")!=phase:
22
- d["harness_phase"]=phase
23
- json.dump(d,open(path,"w"),indent=2,ensure_ascii=False)
24
+ with open(path) as fh:
25
+ d=json.load(fh)
26
+ # No escribir si no hay cambio.
27
+ if d.get("harness_phase")==phase:
28
+ sys.exit(0)
29
+ # Validación mínima de forma antes de tocar disco (no relajamos el schema completo,
30
+ # solo evitamos persistir algo que claramente no es un build-state).
31
+ if not isinstance(d,dict) or not all(k in d for k in ("version","harness_phase","active_slice","history","releases")):
32
+ sys.exit(0)
33
+ d["harness_phase"]=phase
34
+ dirn=os.path.dirname(path) or "."
35
+ fd,tmp=tempfile.mkstemp(dir=dirn,prefix=".build-state.",suffix=".tmp")
36
+ try:
37
+ with os.fdopen(fd,"w") as out:
38
+ json.dump(d,out,indent=2,ensure_ascii=False)
39
+ out.flush()
40
+ os.fsync(out.fileno())
41
+ os.replace(tmp,path) # sustitución atómica
42
+ except Exception:
43
+ try: os.unlink(tmp)
44
+ except OSError: pass
45
+ raise
24
46
  except Exception:
25
47
  pass
26
48
  PY
@@ -39,8 +61,24 @@ if not s:
39
61
  else:
40
62
  g=s.get("gates",{})
41
63
  abiertos=[k for k,v in g.items() if v is False]
42
- print(f" Slice activo: {s.get('hu')} ({s.get('epica')}) · change={s.get('openspec_change')} · fase={s.get('phase')}")
64
+ hus=", ".join(s.get("hus") or []) or "—"
65
+ print(f" Slice activo: {s.get('epica')} [{hus}] · change={s.get('openspec_change')} · fase={s.get('phase')}")
43
66
  print(f" Gates pendientes: {', '.join(abiertos) if abiertos else 'ninguno ✅'}")
67
+ # Handoff fino en disco (A1): items de cableado aún FAILING + última bitácora.
68
+ # Una sesión fresca arranca de aquí; mientras queden failing, el cableado NO está hecho.
69
+ failing=[w for w in (s.get("wiring_checklist") or []) if w.get("status")=="failing"]
70
+ if failing:
71
+ muestra="; ".join(f"{w.get('id')}({w.get('kind')})" for w in failing[:8])
72
+ extra=f" (+{len(failing)-8} más)" if len(failing)>8 else ""
73
+ print(f" ⚠️ Cableado pendiente ({len(failing)} item/s failing): {muestra}{extra}")
74
+ print(" NO declares el slice terminado mientras queden items failing (verifica con prueba real).")
75
+ pend=[ss for ss in (s.get("sub_slices") or []) if ss.get("status")!="done"]
76
+ if pend:
77
+ print(f" ⚠️ Sub-slices pendientes: {', '.join(ss.get('id') for ss in pend)}")
78
+ log=s.get("progress_log") or []
79
+ if log:
80
+ last=log[-1]
81
+ print(f" Última bitácora: [{last.get('by')}] {last.get('note')}")
44
82
  PY
45
83
  fi
46
84
  exit 0
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env bash
2
+ # release-gate-nudge.sh — Stop
3
+ # Sugiere correr el Release Gate (releasing-a-version) cuando hay ≥2 épicas archivadas sin
4
+ # auditar desde el último release. NUNCA bloquea el cierre, NUNCA ejecuta trabajo pesado,
5
+ # NUNCA llama al modelo ni escribe estado. Determinista y barato: aritmética de conjuntos
6
+ # sobre epicas[] (archivadas − cubiertas), independiente de timestamps.
7
+ # El criterio "cierra una línea de release" vive en docs/02-user-story-map/ y NO se intenta aquí
8
+ # (lo computa la skill building-a-slice en la fase 8).
9
+ set -uo pipefail
10
+
11
+ ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "${CLAUDE_PROJECT_DIR:-$(pwd)}")"
12
+ STATE="$ROOT/.claude/state/build-state.json"
13
+ [ -f "$STATE" ] || exit 0
14
+ command -v python3 >/dev/null 2>&1 || exit 0 # fail-open: jamás impide cerrar sesión
15
+
16
+ # Mensaje a STDOUT (no stderr): un Stop hook con exit 0 no bloquea el cierre; el 2>/dev/null
17
+ # suprime SOLO trazas de python, nunca el nudge.
18
+ python3 - "$STATE" <<'PY' 2>/dev/null || true
19
+ import json, sys
20
+ try:
21
+ d = json.load(open(sys.argv[1]))
22
+ except Exception:
23
+ sys.exit(0)
24
+ hist = d.get("history") or []
25
+ rels = d.get("releases") or []
26
+ # Épicas ya archivadas (slices cerrados).
27
+ archived = {h.get("epica") for h in hist if isinstance(h, dict) and isinstance(h.get("epica"), str)}
28
+ # Épicas ya cubiertas por ALGÚN release (pending/passed/failed por igual).
29
+ covered = set()
30
+ for r in rels:
31
+ if isinstance(r, dict):
32
+ for e in (r.get("epicas") or []):
33
+ if isinstance(e, str):
34
+ covered.add(e)
35
+ pend = sorted(archived - covered)
36
+ if len(pend) >= 2:
37
+ print(f"💡 Release Gate sugerido: {len(pend)} épicas archivadas sin auditar desde el último release ({', '.join(pend)}).")
38
+ print(" Ejecuta /build:release (o la skill releasing-a-version): corre los gates pesados UNA vez sobre el diff acumulado.")
39
+ PY
40
+ exit 0
@@ -33,20 +33,42 @@ ti=data.get("tool_input",{})
33
33
  fp=ti.get("file_path") or ti.get("path") or ""
34
34
  if not fp.endswith("package.json"):
35
35
  sys.exit(0)
36
- content=ti.get("content") or ti.get("new_string") or ""
37
- if not content.strip():
36
+ content=ti.get("content")
37
+ new=ti.get("new_string")
38
+ old=ti.get("old_string")
39
+ # Nada que verificar si la edición no aporta texto.
40
+ if not (content and content.strip()) and not (new and new.strip()):
38
41
  sys.exit(0)
39
42
  allow=json.load(open(os.environ["ALLOW"])).get("allow",[])
40
43
  def ok(name):
41
44
  return any(fnmatch.fnmatch(name, pat) for pat in allow)
42
- # Extrae nombres de deps tanto de JSON completo como de fragmentos de edición.
43
- deps=set()
44
- try:
45
- pkg=json.loads(content)
45
+ def extract(pkg):
46
+ deps=set()
46
47
  for sec in ("dependencies","devDependencies","peerDependencies","optionalDependencies"):
47
48
  deps.update((pkg.get(sec) or {}).keys())
48
- except Exception:
49
- for m in re.finditer(r'"((?:@[\w.-]+/)?[\w.-]+)"\s*:\s*"[\^~>=<*\d][^"]*"', content):
49
+ return deps
50
+ # Extracción por clave (version-agnóstica) en tres ramas de prioridad decreciente.
51
+ # Las ramas 1 y 2 parsean el documento COMPLETO, así que capturan specs no-semver
52
+ # (github:, file:, git+https:, npm:alias) que la regex de la rama 3 dejaba pasar.
53
+ deps=set(); extracted=False
54
+ # (1) Write con package.json completo en `content`.
55
+ if content and content.strip():
56
+ try:
57
+ deps=extract(json.loads(content)); extracted=True
58
+ except Exception:
59
+ pass
60
+ # (2) Edit: reconstruir el documento POST-edición leyendo el package.json de disco.
61
+ if not extracted and new is not None:
62
+ try:
63
+ with open(fp) as fh: disk=fh.read()
64
+ post = disk.replace(old, new) if old else (new + disk)
65
+ deps=extract(json.loads(post)); extracted=True
66
+ except Exception:
67
+ pass
68
+ # (3) Fallback (solo si 1 y 2 fallan): regex semver ACTUAL, sin ampliar.
69
+ if not extracted:
70
+ frag = content or new or ""
71
+ for m in re.finditer(r'"((?:@[\w.-]+/)?[\w.-]+)"\s*:\s*"[\^~>=<*\d][^"]*"', frag):
50
72
  deps.add(m.group(1))
51
73
  bad=sorted(d for d in deps if d and not ok(d))
52
74
  if bad:
@@ -65,6 +65,10 @@
65
65
  {
66
66
  "type": "command",
67
67
  "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/reflect-nudge.sh\""
68
+ },
69
+ {
70
+ "type": "command",
71
+ "command": "\"${CLAUDE_PLUGIN_ROOT:-$CLAUDE_PROJECT_DIR/.claude}/hooks/build/release-gate-nudge.sh\""
68
72
  }
69
73
  ]
70
74
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trycore/spec-build-harness",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Arnés agéntico de construcción de Trycore para Claude Code: pipeline de dos loops (slice por épica + release gate) con gates de calidad, estado compartido y OpenSpec. Compañero de @trycore/spec-product-flow. Agnóstico al proyecto.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -59,7 +59,7 @@ TARGETS=(
59
59
  for target in "${TARGETS[@]}"; do
60
60
  [[ -e "$target" ]] || continue
61
61
  hits=$(grep -riEn -- "$PATTERN" "$target" 2>/dev/null \
62
- --include='*.md' --include='*.json' --include='*.sh' \
62
+ --include='*.md' --include='*.json' --include='*.sh' --include='*.js' --include='*.mjs' \
63
63
  --exclude-dir='node_modules' || true)
64
64
  if [[ -n "$hits" ]]; then
65
65
  VIOLATIONS+=("$hits")
@@ -25,7 +25,14 @@ el avance en el estado.
25
25
  `.claude/state/README.md`). Lee antes de actuar; escribe una vez por transición.
26
26
  - **Secuencial**: un slice activo a la vez. Un gate no se salta.
27
27
  - **Divulgación progresiva**: carga el `references/<tema>.md` solo cuando la fase lo necesita.
28
- - **Delega en subagentes** para revisión pesada (devuelven síntesis, protegen el contexto).
28
+ - **Delega en subagentes** para revisión pesada y para **explorar** (devuelven síntesis condensada,
29
+ protegen el presupuesto de atención de la sesión principal para **cablear**, no para descubrir).
30
+ - **Refresh de contexto = estado por defecto**: cada iteración nace **headless / contexto virgen** y
31
+ reconstruye el estado **desde disco** (git + `build-state.json` + logs), no desde la conversación
32
+ viva. Mantén el **`wiring_checklist[]`** (un item por escenario AC y por punto de integración entre
33
+ capas): nace `failing`, pasa a `passing` **solo tras prueba real ejecutada**. Deja una nota en
34
+ `progress_log[]` por hito. **Mientras quede un item `failing`, el slice NO está terminado.** Ver
35
+ `references/state-protocol.md`.
29
36
 
30
37
  ## Dos loops
31
38
 
@@ -39,6 +46,39 @@ inner loop: **≤ ~20 min por épica** y producto que **camina end-to-end en tod
39
46
  > cada paso sea un stub. Cada épica posterior **engorda** un paso de ese esqueleto y mantiene el
40
47
  > `journey_smoke` verde. Nunca se construyen capas horizontales aisladas que "se juntan al final".
41
48
 
49
+ > **Cimiento antes que negocio (épicas fundacionales).** Las épicas marcadas `layer: foundational`
50
+ > (autenticación, acceso a datos, arquitectura base, design-system/componentes base) se construyen
51
+ > **antes** que las `layer: business`. El DoR **rechaza** abrir una épica de negocio que arrastra
52
+ > cimiento no construido y lo extrae a una épica fundacional previa (ver `dor.md`). Así cada slice de
53
+ > negocio **solo toca lógica aplicable** y no quema contexto creando infra.
54
+
55
+ > **Descomposición por tamaño (no one-shot).** Una épica que supera el **gate de tamaño**
56
+ > (heurística por defecto: **> 3 HU** ó **≥ 3 capas tocadas**; configurable por proyecto) es
57
+ > demasiado grande para una pasada: el DoR obliga a trocearla en **sub-slices verificables**
58
+ > (`sub_slices[]`) construidos **de a uno**, con `journey_smoke` verde entre cada uno antes de pasar
59
+ > al siguiente. El orquestador trabaja por **fases encadenadas** (mapear → generar → revisar →
60
+ > fix-loop → optimizar) y reparte la exploración **"ancho antes que profundo"** con subagentes
61
+ > **solo-lectura por área** (frontend/backend/datos); el **cableado** lo hace la sesión, no
62
+ > subagentes que escriben en paralelo. Trocear acota además el tamaño del `wiring_checklist[]`.
63
+ > Para épicas troceadas, esa exploración solo-lectura **puede** conducirse con la plantilla (opcional)
64
+ > `workflows/explore-fanout.workflow.js` — contrato en `references/exploration-fanout.md`. **No** se usa en
65
+ > épicas atómicas (inflaría el inner loop barato); es read-only (no escribe estado) y el cableado sigue
66
+ > siendo de la sesión.
67
+
68
+ ## Workflows (plantillas, no scripts)
69
+
70
+ Los archivos `*.workflow.js` bajo `workflows/` son **plantillas de referencia** que esta skill **conduce**,
71
+ no scripts a correr verbatim (si contradicen `METODOLOGIA.md`, gana la metodología). Reglas duras:
72
+ - **Opt-in y solo para épicas grandes.** Los workflows del inner loop solo aplican a épicas troceadas por el
73
+ gate de tamaño (`sub_slices[]` no vacío); **nunca** en el camino caliente ≤ ~20 min de una épica atómica.
74
+ - **Read-only sobre el estado.** Ningún workflow escribe `build-state.json`: devuelven un diagnóstico y
75
+ `build-orchestrator` (o el agente dueño del gate) aplica el mapeo respetando el protocolo (una transición =
76
+ una escritura; gates monótonos; **validar contra el schema tras escribir**).
77
+ - **Subagentes de exploración = solo-lectura** (Read/Grep/Glob); el cableado lo hace la sesión.
78
+
79
+ Ver `workflows/README.md`. Hoy: `workflows/explore-fanout.workflow.js` (exploración fan-out) y
80
+ `workflows/wiring-verify.workflow.js` (conducción del verificador adversarial del gate `wiring_verified`).
81
+
42
82
  ## Fase 0 · Scaffold (Paso 1 fundamental — precondición restrictiva)
43
83
 
44
84
  Antes de abrir **cualquier** slice, el scaffold runnable del proyecto debe **existir y estar
@@ -78,9 +118,9 @@ Espejo de la Fase 0, para proyectos **con UI**. Antes de abrir el primer slice c
78
118
  | 1 · dor | Validar Definition of Ready | `dor-dod-gatekeeper` | `dor` | `dor.md` |
79
119
  | 2 · change | `opsx:new` + bloque `## Trazabilidad`; validar enlace (barato) | `opsx:new`, `change-epic-coherence` | `coherence_link` | `link-change-epic.md` |
80
120
  | 3 · tdd | red → green → refactor | `superpowers:test-driven-development` | `tdd` | — |
81
- | 4 · smoke | Recorrer el journey-hasta-aquí end-to-end; **slices con UI:** verificar fidelidad a la fuente de diseño | skill `verify` / `run` (+ MCP chrome-devtools), `ux-fidelity-reviewer` | `journey_smoke`,`fidelity` | `mcp-map.md` |
121
+ | 4 · smoke | Recorrer el journey-hasta-aquí end-to-end con el **runner determinista fuera-de-chat** (`integration-check`: suite+build+reporte) en **sesión/contexto virgen**; **slices con UI:** fidelidad por **verificación visual REAL** (MCP chrome-devtools, screenshot app vs prototipo) | runner `integration-check`, skill `verify`/`run` + MCP chrome-devtools, `ux-fidelity-reviewer` | `journey_smoke`,`fidelity` | `integration-check.md`, `mcp-map.md` |
82
122
  | 5 · api/data | contratos + consistencia (si aplican al slice) | `api-contract-tester`, `data-consistency-checker` | `api`,`data` | `newman-tests.md`, `data-consistency.md` |
83
- | 6 · dod | Definition of Done (por slice, reducido) | `dor-dod-gatekeeper` | `dod` | `dod.md` |
123
+ | 6 · dod | **Primero** verificación adversarial INDEPENDIENTE del cableado (contexto virgen: refuta stubs/rutas sin cablear/AC sin test/items `failing`) → `wiring_verified`; **solo entonces** Definition of Done | `wiring-adversarial-verifier`, `dor-dod-gatekeeper` | `wiring_verified`,`dod` | `dod.md`, `integration-check.md` |
84
124
  | 7 · pr | Abrir PR + archivar change en el mismo PR | `opsx:archive`, `opsx:sync` | — | `gitflow.md` |
85
125
  | 8 · release? | Preguntar si correr el Release Gate ahora | usuario (default computado) | — | abajo |
86
126
 
@@ -88,9 +128,15 @@ Los gates `stack`, `security`, `smell`, `ux` y la coherencia triple completa **y
88
128
  aquí**: pertenecen al Release Gate. Las **deps** siguen vigiladas en tiempo real por el hook
89
129
  `stack-guard.sh`; lint/tsc/gitflow por sus hooks.
90
130
 
91
- El gate `fidelity` (fidelidad a la fuente de diseño) **sí** es de inner loop: es barato (se computa
92
- en `smoke`, con la app ya levantada) y vivo por-slice; complementa al `ux-krug-reviewer` (usabilidad),
93
- que sigue en el Release Gate.
131
+ El gate `fidelity` (fidelidad a la fuente de diseño) **sí** es de inner loop: se computa en `smoke`,
132
+ con la app ya levantada, y es vivo por-slice; complementa al `ux-krug-reviewer` (usabilidad), que
133
+ sigue en el Release Gate. **Estricto para UI:** una UI no mejora su fidelidad por el prompt sino
134
+ porque el agente **carga la página, observa la salida real y lee la consola**. Para slices con UI
135
+ (`design_source.applies===true`), `fidelity` **solo cierra con verificación visual real vía MCP
136
+ chrome-devtools** (screenshot app vs prototipo). Sin MCP, `fidelity` queda `false` (INCONCLUSO ya
137
+ **no** pasa) → el `dod` no cierra: corre el slice donde haya MCP. Mantén **cobertura** (ninguna
138
+ pantalla del prototipo en alcance sin construir; ninguna pantalla de la app sin HU/EP) y el
139
+ **journey-smoke de clic real como tenant no-admin**.
94
140
 
95
141
  MCP/LSP por gate: ver `references/mcp-map.md`. Protocolo de estado: `references/state-protocol.md`.
96
142
 
@@ -126,4 +172,14 @@ El usuario siempre puede sobreescribir el default. Si acepta, invoca la skill
126
172
  - El enlace change↔épica va en `## Trazabilidad` del `proposal.md`, **nunca** en frontmatter YAML
127
173
  (rompe `openspec validate`). Ver `link-change-epic.md`.
128
174
  - Integración solo por **PR** a `main` (el hook `gitflow-guard.sh` bloquea commits/push directos).
175
+ - **`dod` exige `wiring_verified: true`** (verificación adversarial independiente, contexto virgen).
176
+ El DoD declarativo del gatekeeper es un **piso, no el arreglo**: reusar el mismo agente como
177
+ generador y verificador produce auto-confirmación. La generación y la verificación van separadas.
178
+ Opcionalmente, esa verificación se **conduce** con la plantilla read-only
179
+ `workflows/wiring-verify.workflow.js` (envuelve al `wiring-adversarial-verifier`); `build-orchestrator`
180
+ sigue siendo quien **escribe** `gates.wiring_verified` a partir del veredicto que la plantilla devuelve.
181
+ - **Producto completo, no MVP.** El alcance acordado se construye entero. **Recortar o diferir es
182
+ bloqueante explícito** que requiere acuerdo del equipo — nunca una decisión del modelo. No derives
183
+ en lo complejo. La verificación es **ejecutada, no por inspección** (ver `METODOLOGIA.md` y el
184
+ bloque del arnés en `CLAUDE.md`).
129
185
  - Si una regla aquí contradice la metodología Trycore (`METODOLOGIA.md`), **gana la metodología**.
@@ -12,9 +12,21 @@ pesadas (seguridad, diseño, UX, coherencia triple, arquitectura, integración)
12
12
  - [ ] **`data`** — `data-consistency-checker` valida invariantes de datos (salida de servicios externos validada contra esquema antes de alimentar la capa de decisión determinista del dominio) (si el slice toca datos).
13
13
  - [ ] **`api`** — `api-contract-tester` (Newman) 100% verde (o `null` si el slice no tiene endpoints).
14
14
  - [ ] **`fidelity` (slices con UI)** — `ux-fidelity-reviewer` devuelve **FIEL** (o DESVIACIONES todas
15
- justificadas/documentadas) → `gates.fidelity: true`; `null` si el slice no tiene UI. INCONCLUSO
16
- (MCP no disponible) se registra, **no bloquea**. Es gate **vivo** de inner loop (no la revisión Krug,
17
- que sigue en el Release Gate).
15
+ justificadas/documentadas) → `gates.fidelity: true`; `null` si el slice no tiene UI. **ESTRICTO para
16
+ UI** (`design_source.applies===true`): solo `true` con **verificación visual real** vía MCP
17
+ chrome-devtools (screenshot app vs prototipo). **INCONCLUSO ya NO pasa**: sin MCP queda `false` y el
18
+ `dod` no cierra (corre el slice donde haya MCP). Mantén **cobertura** (ninguna pantalla del prototipo
19
+ en alcance sin construir; ninguna pantalla de la app sin HU/EP). Es gate **vivo** de inner loop (no la
20
+ revisión Krug, que sigue en el Release Gate).
21
+ - [ ] **Sub-slices completos** — si la épica se descompuso (`sub_slices[]` no vacío), **todos** en
22
+ `status: done` con su `journey_smoke` verde. No se cierra `dod` con sub-slices pendientes.
23
+ - [ ] **`wiring_verified`** — el `wiring-adversarial-verifier` (subagente **independiente**, contexto
24
+ virgen) intentó **refutar** el slice (stubs, rutas sin cablear, AC sin test, items de
25
+ `wiring_checklist[]` aún `failing`) y no halló huecos → `gates.wiring_verified: true`. **Prerequisito
26
+ duro de `dod`**: el DoD declarativo de este checklist es un **piso, no el arreglo** (la auto-confirmación
27
+ surge de reusar el mismo agente como generador y verificador). Esa verificación puede conducirse,
28
+ opcionalmente, con la plantilla read-only `../workflows/wiring-verify.workflow.js` (envuelve al verificador;
29
+ `build-orchestrator` es quien escribe el gate a partir de su veredicto).
18
30
  - [ ] **OpenSpec**: todas las tasks `[x]`; el archive del change va **en el mismo PR** (no PR aparte).
19
31
  - [ ] **Docs/trazabilidad**: back-ref del change añadida en la épica y en cada HU de `hus[]`.
20
32
  - [ ] **Hooks verdes (automáticos, no son gates de agente)**: `lint-typecheck.sh` (lint + chequeo de tipos del stack declarado), `stack-guard.sh` (deps en allowlist según la sección de requisitos técnicos del PRD del consumidor, ruta declarada en `stack-allowlist.json#source`), `gitflow-guard.sh` (rama `feature/*`, sin commits directos a `main`).