/mold
When to invoke: Converge a fuzzy idea or half-formed feature into an approved spec through an iterative, grounded design dialogue. Use when the user has a fuzzy idea or design direction — phrases like “let’s design X”, “I’m thinking about Y”, “what should the API for Z look like”, “shape this into a spec”, “what would it take to build/set up X”, “I want to add a feature that…”, “/mold”. Use even when the user is “just thinking out loud” if they want the dialogue to leave behind a written artifact. Do NOT use for free-form discussion with no artifact intent (/culture), direct implementation (/cook), or research-only questions (/briesearch).
Two modes, by analogy to /culture:
- User-invoked full ceremony (default). The user typed
/mold(or/cheeserouted an explicit fuzzy-design ask straight here). Runs the full Explore/Ground/Shape/Sketch/Grill/Diagnose dialogue and the two-key handshake before any spec is written; the Flow below describes it. - Agent-invoked mini-spec mode.
/cheesecalls into/moldat tier 1 of its escalation (skills/cheese/SKILL.md§ Escalation) when the cook fast-path checks all pass and a spec must materialise before/cook --autoruns. No dialogue, no handshake. See## Agent-invoked mini-spec modebelow.
- Bounds pass — before routing, run one Explore-style bounds round for every input shape: map the problem’s edges to candidate goals and non-goals, asking the user rather than assuming. Open the per-round decision ledger (
Decided / Asking / [AGENT-DECIDED]; see## Rules). Tier it — a clear input gets a single fast confirm, not a full A/B/C/D menu — but never skip it. When the dialogue reveals full-spec-sized work, warn to upgrade tier (harness-detected: claude/model opus+/effort; codex/OMP equivalent; generic fallback) before continuing. - Route — pick the secondary mode from the input shape (see
references/modes.md) and announce it in one line. If the user’s framing rests on a false premise or a loaded assumption, name it before routing. - Dialogue — build shared understanding: every consequential fork is the user’s to pick, surfaced as a choice, never settled for them. Contribute full depth (options, edge cases, evidence) to inform each question, never to replace asking it. Ground every critical claim via the selected source-code search/read backend, a Validate Cycle (
references/validate-cycle.md), or — for an ungrillable design unknown — a Prototype Cycle (references/prototype-cycle.md); both are sub-agent-spawnable mid-dialogue, in parallel, context-bounded (soft backstop of 10). Track and resolve contradictions across turns before continuing. After 3 consecutive fork questions, or on “what forks are left?”, render the decision map (## Rules§ Decision map). - Sketch — for any feature touching >1 module or a new public interface, run the shape check (
references/shape-check.md) on the touched symbols, then lock seams in pseudocode signatures before talking spec content. While the code is open, bind every identity/ownership-role noun to a code referent perreferences/handshake.md§ Entity-referent binding — a search hit of a different referent is an alias, not a pass. - Decompose for approval — once the draft spec and any pre-Curdle follow-up disposition are complete, dispatch the fresh-context curd-block decomposer on the draft text and validate its result before requesting approval. Retry an invalid result once; if it is still invalid, stop before the handshake rather than approving a block that cannot be persisted. Present the validated curd block as
N curds / M wavesat the handshake. Seereferences/curdle.md§ “Pre-approval decomposer dispatch”. - Two-key handshake — both the user (explicit verb) and the agent (coherence self-check) must agree to the draft spec and displayed curd plan before extraction. Neither key changes or disappears. See
references/handshake.md. - Curdle — resolve the durable spec path with
SPEC=$(python3 shared/scripts/artifact_path.py specs <slug>)(bundle-only host fallback:python3 skills/mold/scripts/mold.pyz artifact-path specs <slug>). The resolver anchors specs at the per-project durable corpus (../cheese/references/formatting.md§ Corpus location); never hardcode a repo-local spec path. Phase one writes every local artifact and write-ahead prepared state before any external call: the approved spec at"$SPEC", the same approved curd block as## Curds, any local issue drafts, and the session’s non-obvious decisions as durable ADRs. Phase two then publishes approved follow-ups, retains prepared recovery state when an external capability is unavailable or publication fails, and reconciles their state and references into the durable spec. Never re-dispatch or mutate the approved curd block during Curdle. Format, slug, publication, reconciliation, corpus-resolution, and curd-block persistence rules:references/curdle.mdandreferences/adr.md. - Count and hand off — only after phase-two publication attempts and reconciliation finish, run
python3 skills/mold/scripts/mold.pyz curd-count "$SPEC" --blast-radius <low|medium|high>for the recommended downstream skill (procedure inreferences/curd-count.md), then prompt via## Handoff. Never dispatch before the user selects; after a non-stop selection, run the selected skill immediately.
Portability reference: ../cheese/references/harness-portability.md. It covers helper resolution, sub-agent dispatch, GitHub operations, and handoff transitions; prefer the bundled or repo-local helper first, and treat ${CLAUDE_SKILL_DIR} as optional host-provided fallback.
The handoff blocks below are the portable contract; slash commands are host renderings, not the control model.
Follow-up candidates
Section titled “Follow-up candidates”Every non-goal and explicit dialogue deferral enters the session’s follow-up candidate set, logged as [FOLLOW-UP?]. When candidates exist, the pre-Curdle disposition batch must complete before the two-key handshake can pass; omit it when none exist. Ledger notation, dialogue-state semantics, and Curdle-ordering detail: references/handshake.md § Follow-up disposition.
| Mode | Use when | Goal |
|---|---|---|
| Explore | The idea is vague | Identify the real problem and pain point |
| Ground | A file, bug, or existing doc is named | Verify facts against evidence |
| Shape | The goal is known but approach is open | Compare viable options (Do Nothing always included) |
| Sketch | Interfaces or module boundaries matter | Lock responsibilities and seams |
| Grill | A favoured approach needs stress-testing | Steelman each item, then put every design-changing call to the user as a fork |
| Diagnose | A symptom, failure, or trace is supplied | Build a Loop → reproduce → hypothesize → confirm root cause |
Full mode definitions, exit criteria, and user knobs: references/modes.md. Trigger and trace evals, including the Grill user-fork checks: references/evals.md.
Agent-invoked mini-spec mode
Section titled “Agent-invoked mini-spec mode”/cheese’s tier-1 escalation calls into /mold to produce a spec without a user-facing dialogue, once the cook fast-path checks have already passed at the call site. The mode skips the Flow above entirely: derive a slug, write the mini-spec, and return the resolved spec path so /cheese can dispatch /cook --auto <spec-path>.
The two-key handshake does not fire in this mode; the agent-introduced-scope check still runs implicitly — every distinguishing noun in the mini-spec must come from the user’s input or the tier-2 /culture//briesearch synthesis, never a silent agent addition.
Full procedure, the mini-spec schema, and the ## Provenance rules: references/mini-spec-mode.md.
Preferred tools and fallbacks
Section titled “Preferred tools and fallbacks”Call source-code search, read, and edit backends directly according to code-intelligence-routing.md. Shape checks use semantic caller search plus dependency context; procedure: references/shape-check.md.
Beyond source-code routing there are mold-specific tools:
| Need | Prefer | Fallback |
|---|---|---|
| External validation | /briesearch with Context7/Tavily |
user-provided docs, repo docs, or note as unverified |
Wiki grounding (Ground entry + decision points; scope per references/grounding.md § When to probe) |
mcp__hallouminate__list_corpora + mcp__hallouminate__ground on repo:<repo>:wiki |
skip; proceed with code evidence only; cap at speculating when design rationale is central |
Optional tools accelerate the work but never block the dialogue. When evidence is unavailable, mark the claim [?] until settled.
Sub-agent context gate
Section titled “Sub-agent context gate”/mold keeps the dialogue, contradictions, approval state, and the two-key handshake in the parent context — those never delegate. Offloading heavy work to a read-only sub-agent is the default: explorer for code reads and shape checks, researcher for deep /briesearch. Spawn one whenever the work would flood the conversation with raw evidence or graph output. Triggers, digest constraints, and the inline fallback: references/context-budget.md.
Gate graph
Section titled “Gate graph”Mold’s gate state machine is one machine-readable model, rendered via python3 skills/mold/scripts/mold.pyz gate-graph --render dot|svg|png|mermaid. dot/mermaid need no binary; svg/png use Graphviz dot when present and degrade to mermaid. A test keeps its gate nodes in lockstep with the handshake.md coherence checklist, so a gate cannot be dropped from prose. Details: references/gate-graph.md.
Approval gate
Section titled “Approval gate”Curdle requires the two-key handshake: an explicit user verb (e.g. curdle, ship it) plus the agent’s coherence self-check, with the validated curd block’s N curds / M waves presented alongside the final approval request (Flow step 5). Checklist, mandatory gates, and override semantics: references/handshake.md.
Before the handshake fires, also run the agent-introduced-scope check — flag any noun in Approach / Decisions / Interface sketches the user did not type, and require explicit per-term approval before extraction. Full procedure and the single-chokepoint guarantee in references/handshake.md § Agent-introduced scope.
If any gate is unmet or the curd block remains invalid after one retry, propose the smallest next question, evidence check, or decomposer correction. Write artifacts only after both keys pass.
/mold --hard propagates --hard to /cook at handoff (any cook-flavoured option carries it forward). Mold runs no gate itself — the metacognitive vibecheck fires later, at /cure’s share-for-review boundary. See skills/hard-cheese/SKILL.md and ../hard-cheese/references/composition.md.
Handoff
Section titled “Handoff”Pipeline: culture → [mold] → cook → press → age → cure → plate
After Curdle’s phase two finishes, run the curd-count script (procedure and --blast-radius rules in references/curd-count.md), then render the branch menu below and prompt via the shared handoff gate. Never pre-select an autonomous option.
Read the JSON digest. /cook is the uniform (recommended) option; the digest’s mode field (parallel, linear, or null) is orientation-only — it explains why a branch recommends the autonomous chain and is never rendered as a skill name. Ask via the shared handoff gate (../cheese/references/handoff-gate.md), leading each option with the verb and the skill command (spec path plus any in-scope --hard) as backing detail.
The three blast-radius branches — decomposable, non-decomposable high-blast-radius, and non-decomposable low/medium — each render a fixed menu keyed off the digest’s decomposable, candidate_curds, verdict, and mode fields. Menu wording, the recommended/manual/stop options per branch, and mode’s role in choosing the branch: references/handoff-menus.md.
- Dialogue first; artifacts are the by-product.
- Tiered lettered options. Consequential forks (scope, approach, non-goals, interface/seam, trade-offs) go to the user as
A/B/C/Dchoices via the question transport at../cheese/references/ask-user-question.md— never resolved silently. Minor mechanical calls are logged[AGENT-DECIDED]inline with a one-line vetoable alternative (ADR-003). A fork is valid only after its depth was contributed in-dialogue first. Visible-prose gate (hard): every structured question MUST be preceded, same visible turn, by prose naming the fork, weighing options, and citing evidence — never in a thinking block, never straight from the user’s message to the picker. One open picker: never emit a second structured question before the first is answered. - Per-round decision ledger. Each dialogue round prints
Decided / Asking / [AGENT-DECIDED]. At curdle the ledger persists to the ADR(s) (references/adr.md) plus a one-line minor decision-log on the spec; no separate ledger file (ADR-004). - Decision map. After 3 consecutive fork questions, or on “what forks are left?”, render a compact map from the ledger: Done forks (from
Decided), remaining-before-curdle forks split into required (references/handshake.md§ Mandatory gates) vs optional, and a one-line curdle-readiness verdict (ready, or blocked naming the unmet gate). It renders existing state — not a new artifact, file, or script. - Do not implement code.
- Do not write production files before the approval gate.
- Do not silently settle uncertain claims.
- Apply the shared voice kernel (lives at
../age/references/voice.md): correct false premises, flag confidence ascertain | speculating | don't knowon each critical claim, steelman before dismissing, and put the design-shaping decisions to the user — depth informs each question, it never replaces asking it.
Agent resolution
Section titled “Agent resolution”Resolve delegates through ../cheese/references/agent-resolution.md.
| Work | Preferred types | Permissions/isolation | Minimum power | Effort | Fallback |
|---|---|---|---|---|---|
| Explore the codebase | explorer | read-only, fresh-context | default | medium | compatible explorer, then general |
| Research external constraints | researcher | read-only, fresh-context | default | medium | compatible researcher, then general |
| Decompose for approval | planner, general | read-only, fresh-context | powerful | high | compatible planner, then general |
The canonical mold spec or mini-spec carries the shared agent_resolution block.
ADRs — durable design rationale
Section titled “ADRs — durable design rationale”Mold records the non-obvious decisions of a session as Architecture Decision Records (ADRs). The approved spec and its ADRs are durable project records: the spec keeps the implementation contract, while ADRs preserve the rationale a future session would otherwise re-derive. Write them at Curdle, after the two-key handshake, in phase one’s local atomic write.
What earns an ADR
Section titled “What earns an ADR”One ADR per decision a future reader would otherwise have to reverse-engineer:
- a chosen approach over a real alternative (the trade-off, not the obvious pick);
- a constraint discovered mid-dialogue (a Prototype Cycle answer that changed the
design; a
[CONFLICT]the codebase forced); - anything tagged a Decision in the spec that has a substantive rationale.
Do not write an ADR for a forced move with no alternative, or for a detail the spec body already states plainly.
Decision ledger
Section titled “Decision ledger”Mold’s per-round decision ledger (Decided / Asking / [AGENT-DECIDED], see
../SKILL.md § Rules) persists here at curdle: each [AGENT-DECIDED] call
that had a real alternative the user could have vetoed earns an ADR — it is
exactly the kind of decision a future reader would otherwise reverse-engineer.
Minor calls with no surviving alternative ride the spec’s one-line decision-log
(curdle.md § Spec template) instead of a full ADR; the ledger keeps no separate
file (ADR-004).
Resolution — where ADRs land (portable, never hardcoded)
Section titled “Resolution — where ADRs land (portable, never hardcoded)”Mold runs in arbitrary repos. The corpus is resolved dynamically at curdle,
never hardcoded — there is no easy-cheese:wiki baked into a runtime path.
adr_target(): # 1. Probe for a hallouminate wiki at the CONSUMER's root repo. # Shape-match the corpus, never exact-match a placeholder — the repo name is # dynamic (matches grounding.md and paths.py's domain_model_target()). corpus = first(c for c in hallouminate.list_corpora() if c.startswith("repo:") and c.endswith(":wiki")) # dynamic; their repo, not ours if corpus: return ("hallouminate", corpus) # searchable, cross-session # 2. Fall back to a tracked file path everywhere else. return ("file", "docs/adr/<slug>-NNN.md") # tracked in the consumer's repo- hallouminate present: write each ADR into the consumer’s
repo:<their-repo>:wikicorpus viaadd_markdown. The corpus is shape-matched fromlist_corpora, never a literal — that is the portability invariant. - hallouminate absent: write
docs/adr/<slug>-NNN.md(tracked), emit a loud one-line note that the ADR went to a file rather than the wiki (never a silent degrade — seecurdle.md§ Atomic write), and recommend installing hallouminate so future rationale becomes searchable. - probe shape varies by harness
[?]: iflist_corporais unreachable, fall back to the tracked file path and say so — never block curdle on the probe.
The spec path follows the separate artifact resolver contract and remains in its durable project corpus; ADR target resolution does not make the approved spec transient.
ADR format
Section titled “ADR format”Mirror the spec’s own ## ADRs section shape (this very spec uses it):
### ADR-NNN: <one-line decision title> [status: accepted]- **Context:** <what made this a real decision; the forces in play>- **Decision:** <what we chose>- **Alternatives:** <the rejected options and why>- **Consequences:** <what this buys and what it costs later>Numbering is per-slug (<slug>-001, -002, …) on the file fallback; in the wiki,
prefix the page slug the same way so the series stays grouped.
Timing
Section titled “Timing”ADRs are a phase-one Curdle by-product. Write them after both handshake keys
pass, in the same local atomic step as the durable spec and before any external
follow-up publication. They never substitute for the spec’s own ## Decisions
line: the ADR is the long form; the Decisions bullet is the index entry.
Context budget — staying out of the dumb zone
Section titled “Context budget — staying out of the dumb zone”A long mold dialogue can drift into the model’s degraded-attention band (roughly ~120k–140k tokens), where recall and coherence soften. Mold defends the window two ways: offload heavy work to sub-agents by default, and nudge the user toward a checkpoint as the window fills. Both are advisory levers, not hard gates — the reliable one is sub-agent offload (ADR-003, Risks).
Default: offload heavy work to sub-agents
Section titled “Default: offload heavy work to sub-agents”The sub-agent context gate (SKILL.md § Sub-agent context gate) is the default for heavy work, not an exception. Resolve the typed read-only role through ../../cheese/references/agent-resolution.md: exact specialist, compatible specialist, then a prompt-constrained general worker with degraded: true. Use inline work only when dispatch is unavailable:
- Research: deep
/briesearch(3+ doc fetches or 2+ search angles) — theresearcherphase-agent. - Shape check: more than 5 symbols, wide module fan-out, large caller/dep
traversals — the
explorerphase-agent. - Prototype Cycle: the throwaway build always runs in a sub-agent
(
prototype-cycle.md) — theexplorerphase-agent. - Diagnose: bulky logs/traces before a concise root-cause hypothesis — the
explorerphase-agent.
The sub-agent returns a ≤2 KB digest; the raw evidence never enters the parent window. The parent keeps only the dialogue, contradictions, approval state, and the two-key handshake — those never delegate.
The nudge — heuristic, not a hard count
Section titled “The nudge — heuristic, not a hard count”There is no precise live token count, so the budget is a heuristic estimate, designed as a nudge:
| Estimate | Action |
|---|---|
| ~120k tokens | Advisory: note the window is filling; prefer sub-agent offload for the next heavy step; tighten questions. |
| ~140k tokens | Suggest a re-up: recommend /wheypoint to compact the session into a durable handoff slug, then resume in a fresh context. |
Estimate from the visible signals — turn count, sub-agent digests folded in, large pastes — not a false-precision number. When in doubt, offload before you nudge: the sub-agent split is the lever that actually moves the needle.
The wheypoint re-up
Section titled “The wheypoint re-up”At the ~140k nudge, recommend (do not auto-run):
The dialogue is large enough to risk the model's dumb zone. /wheypoint willcompact what we've decided into .cheese/notes/<slug>.md so a fresh session canresume without losing the handshake state. Resume with /cheese --continue <slug>./wheypoint preserves the dialogue, contradictions, approval state, and any open
Validate/Prototype cycles, so the fresh agent picks up mid-handshake rather than
re-deriving the design. See skills/wheypoint/SKILL.md.
Why a nudge, not a gate
Section titled “Why a nudge, not a gate”A hard token gate would cut confidence-gathering short — the exact failure ADR-003 rejects for cycle caps. The window pressure is real but approximate, so mold treats it as a prompt to act (offload or checkpoint), never as a wall that ends the dialogue.
Curd count — recommendation driver
Section titled “Curd count — recommendation driver”Runs after Curdle writes the spec, before the Handoff menu renders. Pushes the parse-and-count work into a Python script so the recommendation is deterministic and stays out of the conversation’s token budget.
What it answers
Section titled “What it answers”Whether to recommend /cook for the (recommended) slot in the Handoff
menu, and which internal wave-plan mode to signal alongside it: parallel
curd fan-out or the linear chain. /cook is the uniform recommendation —
/ultracook is retired as a top-level skill choice.
/cook --auto is a user-opt-in alternative the menu always offers in the
non-decomposable low/medium branch, but it is never a recommended pick: per
existing mold rules, “Never pre-select; auto mode is opt-in” — so the script
does not consider it.
A decomposition of PARALLEL_THRESHOLD (2) or more curds signals a parallel
wave-plan; below that, the choice between plain /cook and a linear-mode
/cook is driven by the shape-check’s blast-radius verdict. The decomposer
stays authoritative — the count is a pre-dispatch hint, not the mode gate.
Procedure
Section titled “Procedure”After curdle.md writes the spec to disk, run the script and read the JSON
digest into context:
SPEC=$(python3 ${CLAUDE_SKILL_DIR}/scripts/mold.pyz artifact-path specs <slug>)python3 ${CLAUDE_SKILL_DIR}/scripts/mold.pyz curd-count "$SPEC" \ --blast-radius <low|medium|high>Pass the --blast-radius value verbatim from the shape-check verdict line
(see shape-check.md). If shape-check was skipped or its verdict was [?],
omit the flag — the recommendation will degrade to /cook for sub-threshold
specs.
Signals counted
Section titled “Signals counted”| Signal | Source in the spec |
|---|---|
goals |
Bullets under ## Goals |
quality_gates |
Bullets under ## Quality gates (also matches ## Acceptance criteria for legacy specs) — reported, not counted |
decisions |
Bullets under ## Decisions (reported but not used in the rule) |
candidate_curds = goals — only distinct behavioural goals drive the count.
quality_gates (acceptance criteria) and decisions are reported as signals
but deliberately excluded from the count: they are facets of one coherent
change, not independent file-disjoint curds. Counting acceptance criteria as
curds inflated the recommendation toward parallel fan-out for single coherent
refactors whose own criteria reference the same files (issue #111) — the more
thoroughly a spec was written, the more likely it mis-recommended fan-out.
Decision rule
Section titled “Decision rule”The script always recommends /cook for the (recommended) slot and names
the internal mode signal alongside it. --auto variants (/cook --auto,
etc.) are user-opt-in alternatives surfaced by the Handoff menu — the script
never recommends them, because “Never pre-select; auto mode is opt-in” is an
existing mold rule.
candidate_curds |
blast_radius |
recommended_skill (always /cook) |
mode |
|---|---|---|---|
≥ 2 (PARALLEL_THRESHOLD) |
any | /cook |
parallel |
| < 2 | high |
/cook |
linear |
| < 2 | medium, low, or unknown |
/cook |
null |
Digest shape
Section titled “Digest shape”{ "spec_path": "<resolver-owned durable spec path for <slug>>", "slug": "<slug>", "blast_radius": "high", "candidate_curds": 7, "signals": {"goals": 7, "quality_gates": 6, "decisions": 3}, "threshold": 2, "decomposable": true, "recommended_skill": "/cook", "mode": "parallel", "rationale": "7 candidate curds >= 2 threshold; parallel fan-out", "notes": [ "Count is a signal, not a verdict.", "candidate_curds = goals only; acceptance-criteria / quality-gate count does not drive it (issue #111).", "Confirm curd independence (criterion 4: file-disjoint) before /cook fans out in parallel waves." ]}Independence is the user’s call
Section titled “Independence is the user’s call”The script counts; it cannot verify that the candidate curds are file-disjoint
(criterion 4) from spec text alone. Before a parallel wave-plan runs, mold
confirms independence with the user — typically by naming the file footprints
captured in ## Interface sketches and asking whether any two candidate
curds touch the same file. If they do, the decomposer folds the shared-file
curds back into the linear chain; the dispatched skill is /cook either way.
When tilth / Python is unavailable
Section titled “When tilth / Python is unavailable”The script depends only on the Python 3 stdlib. If the host has no python3,
mold falls back to the pre-script Handoff: blast-radius alone recommends
/cook and signals a parallel or linear wave-plan (high blast radius signals
linear mode; low or medium recommends /cook with no mode) for the
(recommended) slot, and a parallel wave-plan appears in the option list
with a manual “if this spec decomposes into 2+ independent curds, the
decomposer will fan it out” tagline. /cook --auto stays where it always
lives — as a user-opt-in alternative in the non-decomposable low/medium menu,
never the recommended pick. Say the substitution out loud.
Curdle — artifact extraction
Section titled “Curdle — artifact extraction”Curdle is the terminal state of mold. It runs only after the two-key handshake (see handshake.md).
Artifact types
Section titled “Artifact types”Resolve the spec path with SPEC=$(python3 ${CLAUDE_SKILL_DIR}/scripts/mold.pyz artifact-path specs <slug>) — it anchors at the per-project durable corpus (see ../../cheese/references/formatting.md § Corpus location). Issues stay repo-local: write them as .cheese/issues/<slug>-NNN.md.
| Type | When | Path |
|---|---|---|
| Spec | Any meaningful design discussion | $SPEC (resolver output) |
| Spec + Issues | Accepted follow-ups whose disposition calls for local recovery or tracker payload | spec at $SPEC; issues at .cheese/issues/<slug>-001.md, -002.md, … |
| Issues only | Pure standalone bug tickets, no design | .cheese/issues/<slug>-001.md, … |
A spec is the rich container; absorbs problem framing, requirements, approach, decisions, interface sketches, risks, gates. An issue is a separate, GitHub-flavoured item the user can paste into a tracker.
Slug rules
Section titled “Slug rules”- Lowercase the working problem statement, drop stopwords, kebab-case, cap at 5 words.
- Honour user-passed slugs verbatim.
- Match the spec’s parent slug for issues (
<slug>-001.md,-002.md).
Collisions
Section titled “Collisions”| Existing | Action |
|---|---|
Same slug, status draft |
Overwrite (default) or rev (<slug>-v2) — ask if unsure |
Same slug, status approved |
Default to rev; never silently overwrite |
| Existing spec, new issues for same slug | Append issues to that slug’s series |
Spec template
Section titled “Spec template”Cross-cutting house style and citation form: formatting.md. This section owns the spec shape; formatting.md owns the voice rules and the footnote primitive.
---slug: <slug>status: draftcreated: <YYYY-MM-DD>confidence: <low | medium | high>gates_overridden: [] # list of unchecked handshake items if `curdle anyway` was usedagent_introduced_scope: [] # terms in the spec the user did not type — each approved per `handshake.md` § Agent-introduced scope (audit trail; downstream skills trust this list)entity_referent_bindings: [] # list of binding records {noun, verdict, referent, citation, note} for identity/ownership-role nouns bound to code referents or marked NEW ENTITY — each resolved per `handshake.md` § Entity-referent binding (audit trail; downstream skills trust this list)---
# <Title>
## Problem<one paragraph; what's broken or missing today, who feels it>
## Goals- <bullet>
## Non-goals- <bullet>
## Deferred follow-ups- **<deterministic follow-up ID>** — <summary> - Destination: <github_issue | roadmap_goal | local_draft> - State: <prepared | linked | created> - Reference: <local draft path | URL | durable roadmap reference>
## Approach<chosen option summary>
## Decisions- <one-line decision> — <one-line rationale>- _Minor decisions:_ <one line capturing the `[AGENT-DECIDED]` calls the user did not veto — the per-round ledger's minor tier; major decisions get full ADRs per `adr.md`>
## Acceptance
Write acceptance criteria in **EARS form** by default:WHEN
If the trigger cannot be stated precisely (e.g. pure internal utilities with no external event), use prose with a `[prose-fallback]` marker.
- WHEN <trigger> THE SYSTEM SHALL <response>- WHEN <trigger> THE SYSTEM SHALL <response>
## Interface sketches```pseudocode<signatures, schemas, seams>Open questions
Section titled “Open questions”- [TBD]
- [BLOCKED]
—
Quality gates
Section titled “Quality gates”:
Reproduction (Diagnose only)
Section titled “Reproduction (Diagnose only)”<failing test, curl, replay command, etc.>
References
Section titled “References”<one footnote definition per cited source; include only when out-of-scope evidence was cited above per ../../cheese/references/formatting.md § Citations>
### Issue template
```markdown---slug: <slug>-<NNN>status: openflavor: bug | chore | sliceparent_spec: <slug>---
# <One-line summary>
## Context<why this exists, in 1–3 sentences>
## Acceptance- <bullet — verifiable outcome>
## Notes- <optional caveat or pointer>Two-phase Curdle for accepted follow-ups
Section titled “Two-phase Curdle for accepted follow-ups”Accepted follow-ups use a local-first two-phase Curdle. Each receives a deterministic follow-up ID composed from the spec slug and its one-based ordinal, for example mold-follow-up-routing-F001.
Phase one — local write-ahead state
Section titled “Phase one — local write-ahead state”Preserve every existing Curdle by-product: the spec, ADRs, glossary, domain model, and any rejected-direction records. Add a local issue draft for each accepted follow-up that needs recoverable tracker payload, then persist its ID, destination, prepared state, and draft reference in Deferred follow-ups before any external call.
$SPEC is the authoritative store for prepared follow-up state because the resolver anchors it in the durable project corpus. Local issue drafts are auxiliary publication payloads, not the authoritative record. Stage and move this complete local set under the existing atomic-write rule before phase two begins.
Phase two — external publication and reconciliation
Section titled “Phase two — external publication and reconciliation”Only units whose approved action is create/link now and whose destination is external enter phase two. A local issue draft destination completes as prepared in phase one:
- For GitHub Issues, use the host GitHub capability first and
ghas the portable fallback. Discover repository labels and issue forms instead of assuming them. - For roadmap goals, run the owned
/wiki-roadmapworkflow when that skill and its required capability are available. New roadmap creation and extension remain owned by that workflow. - Put the deterministic follow-up ID in every published item. On every retry, search the exact deterministic follow-up ID before creation; when an exact match exists, link it and SHALL NOT create a duplicate.
- A reused external item becomes
linked; a newly published item becomescreated. Reconcile that state and the final URL or durable roadmap reference intoDeferred follow-ups. - When a capability is unavailable or publication fails, retain the recovery draft, keep the follow-up prepared, report the failed action and retry path, and continue without blocking the approved spec.
Finish roadmap publication and all mechanical spec reconciliation before the implementation handoff. Reconciliation records the already-approved result; it does not reopen the design.
ADRs (durable by-product)
Section titled “ADRs (durable by-product)”After both handshake keys pass, write the session’s non-obvious decisions as durable ADRs in phase one’s local atomic write with the durable spec. Both remain in the durable project corpus: the spec is the approved implementation contract, while ADRs preserve the rationale behind it. The corpus is resolved dynamically — probe for the consumer’s repo:<their-repo>:wiki hallouminate corpus and write there if present, else fall back to a tracked docs/adr/<slug>-NNN.md. Never hardcode a corpus name. Full resolution rule and ADR format in adr.md.
Durable glossary (by-product)
Section titled “Durable glossary (by-product)”Write resolved canonical terms to .cheese/glossary/<slug>.md in the same atomic step as the spec and ADRs. Downstream skills (/cook, /age, /press) read this file for naming consistency. The glossary is the output of the Ground phase’s term resolution; it is not reconstructed from the spec.
Format:
# Glossary — <slug>
| Term | Canonical meaning | Code referent (file:line or NEW ENTITY) | Avoid || --- | --- | --- | --- || <term> | <one-line definition> | <referent> | <losing synonym, …> |The Avoid column records the losing synonyms the Ground phase rejected in favour of the canonical term (comma-separated, or — when none). Omit the file if no terms were resolved during Ground (no overloaded-term dialogue occurred).
Domain model (cumulative by-product)
Section titled “Domain model (cumulative by-product)”In the same atomic step as the spec, ADRs, and per-slug glossary, merge the session’s resolved terms — with their Avoid synonyms — into the project-level domain model resolved via domain_model_target() (shared/scripts/paths.py). Unlike the per-slug glossary (a branch-local handoff), the domain model is cumulative cross-session memory: it builds the project’s ubiquitous language across every session. Context-specific terms only; general programming concepts never enter.
Merge, don’t overwrite:
- New term — append an entry.
- Changed term (definition, referent, or Avoid set differs) — update that entry in place.
Entry format:
**<Term>** — <definition>._Avoid_: <syn1>, <syn2>_Code_: <file:line (or NEW ENTITY)>Omit the _Avoid_ line when no synonyms were rejected.
Lazy context-map split. A single bounded context lives as one domain-model.md at the store root. When a second bounded context crystallises, split lazily into:
domain-model/index.md— the context map: the bounded contexts and their relationships (Pocock CONTEXT-MAP shape).domain-model/<context>.md— one page per bounded context, each holding that context’s entries.
Do not pre-split for a single context. This layout is identical across all three stores domain_model_target() may resolve to (wiki, docs/, XDG corpus).
Rejected-directions store (by-product)
Section titled “Rejected-directions store (by-product)”When the agent-introduced-scope audit or the two-key handshake explicitly rejects a direction (the user says “drop .cheese/.out-of-scope/<slug>-NNN.md. An explicit deferral becomes a follow-up candidate; a rejected direction is not a follow-up candidate.
Format:
# Rejected direction — <slug>-<NNN>
## Direction<one-line description of what was rejected>
## Rationale<why it was rejected, in 1–2 sentences>
## ContextSession: <slug>; rejected at: <handshake | scope-audit>This store is consulted by /cheese before re-proposing a direction (see skills/cheese/SKILL.md § Rejected-directions check). Do not write ordinary scope boundaries or accepted follow-ups here: non-goal-only dispositions create no artifact, while accepted follow-ups use Deferred follow-ups plus any auxiliary .cheese/issues/ recovery draft. Write only direction-level rejections (approaches, design knobs, named features the user explicitly declined). Note: this store is dot-prefixed (.out-of-scope) while its sibling stores (glossary/, issues/, specs/) are not — any scan must target the dotted path explicitly; a bare .cheese/* glob will not match it.
Spec-verify pass (optional)
Section titled “Spec-verify pass (optional)”Before the hand-off, if the /spec-verify skill is available in the harness, run it as an independent spec-review pass. If absent, skip silently and note once — this pass is optional and must not block curdle in environments where the skill is not bundled. Never hard-depend on it.
Detection is instruction-level, not code: check whether /spec-verify appears in the agent’s available toolset (the same pattern as ../../cheese/references/optional-plugins.md § Probe pattern). Do not use command -v or any shell probe — /spec-verify is a skill, not a $PATH executable.
Atomic write
Section titled “Atomic write”Stage to a temp directory under ${TMPDIR} first, then move into place. Never leave partial files on a write failure.
Write → read-back → completion record
Section titled “Write → read-back → completion record”This is the runtime home of the Durable writes coherence gate (handshake.md § Agent key). The gate locks the commitment before the handshake; this step honours it. For each durable write — every ADR and the domain-model merge — run:
- Resolve the target dynamically — the ADR resolution procedure in
adr.md§ Resolution, thedomain_model_target()function (shared/scripts/paths.py) for the model. Both yield(backend, location). - Write to that target:
add_markdownwhen the backend ishallouminate, a staged file write when it isfile. - Read back and confirm the entry landed:
ground/read_markdownfor the wiki backend, a re-read of the file for the file backend. A write that cannot be read back is a failure — fail loud, do not claim the write. - Record it in the curdle completion record printed to the user: one line per durable write naming
<artifact> → <location> (<backend>).
Loud fallback. When hallouminate is unavailable and the resolver degrades to a file backend (docs/adr/…, docs/domain-model*, or the XDG corpus), say so in one visible line — never let a write silently go to files when the author expected the wiki. Absent-plugin degrade contract: ../../cheese/references/optional-plugins.md.
Pre-approval decomposer dispatch (curd block)
Section titled “Pre-approval decomposer dispatch (curd block)”Run this procedure on dialogue-state draft text before the two-key handshake. It prepares approval input; Curdle later persists that exact approved input.
- Dispatch a fresh-context
decomposersub-agent on the current draft spec text (source: mold). Read../../cheese/references/decomposer.mdfor the locked curd-block schema first — do not invent the schema from memory. It returns a curd block. - Validate the returned block with
src/fanout/curd_block.py::validate_curd_block. On failure, retry the dispatch once. - Still invalid after the retry — stop before the two-key handshake. Do not approve or embed an invalid block: a broken decomposer output must never corrupt the spec.
- On success, count the block’s
curdsandwaves, then showN curds / M waveswith the final approval request. The validated block is part of what both handshake keys approve. - During Curdle phase one, persist the same approved curd block as
## Curdsafter## Quality gates(or the natural equivalent section for this spec’s shape). Do not re-dispatch, regenerate, or mutate it after approval.
The pre-approval dispatch produces dialogue state, not a durable artifact or external publication. The two-key handshake still gates every write, and the dispatch does not depend on any external publication capability.
Hand-off
Section titled “Hand-off”Do not render this hand-off until phase-two publication attempts and the mechanical Deferred follow-ups reconciliation are complete.
After writing, suggest the next step inline. Never auto-invoke.
| Artifact | Suggested next step |
|---|---|
| Spec | /cook <spec-path> |
| Issues | Paste each into your tracker, or gh issue create --body-file <path> |
Trigger and trace tests for /mold. Run these against real session transcripts when the skill changes.
Should-trigger queries
Section titled “Should-trigger queries”These prompts must invoke /mold (or its router parent /cheese must hand off to it):
- “grill the agent-decided items”
- “let’s design a rate limiter for the API”
- “I’m thinking about adding OAuth support”
- “what should the schema for the events table look like”
- “should we do the migration now or wait, thinking about downtime”
Should-not-trigger queries
Section titled “Should-not-trigger queries”These prompts must NOT invoke /mold:
- “fix the failing test in auth.ts” — direct implementation, route to
/cook. - “review this diff for bugs” — review-only, route to
/age. - “just thinking out loud, no need to write anything down” — no artifact intent, route to
/culture. - “what does the Stripe API say about idempotency keys” — external research, route to
/briesearch.
If a should-not query triggers /mold, the description in SKILL.md is over-broad — tighten it.
Trace checks
Section titled “Trace checks”For each completed /mold Grill-mode run, verify:
- Every grilled item produces a steelman + tension statement before any verdict. No item skips straight to an uphold/amend verdict without first surfacing the steelman.
- ≥1 user-fork round for a grill of
[AGENT-DECIDED]items. A grill that touches at least one agent-decided or design-changing item invokes the question primitive at least once (AskUserQuestionon Claude Code/Conductor, the equivalent perask-user-question.mdon other harnesses) — an actual user turn, never anA/B/C/Dblock the agent renders and answers itself, and never a self-issued verdict monologue with no user turn. - Amendments surface as questions before ledger entry. Any item whose grilling produces an amendment appears as a question to the user before the amendment is written to the per-round decision ledger.
- Clean-steelman batching stays scoped. Only items where the steelman finds nothing are batch-reported as upheld; an item with a live tension is never folded into a batch.
Failure modes to watch for
Section titled “Failure modes to watch for”- Verdict monologue — the agent steelmans every item, self-issues uphold/amend verdicts, and presents a finished verdict block with no user turn. This is the regression this eval exists to catch (see issue #279, and the Grill section in
skills/mold/references/modes.md). - Amendment silently folded into the ledger — an amendment appears in
Decidedwithout a prior question to the user. Log as a regression. - Over-batching — an item with a real tension gets swept into the “batch-reported as upheld” exception meant only for clean steelmans.
How to run
Section titled “How to run”These evals are intentionally manual today.
The gate graph
Section titled “The gate graph”Mold’s gate state machine has one canonical model: src/mold/gate-graph.py’s
GATE_MODEL (bundled into mold.pyz as the gate-graph subcommand). Both render
targets derive from that one model, so they cannot drift (ADR-001). The model
doubles as the gate-prose-sync source: a test asserts the handshake
coherence-checklist items equal the model’s gate nodes, so a gate cannot be
silently dropped from prose.
Subcommand
Section titled “Subcommand”python3 ${CLAUDE_SKILL_DIR}/scripts/mold.pyz gate-graph \ [--state <state.json>] [--render dot|svg|png|mermaid] [--out <path>]--render dot(default): canonical Graphviz.dotto stdout.--render mermaid: a fenced ```mermaid flowchart block to stdout — renders natively in GitHub and markdown viewers, no binary required.--render svg|png: shells out to Graphvizdotwhen it is on PATH; pass--out <path>for binary targets. Whendotis absent it degrades to mermaid and prints a note to stderr — run-anywhere by construction.--state: optional moldstate.json, validated for shape; the gate model itself is static, so state does not change the graph today.
When to use it
Section titled “When to use it”- Onboarding a contributor to mold’s flow — one picture of modes → gates → handshake → curdle.
- Auditing that the prose checklist and the enforced gates still agree (the gate-prose-sync test is the automated form; the rendered graph is the human form).
- Embedding the mermaid block in a doc or PR description where no Graphviz toolchain exists.
Why dual-render from one model
Section titled “Why dual-render from one model”Requiring Graphviz would break run-anywhere (it is absent on many machines,
including the dev box). Mermaid-only would lose the canonical .dot /
enforcement angle. Emitting both from one in-memory model keeps zero hard
dependency and keeps the two targets in lockstep — the no-drift guarantee is
structural, not a convention someone has to remember.
Snapshot
Section titled “Snapshot”skills/mold/scripts/mold.dot is the committed canonical .dot. A test asserts
it byte-matches to_dot(), so the snapshot can never go stale against the model.
Regenerate it whenever the model changes:
python3 ${CLAUDE_SKILL_DIR}/scripts/mold.pyz gate-graph --render dot \ --out ${CLAUDE_SKILL_DIR}/scripts/mold.dotThe non-goals gate
Section titled “The non-goals gate”One coherence gate is worth calling out on its own: non-goals-audit (rendered
non_goals_audit in the .dot; label Non-goals audit: every bullet traces to a
user-stated out-of-scope item or is marked [AGENT-INTRODUCED]). Like every gate
node it feeds the handshake and is kept in lockstep with the handshake.md
checklist. It makes the most consequential lean — narrowing scope via Non-goals
— a first-class, testable gate rather than a prose-only check (ADR-002). The
audit procedure lives in handshake.md § Non-goals audit.
Grounding — hallouminate wiki probe
Section titled “Grounding — hallouminate wiki probe”Throughout a /mold dialogue — at Ground phase entry and at decision points in any Dialogue mode (see § When to probe) — if hallouminate is available, probe the consumer’s wiki corpus before asking the user the next question. Fold any matching rationale or ADR entries into the evidence base. If hallouminate is absent, skip silently and continue with diff + code evidence only.
Probe shape
Section titled “Probe shape”Mirrors the wiki probe pattern from the detect-and-degrade contract in ../../cheese/references/optional-plugins.md:
ground_wiki(topic): # 1. Check hallouminate availability. if "mcp__hallouminate__list_corpora" not in available_tools: note once: "OPTIONAL MCP ABSENT: hallouminate not loaded. Falling back to diff + code evidence only." return []
# 2. Find the consumer's wiki corpus (dynamic; their repo, not ours). corpora = mcp__hallouminate__list_corpora() wiki = first(c for c in corpora if c.startswith("repo:") and c.endswith(":wiki")) if not wiki: return [] # no wiki configured; skip silently
# 3. Ground the topic. results = mcp__hallouminate__ground(query=topic, corpus=wiki, limit=5) return results- The corpus name comes from
list_corpora, never a literal string — that is the portability invariant (the consumer’s repo, not easy-cheese’s). - If
list_corporais unreachable or returns no wiki corpus, fall back silently. Never block the dialogue on the probe. - State the absence once per run if the tool is missing; do not repeat on every question.
When to probe
Section titled “When to probe”Probe at Ground phase entry and, in the other Modes (Shape/Sketch/Grill), at any decision point — before generating the next question — when any of these are true:
- The dialogue is about to decide a consequential fork whose options could have prior rationale (e.g. “why not X”).
- The next question to the user is one the wiki may already answer (a settled decision, an ADR, a recorded convention).
- The dialogue is about to restate rationale for an existing system or module that may have ADRs.
- The spec being molded overlaps with a prior mold session in this repo.
Skip the probe for pure Explore mode (no named system) and for Diagnose mode (evidence comes from code/logs, not rationale docs).
Cite hits in that round’s decision ledger (Decided / Asking / [AGENT-DECIDED] — see ../SKILL.md § Rules): a settled decision found in the wiki lands under Decided with its wiki page cited, not reopened as a fresh question.
Confidence when absent
Section titled “Confidence when absent”If hallouminate is absent and design rationale is central to the question at hand, cap at speculating and note it inline. See ../../cheese/references/optional-plugins.md for the full degrade contract.
Handoff branch menus
Section titled “Handoff branch menus”Read this when rendering /mold’s post-Curdle handoff menu (SKILL.md § Handoff) — the exact wording for each of the three blast-radius branches, and how the digest’s mode signal picks among them.
Decomposable specs (decomposable: true, candidate_curds ≥ 2, mode: parallel):
The approved spec already contains file-disjoint candidate curds validated before the handshake. /cook is the dispatched skill either way: its curd-block gate routes 2+ file-disjoint curds to parallel mode and folds a single curd into the linear chain, so the approved plan informs execution without changing the command.
- Run the full pipeline (parallel fan-out when disjoint, else linear) (recommended) —
/cook --auto <spec-path>. The decomposer picks parallel curd fan-out or the linear chain;/plateperforms the final artifact-writing gate, resolves topology from the explicit choice and review shape, and publishes the ordinary or stacked layout. - Implement manually, one phase at a time —
/cook <spec-path>. - Stop — dispatch none; leave the spec for later.
Non-decomposable, high-blast-radius specs (decomposable: false, verdict high only, mode: linear):
The spec is large enough that per-phase context contamination becomes a real concern: review reasoning softens when the same window contains the cook reasoning, and the parent context bloats across phases. Offer fresh-context isolation and the manual compaction path:
- Run the full pipeline in fresh-context isolation (recommended) —
/cook --auto <spec-path>, autonomous chain (cook → press → age → cure → age → cure → age, all--auto) with each phase running inside its own sub-agent, blind to prior phases. - Implement manually, one phase at a time —
/cook <spec-path>. - Compact and resume by hand — dispatch none; clear context, then dispatch
/cook <spec-path>directly. (/cheese --continuescans phase handoff slugs only — fresh specs don’t surface there until cook lands a slug — so dispatching the explicit command is the resumption path here.) - Stop — dispatch none; leave the spec for later.
Non-decomposable, low- or medium-blast-radius specs (decomposable: false, verdict low or medium, mode: null):
- Implement the spec (recommended) —
/cook <spec-path>. - Implement and auto-review —
/cook --auto <spec-path>, chains through/press → /age → /cure. Opening or updating a PR remains a/platestep; a new PR follows its explicit-choice and review-shape policy. - Research more first —
/briesearch, gather more external evidence before implementing. - Stop — dispatch none; leave the spec for later.
The internal mode signal is what distinguishes the branches above, never the offered command: mode: parallel or mode: linear means the spec crosses enough curds or module boundaries that the fresh-context, fully-autonomous /cook --auto chain is the recommended pick (the decomposable and high-blast-radius branches); mode: null means the footprint stays small enough that plain /cook is the recommended pick and /cook --auto remains a user-opt-in alternative (the low/medium branch). The no-pre-select-autonomous rule stated in SKILL.md still applies — the user opts into --auto, it is never the only path offered.
The two-key handshake
Section titled “The two-key handshake”Curdle (artifact extraction) requires both keys. Neither is optional.
User key
Section titled “User key”The user must express explicit extraction intent: curdle, ship it, extract, or that's enough. A clear affirmative such as ok let's go, sounds good, or go ahead also turns the key when it directly answers an agent’s extraction question.
Do not infer the key from unrelated or ambiguous approval; ask explicitly when the context does not establish that the user is approving Curdle.
Agent key — coherence self-check
Section titled “Agent key — coherence self-check”Print this checklist and require every box checked before extraction (or an explicit curdle anyway override):
Coherence self-check before curdle:- [ ] Problem statement: grounded, agreed- [ ] At least 2 options weighed (Do Nothing included)- [ ] Chosen option grounded in codebase evidence- [ ] Interface sketches: every public seam has a pseudocode signature- [ ] Cross-module calls go through public interfaces, not internals- [ ] Identity nouns: each bound to a code referent or marked NEW ENTITY (an ALIAS must be resolved, not just noted)- [ ] Non-goals audit: every bullet traces to a user-stated out-of-scope item or is marked [AGENT-INTRODUCED]- [ ] Validate cycles: all launched cycles judged- [ ] Chosen option Grilled (≥1 stress-test entry per major branch)- [ ] Open questions all marked [TBD] / [BLOCKED] / [?] (none silent)- [ ] Quality gates specified (≥1 runnable command)- [ ] Reproduction loop captured if Diagnose ran (or [BLOCKED] if no loop is possible)- [ ] Durable writes: ADR + domain-model targets resolved and the write, read-back, and completion-record protocol committed for the atomic step (or loud fallback noted)If any box is unchecked, name it and propose the smallest move to fill it. The user can override with curdle anyway.
The last box — Durable writes — is a commitment checked before the handshake, not a claim the write already happened: it asserts the ADR + domain-model targets are resolved and the write → read-back → completion-record protocol is locked in for the atomic-write step (curdle.md § Atomic write). The read-back verify and the visible completion record fire during that step, and the hallouminate-absent fallback is noted loud, never silent.
These thirteen checklist items are the gates in mold’s machine-readable gate model
(gate-graph.md). A test asserts the checklist items here equal the
model’s gate nodes, so a gate cannot be silently dropped from this prose — edit
the two together. Render the flow with mold.pyz gate-graph.
Mandatory gates
Section titled “Mandatory gates”These are not soft suggestions — Curdle hard-blocks until they are addressed:
- Ground gate: ≥1 Ground pass with a citation before Shape’s options. Exception: pure greenfield (the agent must say so out loud).
- Shape gate: ≥1 Option block weighed (Do Nothing counts).
- Sketch gate: mandatory when the chosen option touches more than one module or introduces a new public interface. Skip only for trivial single-function changes (the agent must say so out loud).
- Grill gate: mandatory for high-blast-radius decisions. The shape check (
shape-check.md) ranks blast radiuslow | medium | highfrom semantic caller search andtilth_depswhen available. Ahighverdict — multi-module callers or more than five importers — makes Grill mandatory. - Open hypotheses: any Validate Cycle launched but unjudged blocks Curdle unless the user accepts it as
[TBD]. - Agent-introduced scope: every distinguishing noun in the spec must trace to a user-typed mention or get per-term approval. Full procedure in § Agent-introduced scope below — Curdle is the single chokepoint, since downstream skills trust the resulting frontmatter and do not re-block.
- Entity-referent binding: every identity noun binds to a code referent or is marked NEW ENTITY; an ALIAS must be resolved, not just noted. Full procedure in § Entity-referent binding below.
- Non-goals audit: every
Non-goalsbullet traces to a user-stated out-of-scope item or is marked[AGENT-INTRODUCED]. Full procedure in § Non-goals audit below.
These audits — agent-introduced scope, entity-referent binding, and the non-goals audit (below) — fire inline, per dialogue round, not only terminally at Curdle: each runs the moment new scope is proposed and is surfaced in that round’s decision ledger, so a lean is caught when it happens rather than reverse-engineered at the end. Curdle re-runs all three as the terminal backstop and stays the single chokepoint downstream skills trust (RC3).
Agent-introduced scope
Section titled “Agent-introduced scope”Before curdle, audit the draft spec for features the user did not type the name of.
Procedure:
-
Extract distinguishing nouns from the spec’s
Approach,Decisions, andInterface sketchesblocks — proper-noun-ish terms, library names, algorithm names, Greek letters used as parameters, config keys, knobs. -
For each noun, grep the prior user turns of the conversation (the user’s typed messages, not the agent’s or sub-agents’ output) for a literal mention.
-
Any noun with zero hits is agent-introduced. Mark it
[AGENT-INTRODUCED]inline in the draft and present a short table:Agent-introduced scope check:| Term | First introduced by | Where in spec || --- | --- | --- || <noun> | <agent/sub-agent/citation> | <section> | -
The user must explicitly approve each row before the handshake fires. Acceptable approvals: “yes keep
”, “drop ”, “make a follow-up”. Vague “looks good” is not approval. “Make a follow-up” records a candidate for the disposition batch; it does not immediately create an issue or other artifact. -
When the user explicitly drops a direction — an approach, design knob, or named feature they decline — write a rejection record to
.cheese/.out-of-scope/<slug>-NNN.md(format incurdle.md§ Rejected-directions store). A rejected direction is not a follow-up candidate. Explicit deferrals enter the follow-up candidate set instead. -
If any flagged term came from a research citation (briesearch sub-agent, fetched doc, MCP result), it cannot be silently promoted into a design knob — the citation is evidence, not a mandate. See
skills/briesearch/references/synthesis.md§ Alternatives are open questions.
This gate exists because research sub-agents have historically over-synthesised: a Tavily snippet mentioning “X or Y” became a shipped [setting].knob = "x" | "y" flag, copied through curdle → cook without the user typing the distinguishing noun once. The grep heuristic catches that class of drift early.
Curdle is the single chokepoint for this gate. Downstream skills (/cook, etc.) trust the spec frontmatter and do not re-block — record approved-but-flagged terms in spec frontmatter as agent_introduced_scope: [<term>, …] so the paper trail survives.
Non-goals audit
Section titled “Non-goals audit”Non-goals narrows scope — it removes work the user may have wanted without ever asking. That makes it the single most consequential lean, and the existing drift gates never audited it (they read only Approach / Decisions / Interface sketches). This gate guards it, as a sibling of Agent-introduced scope.
Procedure:
- For each
Non-goalsbullet, grep the prior user turns (the user’s typed messages) for the user putting that item out of scope — a “don’t bother with X”, “leave Y alone”, an explicit deferral. - Any bullet with no such user statement is agent-introduced. Mark it
[AGENT-INTRODUCED]inline and present it for decision — the user must explicitly keep, drop, or reword it. A vague “looks good” is not approval. - Record approved-but-flagged non-goals in the same
agent_introduced_scopefrontmatter list, so the paper trail survives downstream. - Add every audited non-goal to the follow-up candidate set, including approved
[AGENT-INTRODUCED]bullets. Candidate status preserves the scope boundary without accepting future work.
This audit is the Non-goals audit coherence gate — the non_goals_audit node in the gate model (gate-graph.md). It fires inline per round as non-goals are proposed and again at Curdle as the terminal backstop, which hard-blocks extraction until every bullet traces to the user or is approved [AGENT-INTRODUCED].
Follow-up disposition (inside the non-goals audit)
Section titled “Follow-up disposition (inside the non-goals audit)”Before the two-key handshake can pass, dispose of every follow-up candidate in one batch. This extends the existing Non-goals audit gate; it does not add or rename a gate.
- Group related candidates into independently deliverable units. Propose grouping or splitting rather than assuming it, and obtain user approval.
- When discovery is available, search GitHub Issues and hallouminate roadmap goals for related work. Present each semantic match as a possible reuse, never as an equivalence; the user approves any reuse.
- Recommend one destination per unit:
- non-goal only — retain the scope boundary and create no follow-up artifact;
- GitHub Issue — discrete, independently actionable work;
- roadmap goal — coordinated, milestone-scale, or dependency-linked work;
- local issue draft — publication is not desired or available.
- The user approves the destination. For every accepted destination except non-goal only, ask the user to choose the action: create/link now or leave prepared. A non-goal-only unit has no action choice.
- Record accepted units for Curdle. Rejected design directions stay in the rejected-directions store and do not enter this batch.
The user approves grouping, splitting, semantic-match reuse, destination, and any applicable action; Mold settles none silently. When no candidates exist, omit the disposition batch and preserve the current handshake and Curdle flow.
Record each candidate within Decided as [FOLLOW-UP?] with its summary, source, and rationale. A follow-up candidate is dialogue state only — collecting one does not create an artifact or future commitment. After both keys pass, Curdle writes local artifacts first (including the same approved curd block), publishes approved follow-ups, and reconciles their state and references into the durable spec, and only then renders the implementation handoff.
Entity-referent binding
Section titled “Entity-referent binding”Before curdle, audit the draft for identity/ownership-role nouns — any noun the design treats as holding, owning, spanning, or claiming state or lifecycle (owner, run, session, claim-holder, coordinator, worker, lease, tenant, lock-holder, …). The trigger is the role, not a fixed word list: domain-specific identities are caught and plain value nouns (formats, algorithms, config knobs) are not flagged.
The mechanism is semantic symbol search, one query per identity noun, following the shared routing contract. The gate is not “did search find something” — it is a three-way verdict on what search returns:
| Search outcome | Verdict | Action |
|---|---|---|
| Symbol whose shape matches the design’s assumed role | Bound | record code referent + file:line citation |
| Symbol of a different shape/referent (aliasing) | ALIAS | state the divergence; resolve by renaming to the real entity or designing the intended one |
| No symbol | NEW ENTITY | add a spec section designing it |
Procedure:
-
Extract identity/ownership-role nouns from the spec’s
Approach,Decisions, andInterface sketchesblocks. -
Search each noun and classify it
Bound/ALIAS/NEW ENTITYper the table above. -
Present the binding table inline in the draft — one row per identity-role noun:
Entity-referent binding check:| design noun | code referent | citation | divergence note || --- | --- | --- | --- || run | ALIAS — make_run_id (one dispatch) | — | code `run` is one dispatch, not a session; design assumed a session spanning siblings (a search *hit* of the wrong shape) — state the divergence, rebind to the real entity || session | NEW ENTITY | — | no symbol; the coordinator session the design needs must be designed | -
An unresolved binding hard-blocks curdle, exactly as an unapproved
[AGENT-INTRODUCED]noun does. A search hit is not resolution: if the design’s usage diverges from the code’s existing meaning of the same word, the aliasing must be stated and settled before extraction.
This gate is the referent-level sibling of Agent-introduced scope — that gate asks did the user type this noun, this one asks does the code have it, with the assumed shape. A fully handshook spec once declared its goal-claims “owned by the run/session” while the code’s run was a single task dispatch, not a coordinator session; the aliased noun survived to a re-age blocker and a cure-pass-2 design decision that belonged in mold. Curdle is the single chokepoint; downstream skills (/cook, etc.) trust the spec frontmatter and do not re-block — record bound and flagged nouns in frontmatter as entity_referent_bindings: [{noun, verdict, referent, citation, note}, …] (a list of binding records) so the referent and file:line citation the trail promises actually survive.
Override semantics
Section titled “Override semantics”curdle anyway overrides the agent key for one extraction. It does not disable future gates. The agent records the override and the unchecked items in the spec frontmatter so the human reviewer can see them. curdle anyway does not waive the Agent-introduced-scope gate — each flagged term still needs explicit per-term approval, since silent inclusion is the failure mode the gate exists to catch, and downstream skills will not re-check. The same holds for the Entity-referent gate: an unbound or aliased identity noun still blocks extraction under curdle anyway, since downstream skills trust the frontmatter bindings and do not re-derive them.
Why both keys
Section titled “Why both keys”The user knows their intent; the agent knows the dialogue’s coherence. Either one alone produces drift — user-only writes incoherent specs; agent-only writes specs the user didn’t actually want.
Agent-invoked mini-spec mode — full procedure
Section titled “Agent-invoked mini-spec mode — full procedure”Read this when /mold is invoked in agent-invoked mini-spec mode (tier-1 escalation from /cheese, per SKILL.md § Agent-invoked mini-spec mode) — the full procedure, the mini-spec schema, and the ## Provenance rules.
- Derive slug from the user’s ask (kebab-case noun-phrase, ≤ 4 words).
- Write the resolver-owned
<spec-path>with the mini-spec schema below. Resolve it viapython3 shared/scripts/artifact_path.py specs <slug>; if you’re on a host that only exposes the packaged helper,python3 skills/mold/scripts/mold.pyz artifact-path specs <slug>is the fallback. Never hardcode a repo-local spec path: the resolver anchors it at the durable corpus, matching the Curdle step. - Return the resolved spec path to
/cheeseso it can dispatch/cook --auto <spec-path>(the full path printed by the resolver, not a bare<slug>).
The two-key handshake does not fire in this mode. The agent-introduced-scope check still runs implicitly: every distinguishing noun in the mini-spec must come from the user’s input or from the tier-2 /culture / /briesearch synthesis recorded in ## Provenance. Anything else is a silent agent addition and is forbidden — the mini-spec records only what the user asked for, not what the agent thinks they might have meant.
Mini-spec schema
Section titled “Mini-spec schema”---slug: <kebab-slug>source: agent-mini-specintent: <one-sentence restatement of the user's ask>blast_radius: low | medium | highinputs: <one-line>outputs: <one-line>verification: <one-line: the obvious check>---
## Contract<one paragraph: behaviour change, scope boundary>
## Acceptance- <verifiable check 1>- <verifiable check 2>
## Non-goals- <what we are NOT changing>
## Provenance (tier 2 only)- culture: <one-line synthesis of what /culture concluded>- briesearch: <one-line synthesis>; artifact: research/<slug>/<slug>.mdsource: agent-mini-spec is the marker that downstream skills (/cook, /age, etc.) can read if they ever want different taste-test stringency for agent-written vs handshake-approved specs. They are not required to act on it today. User-invoked-ceremony specs omit source: or use source: mold-handshake.
## Provenance appears only when /cheese reached tier 2 before falling into tier 1 — i.e., when /culture or /briesearch contributed context the original input lacked. Omit the section when tier 1 fires on the raw input. When /briesearch ran, the artifact: field links the durable cited research at research/<slug>/<slug>.md so the citations are preserved and /cook (or any later skill) can re-read them without re-researching. Omit artifact: only when /briesearch answered from local code patterns alone and wrote no durable file.
The six modes of mold
Section titled “The six modes of mold”Mold has no fixed entry point. Inspect the input shape and pick a starting mode. Announce the mode in one line. Low-confidence classifications default to Explore.
Routing — input shape to starting mode
Section titled “Routing — input shape to starting mode”| Input shape | Start mode | Heuristic |
|---|---|---|
| Stack trace, “X is broken/slow/flaky” | Diagnose | error markers, file:line refs, symptom verbs |
File path, PR ref, existing spec in the durable spec corpus (resolver-owned; see SKILL.md Curdle) |
Ground | concrete artifact exists; read it first |
| Half-baked design doc with signatures or schemas | Sketch | already has interfaces; refine them |
| “I want to add X” with concrete nouns | Bounds pass → Shape | run the bounds pass first (edges → goals/non-goals), then jump to options |
| “Should we do X? thinking about Y” | Bounds pass → Grill | bounds pass first, then stress-test the tentative plan |
| Vague noun, half-sentence, “thinking about” | Explore | no grounded artifact, no chosen direction |
Front-loaded bounds pass. Every row above selects a secondary mode. Regardless of input shape, mold opens with the mandatory bounds pass (SKILL.md Flow step 1 — an Explore-style edges → goals/non-goals round plus the per-round decision ledger) before this table’s mode runs. The concrete-ask rows (“I want to add X”, “Should we do X”) therefore no longer skip straight past asking: the bounds pass fires first, then Shape/Grill takes the refined scope.
Mode definitions
Section titled “Mode definitions”Explore — intent extraction
Section titled “Explore — intent extraction”Job: collapse ambiguity with high-leverage questions. Borrow the Job-To-Be-Done frame: Why Now, What This Unlocks, Who Has The Pain, Do Nothing. Use lettered options to compress decisions.
Exit when: a problem statement plus one concrete pain point is articulated.
Ground — anti-hallucination
Section titled “Ground — anti-hallucination”Job: anchor every claim to evidence — code, docs, prior research. When the user uses overloaded terms (“account”, “session”, “user”), pause and resolve with a canonical-term question. Terms resolved here are written to the session’s durable glossary at .cheese/glossary/<slug>.md at the curdle atomic step (see curdle.md § Durable glossary), so downstream skills (/cook, /age, /press) can read them for naming consistency.
On Ground entry: resolve and load the project’s cumulative domain model via domain_model_target() (shared/scripts/paths.py) — the read-probe cascade (consumer wiki, shape-matched via list_corpora and confirmed via wiki_has_model → tracked docs/domain-model* → <project_corpus_root()>/domain-model*), checked in full before any write: a wiki corpus that is merely listed does not win on its own — an existing file-store model wins over a wiki corpus with no confirmed model. It mirrors the adr_target() resolution pattern (adr.md § Resolution): dynamic, existing model always wins, and if the probe is unreachable degrade to “not loaded” and say so — never block Ground on it. The model is cross-session memory; the per-slug glossary is the branch-local handoff. When a user term conflicts with an existing model entry, challenge immediately (“the model defines X as …, you seem to mean Y — which is it?”). Challenges are LIVE here; writes to the model are deferred to the approval gate — curdle owns the write (see curdle.md), never inline during Ground.
Invariant: never say “I think the code does X” without semantic source-code evidence gathered according to the shared routing contract.
Exit when: every critical claim has a citation.
Shape — option generation
Section titled “Shape — option generation”Job: turn a grounded problem into 2+ candidate approaches with trade-offs. Always include Do Nothing. Present them as lettered options (A/B/C/D) for the user to pick — a consequential fork is theirs to choose, not yours to settle; give a one-line rationale per option, not a verdict. Validate Cycle any critical assumption behind an option. Score options by the information they leave behind: prefer the one that reduces what the next maintainer must know, or makes what they must know more obvious.
Exit when: an option is picked (→ Sketch) or none survive (→ Explore).
Sketch — interface lockdown
Section titled “Sketch — interface lockdown”Job: lock modules, responsibilities, I/O contracts, and seams in pseudocode signatures. Before drafting, when the change touches more than one module or introduces a new public interface, run the shape check (shape-check.md) — signatures, semantic caller search, and dependency blast radius — on the touched symbols so new seams fit existing convention and the impact is bounded. Print the shape-check summary block before any pseudocode. Single-module, internals-only sketches may skip the gate; note “shape check skipped: single-module change” instead.
Acceptance notation (EARS): for every public seam, emit acceptance criteria in EARS form: WHEN <trigger> THE SYSTEM SHALL <response>. If the trigger cannot be stated precisely (e.g. pure internal utilities), fall back to prose with a [prose-fallback] marker.
Concrete-seam rule: when a seam is small enough to write completely (a function body that fits in roughly 20 lines), write the full implementation rather than pseudocode. Reserve abbreviated signatures only for seams where the body is genuinely too large or depends on design unknowns not yet resolved in the dialogue.
Exit when: every public seam has a pseudocode signature or full implementation per the concrete-seam rule; every acceptance criterion is in EARS form (or marked [prose-fallback]); every cross-module call goes through public interfaces, not internals; shape-check verdict is recorded (or explicitly skipped per the gate above).
Grill — adversarial clarification
Section titled “Grill — adversarial clarification”Job: stress-test the chosen approach plus sketched interfaces. One grilled item per turn (the clean-steelman batch below is the only exception): each grilled item (any [AGENT-DECIDED] item or design decision) produces at most a steelman + tension statement, then a user fork — uphold / amend-as-proposed / user’s own call — put to the user by actually invoking the question primitive per ../../cheese/references/ask-user-question.md (a real user turn, not an A/B/C/D block rendered in prose and then self-answered); verdicts are never self-issued for items that change the design. Items where the steelman fails cleanly (grilling finds nothing) MAY be batch-reported as upheld; any item whose grilling produces an amendment MUST surface as a question — through the same primitive — before the amendment enters the ledger. Traverse decision branches and contract corners. Pause for a Validate Cycle when an unverified assumption surfaces.
Exit when: every branch and contract corner is touched and agent confidence ≥ user confidence.
Diagnose — symptom inputs
Section titled “Diagnose — symptom inputs”Job: entry mode for stack traces and “X is broken”. Phases:
Build a Loop → Reproduce → Hypothesize (3–5 ranked, falsifiable) → Confirm root cause.
Phase 0 (Build a Loop) is the core discipline — agree on a fast, deterministic, falsifiable feedback technique (failing test, curl/CLI script, headless browser, replay, bisection harness, differential loop) BEFORE chasing hypotheses. The chosen loop becomes the Reproduction block in the bug-shaped spec, so /cook can verify the fix against the same signal.
Diagnose is diagnostic-only — hand off to Shape (“what’s the fix?”) then Curdle emits a bug-shaped spec.
User knobs (free-form interrupts)
Section titled “User knobs (free-form interrupts)”explore, ground, shape, sketch, grill, diagnose, validate <hypothesis>, prototype <question>, curdle, pause, enough. Honour these immediately.
prototype <question> launches a Prototype Cycle (prototype-cycle.md): a
throwaway built in a hermetic sub-agent worktree to settle an ungrillable design
unknown, returning only the answer as a digest. The code is discarded; the answer
is the keeper.
Uncertainty markers
Section titled “Uncertainty markers”| Marker | Meaning |
|---|---|
[?] |
Agent uncertain; needs validation |
[TBD] |
User uncertain; decision deferred |
[BLOCKED] |
External dependency unresolved |
[CONFLICT <id>] |
Codebase contradicts a stated assumption |
The Prototype Cycle
Section titled “The Prototype Cycle”An escape hatch for design questions that can’t be settled by reasoning, search, or doc-reading — only by trying it. Spawnable at any point in the dialogue, in parallel with a Validate Cycle. Mold owns the parent dialogue; the sub-agent owns the throwaway. The code is discarded; the answer is the keeper.
Use it when a question is ungrillable: an API’s real behaviour, whether two libraries compose, the actual shape of an error, an ergonomics call that only a running sketch can answer. Do not use it for questions a semantic source search, bounded source read, or Validate Cycle already settles — those are cheaper. Follow the shared routing contract for source-code evidence.
The frame
Section titled “The frame”Always announce the cycle before dispatching — the announcement is the discipline.
Launching a prototype cycle on question: "<ungrillable design unknown>"
Plan: spawn sub-agent(isolation: "worktree") # degrade to a temp dir if the repo is not git build a throwaway (may try several variations) digest ← { question, answer, snippet?, confidence } # <=2 KB; no code dumped discard the worktree # the answer is the keeper, never the code log state.prototype_cycles[] ; optionally emit an ADR (adr.md)1 cycle == 1 design question resolved, not 1 per variation. The sub-agent may try several throwaways internally; that is still one cycle.
What the sub-agent returns
Section titled “What the sub-agent returns”A digest, never a code dump (sub-agent split + digest size live in the shared
kernel at ../../age/references/sub-agent-gate.md):
| Field | Content |
|---|---|
question |
the design unknown, restated |
answer |
the resolved behaviour, in one or two sentences |
snippet? |
the minimal decision-encoding fragment, only if it captures the answer better than prose |
confidence |
certain | speculating | don't know |
The worktree is discarded after the digest is extracted. Nothing from the
throwaway tree is committed, copied back, or referenced by path — if a fragment
matters, it lives in the digest snippet.
Isolation and degrade
Section titled “Isolation and degrade”- Default:
isolation: "worktree"— a hermetic git worktree, auto-cleaned. - The repo is not a git repo: degrade to a temp directory under
${TMPDIR}, say so out loud, and clean it up after extraction. - Harness lacks sub-agent spawning: run the throwaway inline in a scratch dir, note the loss of isolation, and still discard it.
Budget
Section titled “Budget”Prototype cycles are context-bounded, not capped (ADR-003). Run as many as
confidence needs; the 120k/140k context-budget mechanic
(context-budget.md) is the natural limiter. A soft backstop of 10
prompts a single “still gathering — continue?” check; it is not a hard stop and
the user can wave it through.
Logging
Section titled “Logging”Every launched cycle is logged in the mold state file:
prototype_cycles: - id: pc-1 question: "Does library X's streaming API surface backpressure?" answer: "Yes — it yields when the consumer is slow; no manual pause needed." confidence: certain adr: ADR-002 # optional, when the answer encodes a non-obvious decisionAn open cycle (no answer:) blocks Curdle until it settles or the user accepts
it as [TBD], exactly like a Validate Cycle.
The shape check
Section titled “The shape check”Run this before drafting in Sketch mode, and any time the discussion in any mode hinges on “what does this touch” or “what depends on this”. The check is read-only — culture and mold both run it; only the artifact stage differs.
What it answers
Section titled “What it answers”- Signatures: what does the touched function/type look like today? What sibling signatures already exist in the same module so a new one fits convention?
- Callers (upstream): who calls the touched symbol, and from which modules?
- Callees (downstream): what does the touched symbol call into? Surfaced by the same symbol query —
kind: "symbol"returns a── calls ──footer with one-hop callees. No extra call. - Imports / blast radius: which files import this module? Which does this module import?
These four answers together describe the shape of the change and bound its blast radius — both upstream (who breaks if I change this) and downstream (what could I drag into the change). The downstream half is what InlineCoder-style bidirectional inlining is empirically worth on repo-level edits; ignoring it leaves a known gap.
Procedure
Section titled “Procedure”Run all three. Cheap when the answers are small; the cost of skipping is silent misrouting later.
| Question | Backend capability | Call |
|---|---|---|
Current signature? Sibling signatures? Downstream callees (── calls ── footer)? |
semantic symbol search | tilth_search(queries: [{query: "<symbol>", kind: "symbol"}], expand: 2, scope: "<module>") |
| Who calls this? (upstream) | semantic caller search | tilth_search(queries: [{query: "<symbol>", kind: "callers"}]) |
| What’s the import / blast radius? | dependency search | tilth_deps(path: "<file>") |
The first call does double duty — its ── calls ── footer is the cheap callee read; do not issue a separate query for it.
For multi-symbol changes, batch up to five symbols in a single semantic search call (query: "a, b, c"). Re-run only when a new symbol enters scope. Follow the shared routing contract.
Output expected before exit
Section titled “Output expected before exit”A summary at the top of the Sketch turn (or culture’s blast-radius step):
Shape check on <symbol(s)>: signature(s): <one line per touched seam> callers: <count> sites in <N> non-test files (paths) callees: <count> one-hop calls (names) — omit line if empty blast radius: imported by <count> files; imports <count> modules verdict: low | medium | highThe callees line is optional — print it only when the symbol query’s ── calls ── footer is non-empty. A leaf function with no callees should drop the line, not print 0.
A high verdict (multi-module callers or more than five importers) makes the Grill gate mandatory in mold (see handshake.md) and forces culture to label the option [high blast radius] before continuing trade-off talk.
When semantic source tooling is unavailable
Section titled “When semantic source tooling is unavailable”Shape-check should not block the dialogue when its preferred tools are missing. Substitute where a sanctioned alternative exists; for shape-check specifically, do not substitute textual search — grep / rg over a symbol name produces a count of string occurrences, not callers or importers, and a guessed blast-radius verdict is worse than an unknown.
- Callers / callees: fall back to LSP
textDocument/references/textDocument/prepareCallHierarchywhen a language server is reachable. Note the substitution out loud. - Imports / blast radius: no LSP equivalent. Skip the count, mark the line
unknown, and lean on the verdict downgrade below. - Verdict: cap at
[?]instead oflow | medium | high— a guessed verdict is worse than an honest unknown. Sketch and culture should treat[?]likehighfor gating purposes (Grill gate engages, option labelled[high blast radius]) until the user accepts the gap.
If both tilth and LSP are unavailable, say so once and proceed with [?]. Do not silently substitute a textual search for the shape-check itself.
When to skip
Section titled “When to skip”- The touched symbol has zero callers (greenfield) — say so out loud.
- The change is contained to one private function inside a single file with no exports — sibling signature lookup still applies; deps and callers can be skipped.
- The user explicitly said
skip the shape check.
Trade-offs and seams discussed without a shape check rely on the agent’s guess at impact. The check converts that guess into numbers — caller count, callee count, importer count — the user can argue with.
The directionality matters: upstream (callers) tells you who breaks if the seam changes; downstream (callees) tells you what the change might drag in. Bidirectional structural context is empirically worth a measurable accuracy lift on repo-level edits, and the downstream half rides for free on the existing symbol query.
The Validate Cycle
Section titled “The Validate Cycle”Any mode can invoke a Validate Cycle. Always announce the cycle before dispatching — the announcement is part of the discipline.
The frame
Section titled “The frame”Launching a validate cycle on hypothesis: "<single declarative sentence>"
Plan: /briesearch — fetch evidence Judge — support, contradict, or refine? Settle — accept, revise, or reject. Continue from current mode.A bare /briesearch call without this frame is discouraged. The frame forces commitment to a hypothesis plus a judgment step.
Outcomes
Section titled “Outcomes”| Outcome | Meaning | Next action |
|---|---|---|
| SUPPORTED | Evidence aligns with the hypothesis | Promote to a decision |
| CONTRADICTED | Evidence disagrees | Mark [CONFLICT <id>], revise or abandon |
| REFINED | Evidence partially aligns | Restate with new precision and re-validate or accept |
Diagnose’s parallel hypothesis ranking IS this cycle, parallelized.
Budget
Section titled “Budget”Validate cycles are context-bounded, not capped (ADR-003 of the mold-parity spec). Confidence-gathering is the goal; an arbitrary cap cuts it short.
- No hard cap. Run as many
/briesearchcycles as confidence needs. The context-budget mechanic (context-budget.md) is the natural limiter — offload deep evidence to a sub-agent and watch the window. - Soft backstop of 10. At the 10th launched cycle, ask once “still gathering — continue?”; it is a check, not a stop, and the user can wave it through.
- Cycles backed by local semantic source-code evidence alone are unbudgeted — they do not count toward the backstop.
The same context-bounded rule governs Prototype Cycles (prototype-cycle.md).
When to skip
Section titled “When to skip”- The claim is already grounded by a bounded source read or earlier cycle; source-code reads follow the shared routing contract.
- The decision is reversible and small — running a cycle costs more than just trying it.
- The user explicitly said “skip the cycle”.
Logging
Section titled “Logging”Every launched cycle is logged in the mold state file:
validate_cycles: - id: vc-1 hypothesis: "Express's Router supports per-route middleware arrays" outcome: SUPPORTED sources: [Context7] - id: vc-2 hypothesis: "We can hot-swap the auth middleware without restart" outcome: CONTRADICTED conflict_id: cf-1Open hypotheses (no outcome:) block Curdle until they settle or are explicitly accepted as [TBD].