Skip to content

/mold

When to invoke: Turn a high-leverage design decision into a validated spec through grounded dialogue. Use it when a leverage trigger fires (auth, irreversible effects, concurrency, contracts, destructive ops, a new slice, a cross-slice dependency, an invariant gap) or when the user asks for a spec or design. Typical phrases include “let’s design X”, “shape this into a spec”, “what should the API for Z look like”, and “/mold”. A feature ask with zero fired triggers is a /cook mini-spec, not a mold; route it through /cheese. Do NOT use it for free-form discussion without artifact intent (/culture), direct implementation (/cook), or research-only questions (/briesearch). Ceremony scales to the ask through references/tiers.md, so a small clear change gets a validated mini-spec without a write-approval turn.


Ceremony scales to the job. The Bounds pass picks one of three tiers from references/tiers.md: Quick writes a validated mini-spec, Light runs only the dialogue modes the open forks need, and Full runs the whole Flow below. Saving a spec needs no extraction approval. Cook still needs an explicit user request. /cheese’s tier-1 escalation enters mini-spec mode; see ## Agent-invoked mini-spec mode.

  1. Bounds pass — open the Goal / Decided / Asking / [AGENT-DECIDED] ledger with the goal pinned as one sentence; only an explicit user fork changes it. Split it into G-n clauses (references/handshake.md § Goal coverage). Map every input’s goals and non-goals as one [AGENT-DECIDED] line; ask the user only when the goal is genuinely unknown or a leverage trigger fires. Run the shape check, then announce the tier with its reason (references/tiers.md). Quick exits here to ## Agent-invoked mini-spec mode without a write-approval turn. Upgrade the tier whenever the evidence changes; never downgrade silently.
  2. Route — choose the secondary mode from references/modes.md, announce it, and correct false premises first.
  3. Dialogue — consequential forks are the user’s to pick. A fork is consequential per the leverage line in ../age/references/voice.md. Every other fork is [AGENT-DECIDED]. Supply options, trade-offs, and evidence before you ask. Ground each critical claim through code, the Validate Cycle, or a Prototype Cycle. Resolve every contradiction. Render the decision map after three consecutive fork questions, or on request.
  4. Sketch — For work across modules or with a new public interface, run references/shape-check.md. Bind identity and role nouns to code referents. Record the Placement block; no bodies.
  5. Plan and validate — run the fresh-context fork-coherence taste test with python3 skills/mold/scripts/mold.pyz taste-test; a failure reopens only named forks, and the third failed verdict stops. The taste review guides the spec but is not a Cook execution reference. For bound curd work, dispatch a typed PlannerRequest, validate its PlannerResultWriterView (one retry, then save without runnable inputs), and normalize on the host. A clear single-curd task can instead use standalone Cook without a planner. Show semantic curds and waves before any Cook choice. See references/curdle.md § “Typed planner dispatch”.
  6. Readiness check — Before saving, run the coherence self-check and strict spec validation. Save a draft when unresolved parent work remains; record each hold in execution_holds:. Finalization refuses ready while an entry remains. User approval is not a prerequisite for writing. Before Cook, require an explicit user selection of scope and route. See references/handshake.md and references/early-curds.md.
  7. Curdle — Resolve the durable spec path with python3 skills/mold/scripts/mold.pyz artifact-path specs <slug> and read path from its JSON reply. Write the validated draft and read it back. Retain typed plan evidence and unresolved holds. Write local issue drafts and durable decisions; publish follow-ups only after their own approval. A concrete bounded curd may use references/early-curds.md while Mold continues shaping its parent. The selected spec path can enter standalone Cook; bound curd execution also receives validated direct refs, never a pointer.
  8. Offer Cook or keep shaping — after reconciliation, run python3 skills/mold/scripts/mold.pyz curd-count. A saved draft is not an execution request. If the user selects bound curd execution, run scripts/mold.pyz finalize and pass only ready direct inputs. A standalone clear task can enter Cook by spec path without machine finalization. Otherwise keep shaping or stop without a Cook command.

Portability: rules. Slash commands are host renderings, not the control model.

Every non-goal and explicit dialogue deferral becomes a [FOLLOW-UP?] follow-up candidate. Dispose of the set before a runnable Cook handoff; details: 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

Modes: references/modes.md. Evals: references/evals.md. Canvas: review-canvas.md.

/cheese’s tier-1 escalation calls /mold after the call site passes all Cook fast-path checks. The Quick tier enters the same mode without a write-approval turn. It produces a validated draft without design dialogue. Return the spec path. After the spec validates, show it and ask one direct Cook question. On explicit selection, dispatch /cook --spec <path> for clear standalone work; do not invent a pointer or require a planner. Append --hard when the user passed it.

The full coherence checklist does not run in this mode. The agent-introduced-scope check still runs implicitly. Every distinguishing noun must come from the user’s input or tier-2 /culture//briesearch synthesis. Never add one silently.

Full procedure, the mini-spec schema, and the ## Provenance rules: references/mini-spec-mode.md.

Call source-code search, read, and edit backends according to code-intelligence-routing.md. Shape checks use semantic caller search plus dependency context; procedure: references/shape-check.md.

Mold-specific tools beyond source-code routing:

Need Prefer Fallback
External validation /briesearch with Context7/Tavily user 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 record hallouminate: absent in the ledger, proceed on code evidence, and cap at speculating when design rationale is central

The grounding record precedes the first structured question: the ledger holds a probe result — citations or hallouminate: absent — first. Mark each unsupported claim [?] until settled.

/mold owns the dialogue, contradictions, and save-approval state. Do not delegate these items. Delegate evidence-heavy code work to a fresh-context explorer and external research to a researcher. Shape uses an explorer digest as input. Record parent-context exploration as a degraded path. See references/context-budget.md for budgets and checkpoints.

python3 skills/mold/scripts/mold.pyz gate-graph --render dot|svg|png|mermaid renders one gate model. Image targets use Mermaid when Graphviz is unavailable. Tests keep gate nodes aligned with the handshake checklist. See references/gate-graph.md.

Every Mold-produced spec carries a provenance marker in frontmatter:

source: mold-handshake | agent-mini-spec | mold-curd-mini-spec

A spec has no disposition field. ## Test Contracts is optional: a spec may include it, and no gate requires it. Row-level rules: references/curdle.md § Test Contracts.

python3 skills/mold/scripts/mold.pyz taste-test binds the verdict to draft SHA256 and each settled fork. Stale, partial, or blocked verdicts fail; a failure reopens only named forks, with two rounds. Approved specs pass unchanged metadata to /cook --spec <spec-path> (add --auto only when the user chose it) for standalone work; bound curd work uses /cook --auto --result <result-path>.

Each fork appears in Approach, Interface sketches, and Acceptance, plus Test Contracts when the draft has them. Do not rename sections. Tag reflecting lines with fork id and run taste-test --precheck before dispatch. goal must survive verbatim in Problem statement (goal-drift); each G-n clause carries an Acceptance or disposition tag (goal-coverage). See references/curdle.md § Spec template and references/gate-graph.md.

Mold may save a validated parent spec or early curd mini-spec without an approval turn. The agent coherence check still controls what the artifact claims as settled. Print the narrowing delta (taste-test --coverage) and the scope audit table before presenting any Cook option. Unresolved decisions remain visible holds, not implicit approvals. See references/handshake.md.

Never start Cook from a saved spec, silence, --auto, or a general design approval. The user must select the exact curd or parent scope and a Cook route. A changed scope or plan needs a new selection. A failed bound finalization leaves a saved draft without executable refs. See references/early-curds.md.

Mold never runs the metacognitive check. Plate alone runs it at the verified-artifacts boundary. Mold appends --hard to every Cook command that it emits when the user passed the flag. Cure forwards the same flag to Plate. See ../hard-cheese/references/composition.md.

Pipeline: culture → [mold] → cook (⇄ press) → age → cure → plate

After Curdle’s phase two finishes, run python3 skills/mold/scripts/mold.pyz curd-count for the blast-radius digest. A draft offers no Cook command. On explicit Cook selection, retain the selected spec path for standalone work. Bound curd work dispatches the printed finalize command, /cook --auto --result <result-path>; the result carries request_id, spec_ref, planner_result_ref, plan_ref, and exact coverage. Prompt through the shared handoff gate (policy); never pre-select. Keep applicability, contract, and taste review metadata unchanged. Append --hard when the user passed it.

The digest’s mode is orientation, not a skill or Cook gate. Render the fixed blast-radius menu from decomposable, candidate_curds, verdict, and mode; see references/handoff-menus.md.

  • Dialogue first; artifacts are the by-product.
  • Tiered lettered options. Consequential forks use A/B/C/D choices via the question transport at ../cheese/references/ask-user-question.md. Never decide them silently. Everything below the leverage line is [AGENT-DECIDED] by default: make the call, log a one-line vetoable alternative in the ledger, and do not ask. A fork is valid only after its depth was contributed in-dialogue first. Precede every structured question with visible prose that weighs the fork and the evidence. Keep one open picker in conversation. In the optional review canvas, independent, already-explained fork cards may share one batch; dependent forks wait for agent reconciliation.
  • Fork cards. Before each consequential question, show a fork card: what it decides, what it moves, and each branch as a symbol table or plain-text graph. Offer Explain more as a choice; an unclear reply re-renders the same fork with more context (fork-questions).
  • Altitude tag. Every Asking fork names the acceptance criterion, public seam, or non-goal it moves. A fork that moves none, or that sits below the leverage line, is [AGENT-DECIDED] or a follow-up candidate, never a user question.
  • Decision ledger. Each round prints Goal / Decided / Asking / [AGENT-DECIDED], the goal verbatim. Curdle persists consequential decisions to ADRs and minor ones to the spec. The taste verdict names every settled consequential entry exactly once.
  • Decision map and fork-round cap. Stop after three consecutive fork rounds that add no new evidence, or three consecutive forks that fail the altitude tag, or when the user requests a decision map. Show completed forks, remaining forks, and a ready or blocked verdict. A fourth round requires new grounding, a delegated digest, or a /wheypoint checkpoint. The map shows ledger state. It does not create an artifact.
  • Do not implement code.
  • Do not write production files in Mold. Saving a spec does not authorize Cook.
  • Do not silently settle uncertain claims.
  • Apply the shared voice kernel at ../age/references/voice.md. Correct false premises. Mark each critical claim’s confidence as certain | speculating | don't know. Steelman before you dismiss. Put consequential forks to the user; depth informs the question, never replaces it.

The generated ../cheese/references/schema-intertwine.md lists every published schema and its contract model.

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
Plan 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. Commands: references/commands.md.

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 coherence self-check, in phase one’s local atomic write.

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.

Mold’s per-round decision ledger (Decided / Asking / [AGENT-DECIDED], see ../SKILL.md § Rules) persists here at curdle: each consequential decision (per the leverage line in ../../age/references/voice.md) earns an ADR — it is exactly the kind of decision a future reader would otherwise reverse-engineer. [AGENT-DECIDED] calls ride the spec’s one-line decision-log (curdle.md § Spec template) with their vetoable alternative, never 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 (the bundle command uses the same shape-match).
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>:wiki corpus via add_markdown. The corpus is shape-matched from list_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 — see curdle.md § Atomic write), and recommend installing hallouminate so future rationale becomes searchable.
  • probe shape varies by harness [?]: if list_corpora is 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.

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.

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.

scripts/render_generated_regions.py generates this file from the static COMMANDS manifest in src/easy_cheese/skills/mold/commands.py. Do not edit this file. Run each command as python3 skills/mold/scripts/mold.pyz <command> [args...]. Each command returns an integer exit status. Pass --help to a command for its arguments and output format. Keep worked examples in the skill instructions.

Command Purpose Subcommands
artifact-path Resolve the durable or transient artifact path for a phase and slug
curd-count Count candidate curds in a spec and recommend the next skill
domain-model-target Resolve the domain-model store from explicit Hallouminate probe results
finalize Finalize a Mold spec and print a ready result for bound Cook execution
gate-graph Render the gate state machine as dot, svg, png, or mermaid
normalize-planner Materialize a planner writer envelope into a canonical PlannerResult
render-html Render a markdown report into one self-contained offline HTML file
review Serve and manage the local Mold review canvas
taste-test Run the applicability, contract, and fork-coherence taste gate; –precheck runs the lexical pre-check on the draft without a verdict
validate-spec Check a spec against the current Mold specification requirements

A long Mold dialogue can reduce model recall and coherence. This risk increases near 120,000 to 140,000 tokens. Mold controls this risk in three ways. It delegates heavy work, limits active orchestration, and recommends a checkpoint when the context grows. Delegation is the most reliable control. See ADR-003.

Use the sub-agent context gate for heavy work. Resolve the read-only role through ../../cheese/references/agent-resolution.md. Select the exact specialist first. Then select a compatible specialist. Use a constrained general worker with degraded: true only when no specialist is available. Work in the parent context only when dispatch is unavailable.

  • Research: Delegate deep /briesearch work to a researcher. Deep work uses at least three document fetches or two search angles.
  • Shape check: Delegate wide analysis to an explorer. Wide analysis includes more than five symbols or a large caller graph.
  • Prototype Cycle: Always run the temporary build in an explorer. See prototype-cycle.md.
  • Diagnose: Delegate large logs and traces to an explorer. Keep only the concise root-cause hypothesis in the parent context.

The sub-agent returns a digest of 2 KB or less. Do not copy raw evidence into the parent context. The parent keeps the dialogue, contradictions, save-approval state, and coherence self-check. Never delegate these items.

Token pressure gives a late warning. Active orchestration consumes the context before this warning occurs. One Mold episode can include bounds, grounding, research, Shape, taste tests, planning, approval, and publication.

The 2026-08 workflow sample contains 16 top-level invocations. The median active time is 35.6 minutes. Large sessions use 100 to 276 tool calls and up to 11 sub-agent spawns.

Each phase has a bound and an exhaustion action. When a phase reaches its bound, stop new work. Record the settled work and take the checkpoint.

Budget Bound On exhaustion
Ground per topic 1 wiki probe and 1 delegated digest Mark the remainder [?]. Treat a third probe as repeated work.
Shape or Sketch per option set 1 explorer digest require a new question before a second dispatch
Fork rounds 3 consecutive rounds that add no new evidence show the decision map and stop questions
Fork altitude 3 consecutive forks that move no acceptance criterion, seam, or non-goal show the decision map; demote the pending fork to [AGENT-DECIDED] or a follow-up candidate
Parent-context tool calls approximately 40 calls run /wheypoint before the next heavy step
Sub-agent spawns 6 spawns per episode Run /wheypoint. Resume from the digests.
Repeated failures 2 consecutive failures from the same tool or agent record the degraded path and use a different route

Count only calls and spawns from the parent context. Do not count internal sub-agent tool calls. Delegation exists to move those calls out of the parent context.

These budgets are not terminal limits. Exhaustion requires a checkpoint or a recorded degraded path. It does not permit a truncated design. Do not make a silent third attempt.

No precise live token count is available. Use the visible signals to estimate context use.

Estimate Action
approximately 120,000 tokens Advise the user that the context is filling. Delegate the next heavy step. Keep each question concise.
approximately 140,000 tokens Recommend /wheypoint. Resume in a fresh context.

Estimate from the turn count, sub-agent digests, and large pasted inputs. Do not report false precision. Delegate before you recommend a checkpoint. Delegation directly reduces parent-context use.

At approximately 140,000 tokens, recommend this action. Do not run it automatically.

The dialogue can now reduce model recall. Run /wheypoint to save the settled decisions in .cheese/notes/<slug>.md.
Resume in a fresh session with /cheese --continue <slug>.

/wheypoint preserves the dialogue, contradictions, approval state, and open Validate or Prototype cycles. The fresh agent resumes at the current handshake state. It does not derive the design again. See skills/wheypoint/SKILL.md.

A hard token gate can stop confidence work too early. ADR-003 rejects this behavior for cycle caps. Context pressure is approximate. Therefore, Mold recommends delegation or a checkpoint instead of ending the dialogue.

Runs after Curdle writes the spec, before finalization. Pushes the parse-and-count work into a Python script so the sizing signal is deterministic and stays out of the conversation’s token budget.

Curd-count reports candidate sizing and the recommended downstream skill. The digest includes goal, quality-gate, and decision signals; landing metadata; and an advisory Cook wave-plan mode. It has no handoff field and does not construct an execution command. Finalization alone evaluates all required evidence and publishes a canonical Cook handoff when the result is ready.

The recommendation names the skill only. The count is advisory sizing: it never authorizes Cook, bypasses finalization, or turns a saved non-ready result into a runnable handoff.

A decomposition of PARALLEL_THRESHOLD (2) or more curds signals a parallel Cook wave-plan; below that, high blast radius signals a linear chain. The decomposer stays authoritative—the count is a pre-dispatch hint, not the mode gate. /ultracook is retired as a top-level skill choice.

After curdle.md writes the spec to disk, resolve its path, then run the script and read the JSON digest into context. <path> is the path field of the artifact-path reply:

Terminal window
python3 skills/mold/scripts/mold.pyz artifact-path specs <slug>
python3 skills/mold/scripts/mold.pyz curd-count <path> \
--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 route stays /cook, while sub-threshold specs receive no Cook mode hint.

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.

recommended_skill is always /cook; it is an advisory destination, not an execution decision. Curd-count emits no handoff or command. The independent Cook mode signal follows the curd count and blast radius:

candidate_curds blast_radius mode
≥ 2 (PARALLEL_THRESHOLD) any parallel
< 2 high linear
< 2 medium, low, or unknown null
{
"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 (advisory)"
}

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 each curd’s scope from the typed CurdPlan (the planner derives file footprints from the Placement block’s slice: and public interface: lines plus the shape-check importer list; ## Interface sketches itself carries no file paths) 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.

The script depends only on the Python 3 stdlib. If the host has no python3, Mold may report the sizing signal manually: count the behavioural goals and apply the blast-radius mode table. Finalization still owns readiness and publishes any Cook handoff; do not substitute an execution command.

Curdle saves a validated draft and may run while Mold continues shaping its parent. Spec writing needs no user approval. A runnable Cook handoff still needs the agent coherence self-check (see handshake.md). For a bounded early curd, read early-curds.md.

Resolve the spec path: run python3 skills/mold/scripts/mold.pyz artifact-path specs <slug> and read path from its JSON reply — 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. It absorbs problem framing, requirements, approach, decisions, interface sketches, risks, and gates. An issue is a separate GitHub-flavoured item. The user can paste it into a tracker.

  • Lowercase the working problem statement, drop stopwords, kebab-case, cap at 5 words.
  • Validate every slug before any Curdle write. Run python3 skills/mold/scripts/mold.pyz artifact-path specs <slug>. The command applies validate_slug and returns a nonzero status for an invalid slug. Stop on a nonzero status.
  • Accept a user-passed slug only after that command returns status zero. A slug can otherwise contain .. or / and write outside .cheese.
  • Reuse the validated slug for every repo-local path. Repo-local paths include .cheese/issues/, .cheese/glossary/, and .cheese/.out-of-scope/. Never interpolate a raw slug into a path.
  • Match the spec’s parent slug for issues (<slug>-001.md, -002.md).
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

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.

landing.layers records ordered groups of canonical curd ids from the approved CurdPlan, as a one-line flow list. Leave it [] only when shape is single; a non-single shape requires at least one layer.

Fork-id tags. Every settled consequential fork in the decision ledger must appear in Approach, Interface sketches, and Acceptance, plus Test Contracts when the draft has them. Each line that reflects a fork carries the fork id in parentheses, for example - AC-3: WHEN ... THE SYSTEM SHALL ... (F-3) or public interface: parse(...) -> Result (F-2). The taste test matches the fork id literally, or every 3+ letter word of the decision text; the tag is the reliable form.

Goal-clause tags. Every G-n clause from the ledger’s goal_clauses carries its tag on at least one Acceptance line, or on exactly one disposition line: a Non-goals bullet, a Deferred follow-ups entry, or a [TBD] item under Open questions. The pre-check fails goal-coverage:G-n for an untagged clause and goal-coverage-cap:<covered>/<total> when fewer than half the clauses reach Acceptance. See handshake.md § Goal coverage. Run python3 skills/mold/scripts/mold.pyz taste-test --precheck --draft <draft> --ledger <ledger> before the reviewer dispatch; fix every reported gap first.

---
slug: <slug>
status: draft
source: mold-handshake
created: <YYYY-MM-DD>
confidence: <low | medium | high>
leverage: [] # fired trigger ids per `../../cheese/references/routing-policy.md` § Leverage triggers; copied from the handoff packet, extended when a later mode fires one
gates_overridden: [] # list of unchecked handshake items if the user approved saving anyway
execution_holds: [] # unresolved named holds (scope-audit row, needs-your-verb, ALIAS/NEW ENTITY, coherence) written at save and removed when resolved; finalize and `/cook --spec` stay held (spec-hold refusal) while it is non-empty
agent_introduced_scope: [] # terms in the spec the user did not type — approved through the scope audit table per `handshake.md` § Scope audit table (audit trail; downstream skills trust this list)
goal_coverage: {} # G-n -> covered | non-goal | follow-up | tbd, the final disposition map printed as the narrowing delta per `handshake.md` § Goal coverage (audit trail; downstream skills trust this map)
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)
agent_resolution: [] # the shared agent-resolution block per `../../cheese/references/agent-resolution.md`
landing:
shape: single | orthogonal_flat | stacked_linear | diamond_stack
layers: []
per_layer_green: required | tip-only
review_fixes: fold | top-up
# <Title>
## Problem
<one paragraph; what's broken or missing today, who feels it>
## Goals
- G-1: <one outcome clause of the pinned goal, verbatim from the ledger>
- G-2: <...>
## Non-goals
- <bullet> (G-n when this bullet defers a goal clause)
## 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>
## Grounding
Add exactly one row for each probe. Use `hit`, `miss`, or `unavailable` for `Outcome`.
Use `unavailable` when a probe cannot run. Record the attempted action in `Evidence`.
Do not leave `Evidence` blank. You can skip a probe, but do not assume its result.
| Probe | Outcome | Evidence |
| --- | --- | --- |
| wiki | <hit \| miss \| unavailable> | <wiki path and one-line finding, or what was attempted> |
| explorer | <hit \| miss \| unavailable> | <explorer digest path and one-line finding, or what was attempted> |
## 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 THE SYSTEM SHALL

If the trigger cannot be stated precisely (e.g. pure internal utilities with no external event), use prose with a `[prose-fallback]` marker.
- AC-1: WHEN <trigger> THE SYSTEM SHALL <response> (<fork-id>, <G-n>)
- AC-2: WHEN <trigger> THE SYSTEM SHALL <response> (<fork-id>, <G-n>)
## Acceptance demonstration
This section is required. Behavior work fills the table with exactly these seven rows, each non-empty.
Non-behavior work (docs, refactor, config) replaces the table with one line: `n/a: <reason>`.
`False success` names one plausible wrong result and how the check rejects it.
Keep every row independent of the implementation: name what a user or caller observes.
| Field | Value |
| --- | --- |
| User task | <what the user wants done> |
| Input | <concrete input> |
| Entrypoint | <command, API, or UI the user touches> |
| Expected result | <observable outcome> |
| Real boundaries | <real systems, files, or services crossed, not mocked> |
| False success | <plausible wrong result and how the check rejects it> |
| Evidence | <what artifact or output proves it> |
## Test Contracts
This section is optional. Include it only when the spec benefits from it.
When present, every numbered Acceptance ID appears exactly once in this table.
`expected_failure` names a deterministic witness and the expected failing assertion.
`mode` is `tracer`, `contract-matrix`, or `guard`.
The seam is the outer boundary that proves the behavior.
A matrix names its ratified interface version and each unique row identity.
Separate row identities with `<br>`.
A guard or tracer leaves those cells blank.
Add one row for each criterion.
| Acceptance ID | Interface referent | Outermost stable seam | Expected failure | Mode | Interface version | Matrix rows |
| --- | --- | --- | --- | --- | --- | --- |
| AC-1 | <public interface> | <existing outer seam> | <witness and expected failing assertion> | tracer | | |
| AC-2 | <public interface> | <existing outer seam> | <witness and expected failing assertion> | contract-matrix | <ratified version> | <row 1><br><row 2> |
## Interface sketches
The Placement block from Sketch (`modes.md` § Sketch). Architecture at 10,000 ft, not bodies.
```text
slice: <owning slice | NEW SLICE>
spine step: <entry | workflow | domain | infra | none>
public interface: <one signature per new or changed crust export> (<fork-id>)
private: <responsibilities that stay behind the crust>
crust delta: <new exports | cross-slice imports | contract changes | none>
arrows: <dependency directions added, or none>
  • [TBD]
  • [BLOCKED] —
  • :

<the host-validated typed CurdPlan when present; list each linked early mini-spec with slug, resolved path, covered G-n clauses, dependencies, and state. Keep unresolved parent work here.>

<failing test, curl, replay command, etc.>

<one footnote definition per cited source; include only when out-of-scope evidence was cited above per ../../cheese/references/formatting.md § Citations>

`source: mold-handshake` marks the strict full-spec path. `source: mold-curd-mini-spec` marks a strict early curd with a required `## Parent` section.
Specs without this provenance marker are v0.13-era legacy and stay
**readable forever**: `validate-spec` accepts them, waiving only the part
the hardened format added after v0.13 — the `Test Contracts` section — and printing a one-line `NOTICE:` rather than an
error.
error. Everything a v0.13 spec did carry is still validated. Minting is the
mirror image: Curdle writes only the template above and gates it with
`validate-spec --strict`, which enforces the hardened format *and* the
`source:` marker unconditionally. Legacy is a read-side grace, never a
write-side option. The policy lives once in
`src/easy_cheese_schemas/spec_format.py` so every release channel inherits it.
#### Current mold-spec schema (generated)
The `mold-spec` document contract enforced by `validate-spec` (`shape-check.md`), refreshed by `scripts/render_generated_regions.py` from the `MoldSpecDocument` model in `src/easy_cheese_schemas/contracts.py`. Do not hand-edit the generated region.
<!-- BEGIN GENERATED: mold-spec-schema -->
document mold-spec {
section "Problem"
section "Goals"
section "Non-goals"
section "Deferred follow-ups"?
section "Grounding" {
columns: ['Probe', 'Outcome', 'Evidence']
per_row: ['Probe and Outcome are drawn from their closed sets', 'Evidence is non-empty, including for unavailable outcomes']
}
section "Approach"
section "Decisions"
section "Acceptance"
section "Acceptance demonstration"? {
columns: ['Field', 'Value']
per_row: ['the seven declared Field names each appear exactly once', 'every Value cell is non-empty', "non-behavior work uses one 'n/a: <reason>' line instead"]
}
section "Test Contracts"? {
columns: ['Acceptance ID', 'Interface referent', 'Outermost stable seam', 'Expected failure', 'Mode', 'Interface version', 'Matrix rows']
per_row: ['tracer rows leave Interface version and Matrix rows blank', 'contract-matrix rows require both Interface version and Matrix rows']
}
section "Interface sketches"
section "Risks"
section "Open questions"
section "Quality gates"
section "Curds"
section "Reproduction"?
section "References"?
}
rule acceptance-demonstration-complete: "Strict validation requires seven non-empty demonstration fields or an n/a line."
rule ac-coverage-exactly-once: "Every Acceptance ID must appear exactly once in the Test Contracts table."
rule tracer-row-blank-matrix-cells: "Tracer rows must leave Interface version and Matrix rows blank."
rule contract-matrix-row-requires-both: "Contract-matrix rows require both Interface version and Matrix rows."
rule grounding-probe-recorded: "The Grounding table must record the wiki probe exactly once with non-empty evidence."
rule delegation-digest-recorded: "The Grounding table must record the explorer probe exactly once with non-empty evidence."
rule landing-closed-class: "landing fields take only their declared values; layers is empty when shape is single."
type AcceptanceDemonstration {
fields? Mapping[str, str] = {}
na_reason? str = ''
}
type GroundingRow {
probe GroundingProbe
outcome GroundingOutcome
evidence str
}
type Landing {
shape LandingShape
layers? tuple[tuple[str, ...], ...] = ()
per_layer_green? PerLayerGreen = required
review_fixes? ReviewFixes = fold
}
type MoldSpecDocument {
frontmatter MoldSpecFrontmatter
acceptance_ids? tuple[str, ...] = ()
test_contract_rows? tuple[TestContractRow, ...] = ()
grounding_rows? tuple[GroundingRow, ...] = ()
acceptance_demonstration? AcceptanceDemonstration | None = None
}
type MoldSpecFrontmatter {
slug str
status str
source str
created str
confidence SpecConfidence
gates_overridden? tuple[str, ...] = ()
agent_introduced_scope? tuple[str, ...] = ()
entity_referent_bindings? tuple[Mapping[str, object], ...] = ()
execution_holds? tuple[str, ...] = ()
landing? Landing | None = None
}
type TestContractRow {
acceptance_id str
interface_referent str
outermost_stable_seam str
expected_failure str
mode TestContractMode
interface_version? str = ''
matrix_rows? tuple[str, ...] = ()
}
enum GroundingOutcome = "hit" | "miss" | "unavailable"
enum GroundingProbe = "wiki" | "explorer"
enum LandingShape = "single" | "orthogonal_flat" | "stacked_linear" | "diamond_stack"
enum PerLayerGreen = "required" | "tip-only"
enum ReviewFixes = "fold" | "top-up"
enum SpecConfidence = "low" | "medium" | "high"
enum TestContractMode = "tracer" | "contract-matrix" | "guard"
<!-- END GENERATED -->
### Issue template
```markdown
---
slug: <slug>-<NNN>
status: open
flavor: bug | chore | slice
parent_spec: <slug>
---
# <One-line summary>
## Context
<why this exists, in 1–3 sentences>
## Acceptance
- AC-1: <bullet — verifiable outcome>
## Notes
- <optional caveat or pointer>

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.

Preserve every existing Curdle by-product: the spec, ADRs, glossary, domain model, and all rejected-direction records. Add a local issue draft for each accepted follow-up that needs a recoverable tracker payload. Before any external call, persist its ID, destination, prepared state, and draft reference in Deferred follow-ups.

$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 gh as the portable fallback. Discover repository labels and issue forms instead of assuming them.
  • For roadmap goals, run the owned /wiki-roadmap workflow 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 for the exact deterministic follow-up ID before creation. If an exact match exists, link it. You SHALL NOT create a duplicate.
  • A reused external item becomes linked; a newly published item becomes created. Reconcile that state and the final URL or durable roadmap reference into Deferred 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. 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.

Write the session’s non-obvious decisions as durable ADRs after the coherence self-check passes. Include them with the durable spec in phase one’s local atomic write. Both stay in the durable project corpus. The spec is the approved implementation contract. The ADRs preserve its rationale. Resolve the corpus dynamically. Probe for the consumer’s repo:<their-repo>:wiki hallouminate corpus. Write there when it exists. Otherwise write a tracked docs/adr/<slug>-NNN.md. Never hardcode a corpus name. See adr.md for the full resolution rule and the ADR format.

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 losing synonyms that the Ground phase rejected in favour of the canonical term. Separate multiple synonyms with commas. Use — when none exist. Omit the file if Ground resolved no terms and no overloaded-term dialogue occurred.

During the same atomic step as the spec, ADRs, and per-slug glossary, merge the session’s resolved terms with their Avoid synonyms. Merge them into the project-level domain model. After the Hallouminate probe, resolve the target through the Mold bundle command:

python3 skills/mold/scripts/mold.pyz domain-model-target \
--probe <unavailable|no-match|match> \
[--corpus repo:<repo>:wiki --model <present|absent|unknown>]

Pass unavailable when Hallouminate is not loaded or the probe failed. Pass no-match when the listing completed but contained no repo:*:wiki corpus. Pass match with the exact corpus name and its model status when the listing found one. The command accepts only these explicit probe results; it does not import or invoke MCP machinery. It emits canonical JSON with backend, string location, and wiki_reachable. Preserve the resolver’s wiki, tracked docs/, then XDG read precedence and report a wiki_reachable: false fallback before writing a file target.

The per-slug glossary is a branch-local handoff. The domain model is cumulative cross-session memory. It builds the project’s ubiquitous language across every session. Add only context-specific terms. Never add general programming concepts.

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 selected by the bundle command (wiki, docs/, XDG corpus).

Write the rejection to .cheese/.out-of-scope/<slug>-NNN.md when the agent-introduced-scope audit rejects a direction. Do the same when the handshake rejects it. Rejections include “drop ” for an approach or design knob, and “not that approach.” 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>
## Context
Session: <slug>; rejected at: <handshake | scope-audit>

/cheese consults this store before it proposes a direction again. 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. Accepted follow-ups use Deferred follow-ups and any auxiliary .cheese/issues/ recovery draft. Write only direction-level rejections. These include approaches, design knobs, and named features that the user explicitly declined. Note: this store uses the dot-prefixed path .out-of-scope. Its sibling stores, glossary/, issues/, and specs/, do not use dot prefixes. Each scan must explicitly target the dotted path. A bare .cheese/* glob does not match it.

Run /spec-verify as an independent spec-review pass before the hand-off when the harness provides it. Skip it without a warning when it is absent. Note the absence once. This pass is optional. It must not block Curdle in an environment that does not bundle the skill. Never create a hard dependency on it.

Detect the skill at the instruction level, not in code. Check whether /spec-verify appears in the agent’s available toolset. Use the pattern in ../../cheese/references/optional-plugins.md § Probe pattern. Do not use command -v or another shell probe. /spec-verify is a skill, not a $PATH executable.

Stage to a temp directory under ${TMPDIR} first, then move into place. Never leave partial files on a write failure.

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:

  1. Resolve the target dynamically. For the ADR, use the resolution procedure in adr.md § Resolution. For the model, run the domain-model-target bundle command shown above with the Hallouminate probe result. It emits backend, string location, and wiki_reachable; False means that the wiki probe was not consulted because it was unavailable. Thus, its file backend is a degraded fallback, not a confirmed absence. This condition triggers the loud fallback below.
  2. Write to that target: add_markdown when the backend is hallouminate, a staged file write when it is file.
  3. Read back the entry and confirm that it exists. For the wiki backend, use ground or read_markdown. For the file backend, read the file again. Treat a write that you cannot read back as a failure. Fail loudly, and do not claim the write.
  4. Record it in the curdle completion record printed to the user: one line per durable write naming <artifact> → <location> (<backend>).

Loud fallback. If hallouminate is unavailable and the resolver degrades to a file backend, state this in one visible line. File backends include docs/adr/…, docs/domain-model*, and the XDG corpus. Never write silently to files when the author expected the wiki. See the absent-plugin degrade contract in ../../cheese/references/optional-plugins.md.

Before this procedure, run the digest-bound fresh-context fork taste test on the dialogue-state draft. It must pass for a runnable handoff; failures reopen only named forks, with two correction rounds. A blocked draft may still be saved with named holds. Prepare the typed plan before the user chooses Cook so the displayed coverage is exact.

  1. Dispatch a fresh-context planner on a PlannerRequest built from the current draft spec text. The planner returns a PlannerResultWriterView; it does not own contract versions, identifiers, digests, lineage, or evidence references.
  2. Validate and normalize the writer view on the host. The normal selected path is the typed PlannerResult containing a typed CurdPlan; reject malformed or wrong-kind output before display.
  3. Still invalid after one retry — save the draft with a plan hold. Do not publish or dispatch an invalid plan.
  4. On success, count semantic curds and waves from the typed CurdPlan, then show N curds / M waves before any Cook choice. The user’s Cook selection covers this exact plan. When candidate curds are two or more, settle landing shape and curd independence before execution.
  5. Persist the draft spec and host-validated PlannerResult and CurdPlan. Do not mutate a displayed execution plan; a change requires a new user Cook selection.

Finalize the selected spec and plan before bound curd execution. The host owns three values and sets each once:

  • REQUEST_ID is the request_id of the PlannerRequest. Keep it stable on an identical retry.
  • ARTIFACT_ROOT is .cheese/cook/<slug>-artifacts. Mold and Cook use the same directory.
  • The operation id is <slug>-<ordinal>. Keep it for an identical retry. Increase the ordinal when an input changes.

After the user selects Cook for the displayed scope or plan, finalize bound curd work. Finalization takes no user approval record or taste-result argument:

Terminal window
python3 skills/mold/scripts/mold.pyz finalize "$SPEC" \
--artifact-root "$ARTIFACT_ROOT" \
--operation-id "<slug>-<ordinal>" \
--request-id "$REQUEST_ID" \
--planner-result "$PLANNER_RESULT_JSON" \
--plan "$CURD_PLAN_JSON"

--plan may be omitted when PlannerResult embeds the exact plan. Pass --save-approved only to save with unchecked coherence items. It adds a hold, so the result remains saved-not-ready; it does not authorize Cook. A fresh user decision and updated spec are required before re-finalization.

Read status in the output, not only the exit status. A nonzero exit status is an input error; stop. ready stores request_id, spec_ref, planner_result_ref, plan_ref, and coverage at result_path. saved-not-ready exits zero and lists unmet requirements and holds, but gives no executable refs.

For ready, render the ready branch of handoff-menus.md. The printed command is /cook --auto --result <result_path>; run it only when the user selects an automatic choice. A manual choice uses /cook --result "$RESULT_PATH". Cook reads the ready refs from result_path and passes them to the host’s execute_bound_plan. For saved-not-ready, show each hold and requirement. Do not dispatch bound execution.

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 (auto) /cook --auto --spec "$SPEC" (standalone) or the printed /cook --auto --result <result_path> (bound) after explicit selection; add --hard when the user passed it
Spec /cook --spec "$SPEC" (standalone) or /cook --result "$RESULT_PATH" (bound) after explicit selection; add --hard when the user passed it
Issues Paste each into your tracker, or gh issue create --body-file <path>
Issues Paste each into your tracker, or gh issue create --body-file <path>

Read this when a concrete curd appears before the parent design is complete. This is an in-dialogue Mold path, not the leverage-free Quick path.

Mold may save a draft parent spec and a draft mini-spec without a separate extraction approval. Saving does not authorize Cook. No coder, worktree writer, /cook command, or automatic chain starts until the user explicitly selects that curd and a Cook route. Silence, a general approval of the idea, --auto, and a saved spec do not start Cook.

A curd is ready to mint only when its scope, acceptance checks, dependencies, and non-goals are concrete. Every consequential decision used by that curd must be settled. Open parent forks may remain only when they cannot change the curd’s contract. If a parent fork can change it, keep shaping instead of minting.

Resolve the parent and child paths with scripts/mold.pyz artifact-path specs <slug>; read path from each JSON reply. Use a distinct child slug. The child uses source: mold-curd-mini-spec, status: draft, the mini-spec schema in mini-spec-mode.md, and a required ## Parent section:

## Parent
- Spec: <parent slug>
- Goals: G-1, G-2
- Depends on: <child slugs or none>
- Frozen decisions: F-1, F-2

The parent ## Curds section lists each child slug, its resolved spec path, covered G-n clauses, dependencies, selected route, and state: draft | cooking | cooked | integrated | superseded. Keep unresolved parent goals and forks in the parent. Do not claim that a cooked child completes the parent. Do not copy a child’s acceptance text into the parent; the child is the contract for that slice. Validate each child with scripts/mold.pyz validate-spec --strict, then read it back. A failed check leaves the child unminted.

A changed child contract gets a new revision and a new execution decision. Do not overwrite an already cooking or cooked child. Recheck parent decisions and file overlap before integrating a Cook result. A conflicting result returns to Mold for reconciliation; it does not silently rewrite either contract.

Show the child contract, dependencies, changed files or intended footprint, and remaining parent work. Ask one route question through ask-user-question.md only when the user wants Cook:

  • Cook here in isolation: dispatch the selected child spec to one isolated coder or worktree. Bound curd execution also passes ready direct finalization refs. Keep Mold’s parent dialogue state with the orchestrator.
  • Cook in another worktree: give the user a command naming the child spec and its revision or digest. For local worktrees with a shared corpus, run python3 skills/mold/scripts/mold.pyz artifact-path specs <child-slug> and show /cook --spec <path>, where <path> is the path field of its JSON reply. For a destination without that corpus, supply the complete validated spec as a portable file and show /cook --spec <copied-spec-path>. The destination takes the user’s Cook request as its own invocation. Never give a bare slug or a local-only path as if it worked in a cloud worktree.
  • Keep shaping: dispatch none. The child remains a validated draft.

A direct Cook selection starts Cook only when the displayed child and route are unambiguous. The selection covers the scope or plan, not the dispatch route. Record the selected route beside the child in the parent ## Curds section. Execute only that route. A route change needs a new user selection, even when the scope and plan stay unchanged.

For Cook here in isolation, follow curdle.md § Finalization for bound curd work. Dispatch only ready spec_ref, planner_result_ref, plan_ref, and exact coverage. If finalization returns saved-not-ready, show its holds and do not dispatch bound execution. A clear standalone child can use /cook --spec <path> without machine finalization. A new plan or changed scope needs a new Cook selection.

For Cook in another worktree, provide the validated spec and command without starting local Cook or publishing local execution refs. The destination treats the user’s Cook request as its own invocation. --auto may chain phases after Cook begins; it never starts Cook by itself.

Continue shaping the parent after the isolated dispatch or command handoff. Record the child’s result and any new constraints in the parent ledger. The user chooses when to Cook another child or the remaining parent scope.

Trigger and trace tests for /mold. Run these against real session transcripts when the skill changes.

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”
  • “/mold rename the parse_flags helper to parse_args in cli.py” — must trigger, and must land in the Quick tier: one confirm, a mini-spec, no fork questions (tiers.md).

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.

For every completed /mold run, verify first that the tier was announced in one line with its reason before the first fork question, and that any tier change was an announced upgrade, never a silent downgrade (tiers.md).

For each completed /mold Grill-mode run, verify:

  1. Every grilled item produces a steelman + tension statement before any verdict. Do not proceed directly to an uphold or amend verdict. Surface the steelman first.
  2. One user-fork round or more for each consequential grilled item. Consequential is the leverage line in ../../age/references/voice.md. Invoke the question primitive at least once for each consequential item. Use AskUserQuestion on Claude Code and Conductor. On another harness, use the equivalent in ask-user-question.md. Require a real user turn. Never render and answer an A/B/C/D block yourself. Never issue a verdict monologue on a consequential item without a user turn. Items below the leverage line are batch-reported as upheld with a one-line steelman and never become a user turn; a user turn spent on one is a regression.
  3. Amendments surface as questions before ledger entry. Ask the user about each amendment that a grill produces. Ask before you write the amendment to the per-round decision ledger.
  4. Clean-steelman batching stays scoped. Batch-report a consequential item as upheld only when its steelman finds nothing. Never include a consequential item with a live tension in a batch. Below-the-line items always batch, tension or not; the ledger carries their vetoable alternative.
  5. Every user fork names what it moves. Each Asking entry cites the acceptance criterion, public seam, or non-goal it changes. A fork with no such target is [AGENT-DECIDED] or a follow-up candidate, never a question.
  6. The Goal: line survives every round. The ledger repeats the pinned goal verbatim from the bounds pass to the handshake. A reworded goal traces to an explicit user fork.
  7. Every G-n clause reaches the handshake with a disposition. The bounds pass prints the clauses. The narrowing delta names each one as covered, follow-up, non-goal, or [TBD]. A spec that covers fewer than half the clauses triggers a re-pin-or-widen fork, never a silent proceed.
  • 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 Decided without a prior question to the user. Log as a regression.
  • Over-batching — a consequential item with a real tension gets swept into the “batch-reported as upheld” exception meant only for clean steelmans.
  • Under-batching — a below-the-line item (naming, internal scope, a trade-off that fires no trigger) gets its own user turn instead of a ledger line.
  • Altitude drift — three or more consecutive forks move no acceptance criterion, seam, or non-goal, and the decision map never renders. The rabbit hole this eval exists to catch: every noun traces to the user, so the noun-level scope gates stay green while the dialogue burrows.
  • Terse fork — a consequential question shows bare option labels with no fork card, no Decides: line, or no branch symbols or graph. Or it offers no Explain more choice, or it answers an unclear reply with a guess or a new fork. See fork-questions.md.
  • Goal fade — the Goal: line drops out of the ledger render or silently rewords. The taste test catches the terminal form as goal-drift; the per-round render is the early form.
  • Quarter build — the goal sentence survives and every noun traces, but Acceptance delivers a fraction of the clauses and the agent presents the slice as the whole. The pre-check catches the terminal form as goal-coverage:G-n or goal-coverage-cap; a missing narrowing delta at the handshake is the early form.

Run this scenario with a fresh task agent in an isolated repository. Supply the changed Mold bundle.

  1. Give the agent a strict, valid spec that needs two curds.
  2. Supply a typed planner result and explicit user Cook selection as separate host events.
  3. Require scripts/mold.pyz finalize; reject any publish command or fabricated execution refs.
  4. Pass the returned request_id, spec_ref, planner_result_ref, plan_ref, and coverage to bound validation and execution.
  5. Capture actual tool calls, any bounded runner response and setup evidence, and the final artifact.

The trace passes only when the checker accepts it, Cook validates the exact refs, and execution produces the selected curds. An unresolved hold must prevent ready finalization.

These evals are intentionally manual today.

A consequential fork question must let the user decide without a reread of the session. The user must see what the fork decides, how each branch behaves, and what each branch costs. This reference owns the shape of a Mold fork question. The transport at ../../cheese/references/ask-user-question.md owns the delivery.

Show a fork card in visible prose immediately before every consequential question. The card is the context that the transport’s self-containment rule requires.

Field Content
F-n title The decision as one question, in the user’s terms.
Decides: One sentence: the behavior or contract that changes with the choice.
Moves: The acceptance criterion, public seam, or non-goal that the fork moves (the altitude tag).
Today: One line or one graph of the current behavior, or new for new behavior.
Branches One row or one graph per option, with its gains, costs, and risks.
Legend: The symbols that the card uses.

Use this symbol set. Use one meaning for each symbol.

Symbol Meaning
✔ gain
✘ cost
⚠ risk
? unverified claim (the [?] marker)
──▶ data or control flow
──✗ failure or lost data

Draw the branches as a plain-text graph in a text fence when the fork changes flow, ownership, or order. Use a symbol table when the branches differ only in properties. Use Mermaid only when the host renders it. A terminal does not. Keep each graph to eight lines or fewer. For an architecture fork, name the C4 level and the elements in the graph, as diagrams.md defines them.

Example:

F-3 Where does the retry count live?
Decides: whether a job keeps its retry count after a worker crash.
Moves: AC-2 (retries survive restart), seam `JobStore`
Today: job ──▶ worker ──✗ crash ──▶ count lost
A job ──▶ worker ──▶ [jobs.attempts] ✔ survives crash ✘ one migration
B job ──▶ worker ──▶ (memory map) ✔ no schema change ✘ lost on crash
C job ──▶ broker header: attempts ✔ no DB write ⚠ couples to broker ?
D Do Nothing ✔ zero work ✘ AC-2 fails
Legend: ✔ gain ✘ cost ⚠ risk ? unverified ──▶ flow ──✗ loss

Each option description in the question widget repeats that option’s ✔/✘ line in words. The widget can truncate the card. The option text must still stand alone.

Before you ask, check the question against these terse-question tests:

  • The user can answer without a reread of an earlier turn.
  • Each option states an observable result, not only a label or a mechanism name.
  • The question defines every project term that the user did not introduce.
  • The card names the evidence and its confidence for each ⚠ and ? claim.

If a test fails, expand the card before you ask.

Every consequential fork question offers Explain more as an explicit choice. Its description is “Show more context, an example, and the downstream effect before I choose.” When the options plus Explain more exceed the question primitive’s capacity, use the transport’s numbered fallback or lossless hybrid. Never drop a design option to make space for Explain more.

Treat these replies as an Explain more selection:

  • the user selects Explain more;
  • the user replies explain or explain <option>;
  • the reply says the question is unclear, too terse, or confusing;
  • the reply is a question about the fork instead of a choice.

Do not guess a choice from an unclear reply.

On an Explain more selection:

  1. Keep the same fork id. Do not open a new fork.
  2. Add the context that the card left out. Use one or more of these angles:
    • background: why the fork exists, with ledger and evidence citations;
    • example: one concrete input that runs through each branch to its observable result;
    • graph: a larger diagram of the affected path, at the C4 level that the fork changes (see diagrams.md);
    • downstream: what each branch makes easy or hard later, and which follow-up it forecloses.
  3. Ask the same fork again with the same options and Explain more. Its description becomes “Explain from a different angle.”

Each re-explanation uses an angle that the user has not seen. Never repeat earlier text. When the user selects Explain more for a specific option, explain only that option. An explain round does not count toward the fork-round cap. It adds no ledger decision.

GATE_MODEL in src/easy_cheese/skills/mold/gate_graph.py holds the one canonical model of Mold’s runnable Cook handoff gate. Draft spec writes happen before this gate. The mold archive bundles it as the gate-graph subcommand. Both render targets derive from that one model, so they cannot drift. See ADR-001. The model is also the gate-prose-sync source. Question transport stays in ask-user-question.md. One test asserts that the handshake coherence-checklist items equal the model’s gate nodes. No gate can therefore disappear from the prose without a failure.

Terminal window
python3 skills/mold/scripts/mold.pyz gate-graph \
[--state <state.json>] [--render dot|svg|png|mermaid] [--out <path>]

Without --out, the command prints one JSON document to stdout: {"render": "<dot|mermaid>", "text": "<rendered source>"}. The render field names the effective target — it differs from the requested --render only on the svg/png degrade path (below). With --out <path>, the command writes the rendered bytes to that path and prints {"path": "<out>"} instead.

  • --render dot (default): canonical Graphviz .dot as the text field.
  • --render mermaid: a fenced ```mermaid flowchart block as the text field — renders natively in GitHub and markdown viewers, no binary required.
  • --render svg|png: shells out to Graphviz dot when it is on PATH; pass --out <path> for binary targets — printing binary bytes to stdout is rejected. When dot is absent it degrades to mermaid — run-anywhere by construction.
  • --state: an optional Mold state.json. The command validates its shape. The gate model stays static, so the state does not change the graph today.
  • Onboarding a contributor to mold’s flow — one picture of modes → gates → execution handshake → Cook handoff.
  • 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.

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.

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:

Terminal window
python3 skills/mold/scripts/mold.pyz gate-graph --render dot \
--out skills/mold/scripts/mold.dot

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.

goal-coverage (rendered goal_coverage in the .dot) is the subtraction sibling of non-goals-audit. The noun audits catch scope the agent added; this gate catches scope the agent dropped. The bounds pass splits the pinned goal into G-n clauses and records them in the ledger as goal_clauses. The taste pre-check then reads each clause’s disposition from the draft alone: covered when an Acceptance line carries the tag, non-goal / follow-up / tbd when the matching section carries it, uncovered otherwise. An uncovered clause fails goal-coverage:G-n. Fewer than half covered fails goal-coverage-cap:<covered>/<total> and forces a re-pin-or-widen fork. taste-test --coverage prints the disposition map for the narrowing-delta line. Procedure: handshake.md § Goal coverage.

fork_taste_test_passed is the only edge into the typed planner stage. Mold hashes the exact draft before it accepts a verdict. The strict ForkTasteVerdict must cover each settled consequential decision exactly once.

The verdict fails for a stale digest, missing reflection, contradiction, orphan, unsupported assumption, or acceptance gap. A semantic pass with blockers also fails.

The ledger JSON may carry the pinned goal as a top-level goal string beside forks; a blank or non-string goal is a ledger error, ledger-goal-empty. The draft’s goal section is the first heading, at any level, whose text after case-folding and punctuation stripping is exactly Problem statement, Problem, or Goal; a heading with extra words such as ## Goal alignment or ## Problem statement (v2) is not the goal section, and a later goal heading never overrides the first. That section must contain the pinned sentence unchanged, compared case- and whitespace-insensitively. A reworded or dropped goal fails as goal-drift. A missing or unrecognised goal heading fails as missing-section:goal:problem. A ledger without goal skips the check. This is the zoom-out gate: the goal the user pinned in the bounds pass is the goal the spec ships. The devil in the details changes Acceptance or an Interface sketch; cruft changes neither, and a fork that changes neither never reaches the user.

Every draft must reflect Approach, Interface sketches, and Acceptance. A draft that includes Test Contracts must reflect them too.

The lexical pre-check (taste-test --precheck) runs the deterministic sub-checks (section presence, fork-id or decision-text mention, goal drift) against the draft alone. It runs before the reviewer dispatch. It does not count toward the two correction rounds. The full taste-test with --verdict repeats the same checks on the digest-bound verdict.

A third taste failure stops typed planning and preserves the draft for review. Taste evidence does not become a Cook execution reference.

Only a user-selected automatic route uses /cook --auto: --spec <spec-path> for standalone work, --result <result-path> for bound curd work. Cook reads the ready refs from the result without changes.

Probe the current repository’s wiki corpus at Ground phase entry. Probe only when hallouminate is available. Also probe at decision points in any Dialogue mode before you ask the next question. See § When to probe. Add each matching rationale entry or ADR entry to the evidence base.

Record one named probe outcome in the ledger for every probe. The outcome is hit, miss, or unavailable. Record hallouminate: absent once when the tool is missing. Then continue with diff evidence and code evidence only.

The grounding-recorded coherence gate blocks the first structured question until the ledger carries a probe outcome. The outcome carries citations, or it names the reason for the absence. Keep the degrade path cheap and visible.

Do not map the topic outcomes to domain-model-target arguments. Use the domain-model probe transport in ../../cheese/references/optional-plugins.md.

The probe mirrors the wiki probe pattern in the detect-and-degrade contract. See ../../cheese/references/optional-plugins.md.

ground_wiki(topic, repo_name, session_corpus):
# 1. Check hallouminate availability.
if "mcp__hallouminate__list_corpora" not in available_tools:
record once: "hallouminate: absent (tool not loaded)"
return unavailable
# 2. Select the corpus for THIS repository. Reuse the session selection.
if session_corpus is None:
corpora = mcp__hallouminate__list_corpora()
matches = [c for c in corpora if c == "repo:" + repo_name + ":wiki"]
if len(matches) != 1:
record once: "hallouminate: unavailable (no wiki for " + repo_name + ")"
return unavailable
session_corpus = matches[0]
# 3. Ground the topic.
results = mcp__hallouminate__ground(query=topic, corpus=session_corpus, limit=5)
record: "hallouminate: hit" with citations, or "hallouminate: miss"
return results
  • Derive repo_name from the configured origin remote. Use the host-reported repository root name only when no origin exists.
  • Match the corpus name exactly. Never select the first repo:*:wiki entry. A different repository’s wiki carries another project’s private rationale.
  • Record unavailable when zero corpora match. Record unavailable when more than one corpus matches. Never guess between two candidates.
  • Never block the dialogue on the probe. An unavailable outcome satisfies the gate.
  • Retain session_corpus for one Mold episode. Repeat discovery only after an unavailable outcome or a registry change.
  • State the absence once for each run. Write it to the ledger once. Do not repeat it for each question.

Probe at Ground phase entry. In other Modes (Shape/Sketch/Grill), probe at decision points before the next question when any condition applies:

  • The dialogue is about to decide a consequential fork whose options could have prior rationale (e.g. “why not X”).
  • Probe when the wiki can possibly answer the next user question. Examples include a settled decision, an ADR, or 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 in pure Explore mode when there is no named system. Also skip it in Diagnose mode. Diagnose evidence comes from code and logs, not rationale documents.

Cite hits in that round’s decision ledger under Decided / Asking / [AGENT-DECIDED]. See ../SKILL.md § Rules. Put a settled wiki decision under Decided and cite its wiki page. Do not reopen it as a new question.

A session can start with prior evidence. Sources include a /culture synthesis, a /briesearch report, or a .cheese/notes/<slug>.md wheypoint. Sources also include an earlier Mold draft or an ADR. Read this evidence once during the Bounds pass. Add each settled item to the ledger. Do not derive settled items again in the parent context.

An item covers a decision only when all three conditions apply:

  • Cited. The item names evidence that a reader can check. Use a path and symbol, line range, wiki page, or dated URL.
  • Fresh. The citation resolves at the current HEAD. Probe the evidence again when a referent moved, changed its name, or no longer exists.
  • Decisive. The item names the decision that it settles. A topic alone does not settle a decision.

Put covered items under Decided. Include the source artifact and citation, such as via: .cheese/notes/<slug>.md. Run the normal pass for each uncovered item. The fast path skips work. It never skips a gate. It cannot skip the coherence self-check or fresh-context taste test. It also cannot skip a consequential fork that the user did not select.

Record the intake result for each session. Record prior evidence: none when the session starts with no prior evidence. This intake record is not a probe outcome. It does not satisfy grounding-recorded. Run the wiki probe and record its outcome separately.

If hallouminate is absent and design rationale is central to the current question, cap the result at speculating. Note this limit inline. See ../../cheese/references/optional-plugins.md for the full degrade contract.

Read this after the user selects Cook. A saved draft alone renders no Cook command. The curd-count digest guides sizing; it does not grant execution authority.

  • A ready finalization result carries request_id, spec_ref, planner_result_ref, plan_ref, exact coverage, and a retained result_path.
  • A saved-not-ready result carries unmet requirements and holds, not runnable bound inputs. Show each item. Do not dispatch bound execution. A separate clear standalone task may use /cook --spec "$SPEC" only when Cook’s fast-path conditions hold and the user explicitly requests that route.
  • For a ready bound result, auto choices use the printed command (/cook --auto --result "$RESULT_PATH"); manual choices use /cook --result "$RESULT_PATH". For standalone work, use /cook --auto --spec "$SPEC" or /cook --spec "$SPEC". The host passes the ready refs to execute_bound_plan and validates them before writer dispatch.

After explicit Cook selection, render the branch selected by the sizing digest’s mode:

Decomposable specs (decomposable: true, candidate_curds ≥ 2, mode: parallel):

  • Run the full pipeline (parallel fan-out when disjoint, else linear) (recommended) — use the auto command above. Cook uses plan curds to select parallel or linear execution; /plate publishes the selected ordinary or stacked layout.
  • Implement manually, one phase at a time — use the manual command above.
  • Stop — dispatch none; leave the spec for later.

Non-decomposable, high-blast-radius specs (decomposable: false, verdict high only, mode: linear):

  • Run the full pipeline in fresh-context isolation (recommended) — use the auto command. Behavior work continues cook (Press loop) → age → cure → age → cure → age; non-behavior work skips Press and continues cook → age → cure → age → cure → age.
  • Implement manually, one phase at a time — use the manual command.
  • Compact and resume by hand — dispatch none; clear context, then use the manual command. /cheese --continue scans phase handoff slugs, so a fresh spec must be resumed through its explicit path.
  • 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) — use the manual command.
  • Implement and auto-review — use the auto command. Opening or updating a PR remains /plate’s explicit step.
  • Research more first — /briesearch.
  • Stop — dispatch none; leave the spec for later.

mode: parallel|linear selects fresh-context Cook execution; mode: null selects the smaller in-session path. This digest mode is not a Mold-to-Cook execution gate. The user must still opt into --auto.

Mold may save a draft spec without the self-check. A runnable Cook handoff requires the agent coherence self-check. Mold shows the scope or plan as information only. The user picks the route and starts Cook; a Cook request asks for no further reply.

Print this checklist before a runnable handoff. Save a draft with named holds when a box is unresolved; write each unresolved hold into the spec’s execution_holds: frontmatter list and remove it only when it is resolved. User approval to save anyway can save, but cannot waive execution readiness:

Coherence self-check before Cook handoff:
- [ ] Problem statement: grounded, agreed
- [ ] Grounding recorded: a wiki probe result — citations or an explicit hallouminate-absent note — preceded the first structured question
- [ ] At least 2 options weighed (Do Nothing included)
- [ ] Chosen option grounded in codebase evidence
- [ ] Exploration delegated: evidence-heavy reads carry an explorer digest, or the parent-context fallback is recorded
- [ ] Interface sketches: Placement block complete (slice, spine step, public interface, private, crust delta, arrows)
- [ ] 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]
- [ ] Goal coverage: every G-n clause is covered by an AC or carries an explicit disposition, at least half ship, and the narrowing delta is printed
- [ ] 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)
- [ ] Fork taste test passed: fresh-context verdict covers every settled consequential decision before typed planning
- [ ] Spec format valid: validate-spec --strict exits 0 on the draft

If any box is unchecked, name it and propose the smallest move to fill it. The draft may still be saved. An override never makes an unchecked spec executable.

The last box — Durable writes — is a commitment checked before the handshake. It does not claim that the write already occurred. It confirms that the ADR + domain-model targets are resolved. It also locks in the write → read-back → completion-record protocol for the atomic-write step (curdle.md § Atomic write). The read-back verification and visible completion record occur during that step. Note the hallouminate-absent fallback clearly, never silently.

These checklist items match the gates in Mold’s machine-readable gate model. See gate-graph.md. A passing fork_taste_test_passed verdict opens the typed planner stage. A stale, partial, contradictory, or blocker-bearing verdict keeps typed planning closed. A test compares this checklist with the model nodes. Edit both sources together. Render the flow with python3 skills/mold/scripts/mold.pyz gate-graph.

These are not soft suggestions. They hard-block a runnable handoff until addressed; a draft records the holds:

  • 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 radius low | medium | high from semantic caller search and tilth_deps when available. A high verdict — 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 carry an approved scope-audit row. See the full procedure in § Agent-introduced scope below. Curdle is the single chokepoint because downstream skills trust the resulting frontmatter and do not re-block.
  • Entity-referent binding: bind every identity noun to a code referent or mark it NEW ENTITY. Resolve each ALIAS; do not only note it. See the full procedure in § Entity-referent binding below.
  • Non-goals audit: every Non-goals bullet traces to a user-stated out-of-scope item or is marked [AGENT-INTRODUCED]. Full procedure in § Non-goals audit below.
  • Goal coverage: every G-n goal clause from the bounds pass is covered by an Acceptance criterion or carries an explicit disposition. At least half the clauses ship. The handshake prints the narrowing delta. Save approval does not waive this gate. Full procedure in § Goal coverage below.
  • Fork taste test: Require a fresh-context verdict before decomposition. Dispatch the verdict to a read-only reviewer (taste-test) at default / medium, resolved through ../../cheese/references/agent-resolution.md. The verdict must match the draft SHA256. It must cover each settled consequential decision exactly once. It cannot contain contradictions, orphaned decisions, unsupported assumptions, or acceptance gaps. When the ledger pins a goal, the draft’s Problem statement must contain it unchanged, compared case- and whitespace-insensitively, or the verdict fails as goal-drift. Hand the reviewer the ledger’s goal and goal_clauses with the draft, so its Drift lens judges the spec against the original ask and not against the already-narrowed draft. Mold permits the initial verdict and two corrective rounds. A third failure stops the process. Before the reviewer dispatch, run taste-test --precheck on the draft and ledger. Fix every mechanical gap it reports; the pre-check consumes no correction round.
  • Spec format gate: Run validate-spec --strict on the draft before Curdle extracts it. The command must exit with status 0. Curdle writes only the current hardened format. It does not use the legacy read grace period.

The agent-introduced scope, non-goals, entity-referent, and follow-up audits below populate one table, presented once, before execution. Each row carries a default disposition. Mold may save the displayed defaults without a confirm; the user can veto them. Rows marked needs your verb require a decision before execution. A row needs its own explicit verb only when it fires a leverage trigger (../../cheese/references/routing-policy.md § Leverage triggers) or is an unresolved ALIAS / NEW ENTITY binding. A row fires a trigger when the term, bullet, or noun it names would itself fire one of the eight ids if kept: an auth knob fires auth, a new export fires contract, a new domain fires new-slice. Such a row renders needs your verb in its Default cell. Saving the draft never settles it. The grep and semantic search that populate the rows still run; the per-row approval round does not.

Scope audit:
| # | Kind | Term / bullet / noun | Source | Default | Leverage |
| --- | --- | --- | --- | --- | --- |
| 1 | scope | <noun> | agent / citation | keep | — |
| 2 | non-goal | <bullet> | agent | keep | — |
| 3 | entity | <noun> | search | Bound <referent> | — |
| 4 | follow-up | <unit: member, member> | dialogue | non-goal only | — |
| 5 | scope | <noun> | citation | needs your verb | contract |
| 6 | entity | <noun> | search | needs your verb (ALIAS <referent>) | — |
Review the defaults; Mold may save the draft. Rows marked `needs your verb` block execution until you name a verb for each.

Finalization runs the table as the execution backstop: every needs your verb row and unresolved coherence box is a named entry in execution_holds:, and scripts/mold.pyz finalize blocks ready while the list is non-empty. It remains the chokepoint that downstream skills trust (RC3).

Before saving a draft, audit it for features the user did not type the name of.

Procedure:

  1. Extract distinguishing nouns from the spec’s Approach, Decisions, and Interface sketches blocks. Include proper-noun-like terms, library names, algorithm names, Greek parameter letters, config keys, and knobs.

  2. For each noun, grep the prior user turns for a literal mention. Search only the user’s typed messages, not agent or sub-agent output.

  3. Any noun with zero hits is agent-introduced. Mark it [AGENT-INTRODUCED] inline in the draft and add a scope row to the scope audit table. Default keep when the noun restates the user’s ask or binds to a code referent, follow-up when it names new work, drop otherwise.

  4. Saving the displayed defaults needs no confirm. A row that fires a leverage trigger needs its own verb before execution: “keep ”, “drop ”, or “make a follow-up”. “Make a follow-up” records a candidate within Decided. This choice does not create an issue or other artifact.

  5. When a direction is dropped, write a rejection record only when the user typed drop or explicitly confirmed a displayed drop default. Do not write one for an unchallenged default. Write it to .cheese/.out-of-scope/<slug>-NNN.md. A direction can be an approach, design knob, or named feature that the user declines. Use the format in curdle.md § Rejected-directions store. Do not make a rejected direction a follow-up candidate. Add explicit deferrals to the follow-up candidate set instead.

  6. Do not silently promote a flagged term from a research citation into a design knob. This applies to briesearch sub-agent citations, fetched docs, and MCP results. 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. For example, a Tavily snippet mentioning “X or Y” became a shipped [setting].knob = "x" | "y" flag. The flag passed through curdle → cook although the user never typed the distinguishing noun. The grep heuristic detects this type of drift early.

Finalization is the execution 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>, …]. This record preserves the paper trail.

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:

  1. For each Non-goals bullet, grep prior user turns for a statement that puts the item out of scope. Search only the user’s typed messages. Examples include “don’t bother with X”, “leave Y alone”, and an explicit deferral.
  2. Any bullet with no such user statement is agent-introduced. Mark it [AGENT-INTRODUCED] inline and add a non-goal row to the scope audit table with default keep. Non-goals that the bounds pass authored as [AGENT-DECIDED] are agent-introduced by definition and enter the table the same way. The user keeps, drops, or rewords it by confirming or editing the row.
  3. Record approved-but-flagged non-goals in the same agent_introduced_scope frontmatter list, so the paper trail survives downstream.
  4. 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. It is the non_goals_audit node in the gate model (gate-graph.md). Populate its rows as non-goals are proposed; present them once, in the scope audit table. Finalization reruns it as the execution backstop. An unresolved row leaves the draft saved but blocks a runnable handoff.

The noun-level gates catch additions. This gate catches subtractions. A spec can keep the goal sentence verbatim, pass every noun audit, and still ship one quarter of the ask. The remaining three quarters vanish through a narrow Acceptance section, never through a Non-goals bullet. The goal-coverage gate makes every cut visible and puts a floor under it.

Procedure:

  1. Decompose in the bounds pass. Split the pinned goal into 2–6 outcome clauses, G-1 … G-n. Each clause names one observable outcome the user asked for. Print the clauses under the Goal: ledger line in round one, and repeat them each round. Only an explicit user fork adds, removes, or rewords a clause. Record them in the ledger JSON as goal_clauses: [{id: G-n, text: ...}, ...].
  2. Tag the draft. Every Acceptance line that delivers a clause carries its tag, for example - AC-2: WHEN ... THE SYSTEM SHALL ... (F-1, G-2). A clause the spec does not deliver carries its tag on exactly one disposition line instead: a Non-goals bullet, a Deferred follow-ups entry, or an Open questions item marked [TBD]. Acceptance wins when a tag appears in more than one place.
  3. Run the check. python3 skills/mold/scripts/mold.pyz taste-test --precheck --draft <draft> --ledger <ledger> fails goal-coverage:G-n for each clause with no tag in any of those four sections. It fails goal-coverage-cap:<covered>/<total> when fewer than half the clauses are covered by Acceptance. Both codes also fail the digest-bound verdict.
  4. Print the narrowing delta. Before offering Cook, run python3 skills/mold/scripts/mold.pyz taste-test --coverage --draft <draft> --ledger <ledger> and print one line: Original ask: G-1..G-n. This spec ships: <covered>. Deferred: <G-n (follow-up)>, <G-n (non-goal)>, <G-n (tbd)>. The delta is the visible cut list. A spec with no deferred clause prints Deferred: none.
  5. Respect the cap. When goal-coverage-cap fires, the spec is a slice of the goal. Do not proceed. Put one fork to the user: re-pin the goal to the slice (the ledger Goal: line and clauses change through an explicit user fork), or widen the spec until at least half the clauses are covered. Never rename a slice as the whole.
  6. No override. Save approval accepts unchecked coherence items. It does not waive an uncovered clause or the cap, for the same reason it does not waive a leverage row: downstream skills trust the spec and never re-check.

The disposition the spec records on each deferred clause feeds the scope audit table. A non-goal disposition enters as a non-goal row; a follow-up disposition enters as a follow-up row. Record the final disposition map in spec frontmatter as goal_coverage: {G-1: covered, G-2: follow-up, ...} so the paper trail survives downstream.

This gate exists because the agent-introduced-scope and non-goals audits ask did the user type this. Neither asks did the spec keep everything the user typed. Agents narrow an ask by building the first tractable quarter and describing it as the whole. The goal sentence survives, the nouns all trace, and the Acceptance section is one quarter the size it should be. The coverage matrix reads the cut from the Acceptance section and the cap refuses a spec that is mostly cut.

Follow-up disposition (inside the non-goals audit)

Section titled “Follow-up disposition (inside the non-goals audit)”

Before a runnable handoff, dispose of every follow-up candidate in one batch: the follow-up rows of the scope audit table. This process extends the existing Non-goals audit gate. It does not add or rename a gate. The default destination is non-goal only; every other destination is a user edit on the row.

  1. Group related candidates into independently deliverable units. Each unit is one follow-up row whose cell lists its members. The displayed grouping is a draft default. The user splits or merges units by editing the row.
  2. Search GitHub Issues and Hallouminate roadmap goals when discovery is available. A semantic match is surfaced on the row as a recommended link #<id>, not adopted as the default: the default destination stays non-goal only, and the user adopts the link by editing the row.
  3. Recommend one destination per unit:
    • non-goal only — keep the scope boundary, create no follow-up artifact, and offer no action choice;
    • GitHub Issue — use for discrete, independently actionable work;
    • roadmap goal — use for coordinated, milestone-scale, or dependency-linked work;
    • local issue draft — use when publication is not desired or available.
  4. The default is non-goal only and needs no approval to save. The user must select any external create/link now action. An edited destination can also remain prepared without publication.
  5. Record accepted units for Curdle. Keep rejected design directions in the rejection store. Do not add them to this batch.

Mold displays grouping, semantic-match suggestions, destination, and action defaults. The user may edit them. No external create/link action runs without the user’s selection. Omit this batch when no candidates exist.

Record each candidate within Decided as [FOLLOW-UP?]. Include its summary, source, and rationale. A follow-up candidate is dialogue state only. It does not create an artifact or future commitment.

Curdle writes local artifacts first. After the user selects a follow-up action, it publishes that approved follow-up. It reconciles state and references into the durable spec before any implementation handoff.

Before saving a draft, audit it for identity/ownership-role nouns. These nouns identify roles that hold, own, span, or claim state or lifecycle. Examples include owner, run, session, claim-holder, coordinator, worker, lease, tenant, and lock-holder. The role triggers the audit, not a fixed word list. Flag domain-specific identities. Do not flag plain value nouns such as formats, algorithms, or config knobs.

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:

  1. Extract identity/ownership-role nouns from the spec’s Approach, Decisions, and Interface sketches blocks.

  2. Search each noun and classify it Bound / ALIAS / NEW ENTITY per the table above.

  3. Add one entity row per identity-role noun to the scope audit table. A Bound row needs no approval; an ALIAS or NEW ENTITY row blocks until resolved. The binding detail reads:

    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 |
  4. An unresolved binding blocks execution, exactly as an unapproved [AGENT-INTRODUCED] noun does. A search hit does not resolve the binding. Determine whether the design’s usage differs from the code’s existing meaning of the same word. If it differs, settle the aliasing before a runnable handoff.

This gate is the referent-level sibling of Agent-introduced scope. That gate asks did the user type this noun. This gate asks does the code have it, with the assumed shape. One example shows why the gate exists. A fully handshook spec declares its goal-claims “owned by the run/session”. The code’s run names one task dispatch, not a coordinator session. The aliased noun then reaches a re-age blocker and a cure-pass-2 design decision that belongs 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}, …]. Use a list of binding records. Preserve the referent and promised file:line citation in this record.

When coherence items are unchecked, ask the user for approval to save the draft anyway. Any clear affirmative reply works; no magic phrase is required. The approval permits one durable save. It does not grant execution authority and does not disable later gates. Record the override and every unchecked item in the spec frontmatter (gates_overridden). It accepts every other default. Finalization returns saved-not-ready with a save-only hold; it must not return ready bound refs until the requirements are cleared through a fresh user decision and updated spec. The override does not waive scope-audit leverage rows, unresolved identity bindings, stale references, invalid landing IDs, an uncovered G-n clause, the goal-coverage cap, or a user do-not-implement hold. Taste review remains useful design evidence, not a required Cook reference. Downstream skills must not reinterpret save approval as execution authority.

The agent checks the design’s coherence, and it is the only execution gate. A Cook request from the user shows intent but cannot waive a failed check. Draft writing needs no execution key.

Agent-invoked mini-spec mode — full procedure

Section titled “Agent-invoked mini-spec mode — full procedure”

Read this when /mold uses agent-invoked mini-spec mode. This mode is the tier-1 escalation from /cheese, per SKILL.md § Agent-invoked mini-spec mode. It provides the full procedure, mini-spec schema, and ## Provenance rules.

  1. Derive slug from the user’s ask (kebab-case noun-phrase, ≤ 4 words). Check the leverage triggers in ../../cheese/references/routing-policy.md first. A mini-spec always carries leverage: []. When any trigger fires, refuse the mint, name the trigger ids, and return the ask to /cheese for /mold’s user mode. 2. Write the resolver-owned <spec-path> with the mini-spec schema below. Resolve it: run python3 skills/mold/scripts/mold.pyz artifact-path specs <slug> and read path from its JSON reply. Never hardcode a repo-local spec path: the resolver anchors it at the durable corpus, matching the Curdle step.
  2. Validate the minted spec with python3 skills/mold/scripts/mold.pyz validate-spec --strict <spec-path>. Stop on a nonzero exit; no malformed or legacy-compatible artifact advances to Cook.
  3. Return the resolved spec path to /cheese. A saved draft is not a Cook command. After the spec validates, show it and ask one direct Cook question through ../../cheese/references/ask-user-question.md. When the user selects Cook, pass the spec path to standalone Cook. Do not require a pointer or planner for a clear mini-spec. Otherwise keep shaping without dispatch.
  4. Append --hard to a selected Cook command when the user passed the flag. Plate alone runs the gate.

The full coherence checklist does not fire in this mode. Saving the mini-spec needs no user approval; Cook still needs the user’s request. 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 or /briesearch synthesis. Record that synthesis in ## Provenance. Never add any other noun. The mini-spec records only the user’s request. It never records the agent’s interpretation.

Mini-spec mode always writes shape: single, so landing.layers stays []. Do not add an inline # comment inside the landing block. The front-matter reader keeps the comment as part of the value. An early in-dialogue curd uses the same body shape but source: mold-curd-mini-spec, a required ## Parent section, and the procedure in early-curds.md.

---
slug: <kebab-slug>
status: draft
source: agent-mini-spec
created: <YYYY-MM-DD>
confidence: <low | medium | high>
intent: <one-sentence restatement of the user's ask>
blast_radius: low | medium | high
leverage: []
inputs: <one-line>
outputs: <one-line>
agent_resolution: []
landing:
shape: single | orthogonal_flat | stacked_linear | diamond_stack
layers: []
per_layer_green: required | tip-only
review_fixes: fold | top-up
verification: <one-line: the obvious check>
---
## Contract
<one paragraph: behavior change, scope boundary>
## Grounding
Add exactly one row for each probe. Record the real outcome. Never invent a row.
| Probe | Outcome | Evidence |
| --- | --- | --- |
| wiki | <hit \| miss \| unavailable> | <wiki path and one-line finding, or what was attempted> |
| explorer | <hit \| miss \| unavailable> | <explorer digest path and one-line finding, or what was attempted> |
## Acceptance
- AC-1: <verifiable check 1>
- AC-2: <verifiable check 2>
## Acceptance demonstration
Optional on a Quick-tier mini-spec (`source: agent-mini-spec`); include it when a realistic end-to-end check is not obvious from `## Acceptance`. Required on an early curd (`source: mold-curd-mini-spec`). When present, `validate-spec --strict` checks it: behavior work fills all seven rows, each non-empty, and non-behavior work writes one line instead: `n/a: <reason>`.
Include one plausible false success and how the check rejects it. Keep rows independent of the implementation.
| Field | Value |
| --- | --- |
| User task | <what the user wants done> |
| Input | <concrete input> |
| Entrypoint | <command, API, or UI the user touches> |
| Expected result | <observable outcome> |
| Real boundaries | <real systems crossed, not mocked> |
| False success | <plausible wrong result and how the check rejects it> |
| Evidence | <artifact or output that proves it> |
## Test Contracts
Optional. Include this section only when the spec benefits from it.
| Acceptance ID | Interface referent | Outermost stable seam | Expected failure | Mode | Interface version | Matrix rows |
| --- | --- | --- | --- | --- | --- | --- |
| AC-1 | <public interface> | <existing outer seam> | <expected failing assertion> | tracer | | |
| AC-2 | <public interface> | <existing outer seam> | <expected failing assertion> | contract-matrix | <ratified version> | <row 1><br><row 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: <absolute report path returned by research-layout>

Mini-spec mode writes shape: single unless the user named a shape.

## Provenance appears only when /cheese reaches tier 2 before falling into tier 1. This occurs when /culture or /briesearch supplies context absent from the original input. Omit the section when tier 1 fires on the raw input.

Mold owns the dialogue and the approval state for every research request. Apply these rules to each /briesearch call:

  • Send invocation: sidechain in the request. A missing value defaults to top-level, which releases the run from Mold’s control.
  • Send allow_question: false. Mold asks every user question itself.
  • Reuse the Mold parent slug for the request. Do not derive a second slug. The parent slug also names the research artifact.
  • Record the full absolute report path returned by research-layout in the artifact: field. This link preserves the citations. It lets /cook or any later skill read them again without new research.
  • Map a don't know result to an open hypothesis. Record no outcome. Keep Curdle blocked until new evidence or an explicit [TBD] decision settles it.
  • Omit artifact: only when /briesearch reads local code patterns and writes no durable file.

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.

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 first runs the bounds pass from SKILL.md Flow step 1 and opens the per-round decision ledger. For a concrete ask (“I want to add X”, “Should we do X”) the pass is one ledger line: goals and non-goals as the agent read them, marked [AGENT-DECIDED]. It becomes a question only when the goal is genuinely unknown or a leverage trigger fires. Then Shape/Grill receives the scope.

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: the dialogue states one problem statement and one concrete pain point, and the ledger pins that statement on its Goal: line.

Job: anchor every claim to evidence from code, docs, or prior research. When the user uses overloaded terms (“account”, “session”, “user”), pause and ask a canonical-term question. At the curdle atomic step, write resolved terms to the session’s durable glossary at .cheese/glossary/<slug>.md. See curdle.md § Durable glossary. Downstream skills (/cook, /age, /press) can read these terms for naming consistency.

On Ground entry: after the Hallouminate probe, resolve and load the project’s cumulative domain model through the Mold bundle command:

python3 skills/mold/scripts/mold.pyz domain-model-target \
--probe <unavailable|no-match|match> \
[--corpus repo:<repo>:wiki --model <present|absent|unknown>]

Use the domain-model probe transport in ../../cheese/references/optional-plugins.md. Do not derive these arguments from Ground’s topic-search hit or miss.

Pass unavailable when Hallouminate is not loaded or the probe failed. Pass no-match when the listing completed but contained no repo:*:wiki corpus. Pass match with the exact corpus name and its model status when the listing found one. The command accepts only explicit probe results and does not import MCP machinery. Its JSON contains backend, string location, and wiki_reachable. Complete the read-probe cascade before any write: wiki, tracked docs/domain-model*, then <project_corpus_root()>/domain-model*. A listed wiki corpus does not win without a confirmed model. An existing file-store model wins over a wiki corpus without a confirmed model. The resolution mirrors the adr_target() pattern in adr.md § Resolution. It is dynamic, and the existing model always wins. If the probe is unreachable, degrade to “not loaded” and report it. Never block Ground because the probe is unreachable. False means no wiki probe occurred because no hook existed or the hook raised. In that case, announce “domain model not loaded from the wiki”. Do not present the file-store result as the whole picture. The model is cross-session memory. The per-slug glossary is the branch-local handoff. Challenge immediately when a user term conflicts with an existing model entry. Ask: “the model defines X as …, you seem to mean Y — which is it?” Challenges are LIVE here. Defer model writes to the approval gate. Curdle owns the write; see curdle.md. Never write 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.

Job: turn a grounded problem into 2+ candidate approaches with trade-offs. Always include Do Nothing. Present lettered options (A/B/C/D) for the user to select, behind a fork card (fork-questions.md). The user chooses consequential forks (the leverage line in ../../age/references/voice.md); do not settle them. Settle every fork below the line and log it. Give a one-line rationale for each option, not a verdict. Validate Cycle every critical assumption behind an option. Score options by the information they leave behind. Prefer the option that reduces the next maintainer’s required knowledge or makes that knowledge more obvious.

Exit when: the user picks one option (→ Sketch). Return to Explore when no option survives.

Job: place the change in the architecture at 10,000 ft. The output is the Placement block that fills ## Interface sketches (curdle.md § Spec template):

  • slice: which domain slice owns the change, or NEW SLICE (a new-slice leverage trigger)
  • spine step: where it sits on the request path (entry → workflow → domain → infra), or none
  • public interface: one signature per new or changed crust export, nothing else
  • private: what stays behind the crust, as a one-line list of responsibilities, not signatures
  • crust delta: new exports, cross-slice imports, or contract changes, or none
  • arrows: any dependency direction the change adds, checked against ../../cheese/references/sliced-bread.md

Run the shape check (shape-check.md) before drafting when the change touches multiple modules or introduces a new public interface; print its summary block first. No block, no sketch. Single-module, internals-only sketches note “shape check skipped: single-module change”; that skip line satisfies the “no block, no sketch” precondition, as shape-check.md § When to skip defines for every sanctioned skip. Do not write bodies, helper signatures, or internal pseudocode in Sketch; those belong to /cook. A non-empty crust delta is a consequential fork.

Acceptance notation (EARS): for every public interface line, 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.

Language default: when a sketch introduces a component with a free language choice, default to the repository’s incumbent memory-safe typed language (Python under a strict type checker, or TypeScript in strict mode). When the incumbent is C or C++, treat Rust as the default for new components. Choose Go only for standalone tooling where diff uniformity dominates. Treat Elm and Gleam as niche. Reviewer familiarity and model generation accuracy dominate review speed; cross-language review throughput itself is unmeasured. Record any departure as an [AGENT-DECIDED] item for Grill.

Exit when: the Placement block is complete, every acceptance criterion uses EARS form or has [prose-fallback], every cross-module call uses public interfaces, not internals, and the shape-check verdict is recorded or explicitly skipped under the gate above.

Job: stress-test the chosen approach and sketched interfaces. Grill runs on consequential forks and high blast-radius options only. Tag each grilled item with what it moves: an acceptance criterion, a public seam, or a non-goal. An item that moves none of those, or that sits below the leverage line, is not a user fork: batch-report it as upheld with a one-line steelman, or record it [AGENT-DECIDED]; either way the ledger carries its vetoable alternative (../../age/references/voice.md). Such items never become a user turn. Use one grilled item per turn for consequential items. Two exceptions apply: the clean-steelman batch below, and independent, already-explained forks in one review-canvas submission (review-canvas.md). For each consequential decision, produce at most a steelman + tension statement. Then present a user fork behind a fork card (fork-questions.md): uphold / amend-as-proposed / user’s own call. Invoke the question primitive in ../../cheese/references/ask-user-question.md. Use a real user turn. Do not render an A/B/C/D prose block and answer it yourself. Never self-issue verdicts for items that change the design. When the steelman fails cleanly and grilling finds nothing, you MAY batch-report items as upheld. When grilling produces an amendment, ask through the same primitive before adding the amendment to the ledger. Traverse decision branches and contract corners. Pause for a Validate Cycle when an unverified assumption appears.

Exit when: every branch and contract corner is touched and agent confidence ≥ user confidence.

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 BEFORE chasing hypotheses. Techniques include a failing test, curl/CLI script, headless browser, replay, bisection harness, or differential loop. The chosen loop becomes the Reproduction block in the bug-shaped spec. Thus, /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.

explore, ground, shape, sketch, grill, diagnose, explain [fork-id], validate <hypothesis>, prototype <question>, curdle, pause, enough, plus the tier knobs quick, light, and full (tiers.md). Honour these immediately.

explain [fork-id] re-renders the open fork, or the named fork, with more context (fork-questions.md § Explain more).

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.

Marker Meaning
[?] Agent uncertain; needs validation
[TBD] User uncertain; decision deferred
[BLOCKED] External dependency unresolved
[CONFLICT <id>] Codebase contradicts a stated assumption

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.

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.

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.

  • 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.

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.

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 decision

An open cycle (no answer:) blocks Curdle until it settles or the user accepts it as [TBD], exactly like a Validate Cycle.

Use the bundled review canvas when visual artifacts or browser interaction help resolve Mold forks.

  1. Publish the review document with python3 skills/mold/scripts/mold.pyz review publish --state-dir DIR --input FILE [--base-revision N]. Read warnings in its output. See Review document.
  2. Start python3 skills/mold/scripts/mold.pyz review serve --state-dir DIR --port 0 and give the returned private URL to the user.
  3. Read submitted snapshots with python3 skills/mold/scripts/mold.pyz review poll --state-dir DIR --after CURSOR --timeout SECONDS.
  4. Reconcile each exact question and option identifier into the decision ledger. Fold notes and each pin’s anchor and text into that ledger.
  5. Publish a new revision when the review document changes. Never replace dirty feedback silently.
  6. When feedback carries end_session: true, run python3 skills/mold/scripts/mold.pyz review close --state-dir DIR and stop polling. This flag marks the user’s choice to end the session, not approval.
  7. Stop the server with python3 skills/mold/scripts/mold.pyz review close --state-dir DIR when the review ends for another reason.

Use this mode only when the user asks to open the canvas from another tailnet device. If tailscale is missing, Self.DNSName is empty, or the tailnet has no HTTPS certificates, tell the user that remote access is unavailable. Then serve without --trusted-host and give the loopback url, or continue the review in conversation.

  1. Read the node name from tailscale status --json at Self.DNSName, without the trailing dot.
  2. Add --trusted-host NODE.TAILNET.ts.net to review serve.
  3. Give the user the tailscale_serve command from the launch output. Give the user the remote_url from the launch output.
  4. Tell the user that the tailscale_serve command replaces an existing HTTPS mapping on port 443. To keep that mapping, add --https=PORT to the command. Then add :PORT to the host in remote_url.
  5. After the review closes, tell the user to remove the mapping with tailscale serve --https=PORT off.

The server still binds 127.0.0.1 and never starts or stops tailscale serve itself. It accepts the trusted host only with X-Forwarded-Proto: https and an https:// origin. It refuses every request that carries Tailscale-Funnel-Request, so Funnel never exposes the canvas. The launch token still protects every request. The tailnet needs MagicDNS and HTTPS certificates.

The canvas requires only questions. Every other field is optional, and the canvas hides a view when its field is absent.

Field Shape Canvas use
questions [{id, prompt, meta?, selection_mode, recommended_option_id?, depends_on?, options: [{id, label, tradeoff?}]}] Open fork cards in the conversation rail
requirements [{id, text, status, fork_ids?}]; status is settled or draft Full EARS text and linked forks in a persistent, scrollable pane outside the shape tabs; drafts list before settled entries
settled_fork_ids list of question IDs Every decision the agent has reconciled so far; cumulative, and republished in full each round, not only the ones settled in this revision
goal, goal_emphasis strings Page title; the emphasis substring shows in the accent color
tier, stage strings (stage: bounds, shape, sketch, or decision map) Eyebrow; decision map opens that view first
summary, agent_status strings Agent message and status line above the forks
ledger [{label, tone?, text?, items?: [{id, text}]}] Ledger view; the label asking and tone accent use the accent color; the label agent-decided and tone dim mute the row’s items
placement {title?, badge?, rows: [{key, value, highlight?}]} Placement view; title defaults to “Placement”; multi-line values align under the key
artifacts existing artifact list Diagram view; without artifacts the view shows scratch Mermaid and Excalidraw panels
gates {items: [{label, state}]} (met, current, open, or na) Gates view
decision_map {settled: [{id, text}], open: [{id, text, marker?}], verdict?: {title, lines}} Decision map view
trail [{label, state, note?, position}] (answered or waiting; before or after) Settled and blocked forks around the current fork
revisions [{label, note?}] Revisions popover
shape_note string Note under the shape views

Text in ledger, decision_map, and summary renders `code` spans as chips. Document text always renders as inert text, never as HTML.

Publish the entire current EARS requirement list each round, including settled and draft entries. Keep stable requirement and fork IDs. Link each requirement to its relevant fork cards through fork_ids. A linked fork shows its prompt and, when not answerable, its waiting or dependency-error state; a settled fork shows its ID. An unresolved link remains visible.

A question’s optional depends_on lists prerequisite question IDs. The question is answerable only when every prerequisite is in settled_fork_ids and absent from questions. Local selection, autosave, submission, and restored feedback never settle a fork. The browser shows waiting and dependency-error questions but disables their controls, shows no restored answer on them, and excludes their answers from feedback. Missing references and malformed dependencies show a dependency error. Cycles remain waiting. The agent reconciles feedback and publishes a new revision before dependent forks become answerable.

Each review publish output has a warnings list. A warning never blocks the publish, so the revision is stored. A warning names one of these problems:

  • a depends_on value that is not a list, or an entry that is not a non-empty string
  • a depends_on reference that is not an open question or a settled_fork_ids entry
  • a prerequisite that is open in questions and also in settled_fork_ids
  • a depends_on cycle among open questions
  • requirement IDs from the previous revision that this revision does not have

The list is empty when the document has none of these problems. Read warnings after each publish. If the list is not empty, correct the document. Then publish the corrected document as a new revision.

Independent, already-explained forks can share one batch submission. Do not batch a dependent fork before its prerequisites settle. Legacy documents without these fields retain their existing rendering and answer behavior. Desktop requirements sit above shapes beside the conversation. Narrow screens stack requirements, shapes, and conversation in separate, non-overlapping scroll panes. Each pane keeps a usable minimum height. The page scrolls on short screens. Legacy documents keep the phone sheet.

frontend/mold-review/examples/ holds three documents: 01-bounds.json, 02-sketch.json, and 03-decision-map.json.

A submission carries answers, notes (the composer text), pins, annotations, view, scene, artifacts, and mermaid_source. Each pin is {id, anchor, text}, where anchor names the part of the canvas, for example placement › public. annotations repeats the pins as numbered plain text. end_session: true means the user chose send & end and wants the Mold session to stop after this feedback.

Autosave only preserves a working copy. Send to agent creates feedback, not approval. Waiting and dependency-error questions never appear in submitted answers, even if an earlier working copy holds an answer.

Browser feedback never satisfies the taste gate, typed-plan gate, or coherence self-check.

The canvas is optional. It is a loopback-bound review aid, not an approval mechanism. It must not request approval, bypass the taste gate, bypass the typed-plan gate, or bypass the coherence self-check.

Run this before drafting in Sketch mode. Also run it whenever discussion in any mode depends 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.

  • 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 describe the change’s shape and bound its blast radius. Upstream identifies who breaks if you change it. Downstream identifies what you could pull into the change. InlineCoder-style bidirectional inlining gives the downstream half empirical value for repo-level edits. Ignoring it leaves a known gap.

Run all three queries. Each query is cheap when the answers are small. A skipped query causes 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 serves two purposes. Its ── calls ── footer provides the cheap callee read. Do not issue a separate query.

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.

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
slice: <owning slice from the import path>
crust delta: <new exports | cross-slice imports | contract changes | none>
verdict: low | medium | high

The 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.

slice and crust delta come from the same tilth_deps answer read against ../../cheese/references/sliced-bread.md: the touched symbol’s own path names the owning slice; the importer list shows which other slices consume it. Any importer outside the owning slice that reads past its crust, any new cross-slice import, or any new export is a crust delta.

Three consumers print this block: mold’s Sketch turn, culture’s blast-radius step, and cook’s Contract step. The block shape is the same in all three; only the gate that follows differs.

A high verdict means multi-module callers, more than five importers, or a non-empty crust delta. It makes the Grill gate mandatory in mold; see handshake.md. Before continuing trade-off talk, culture must label the option [high blast radius].

When semantic source tooling is unavailable

Section titled “When semantic source tooling is unavailable”

Shape-check must not block dialogue when its preferred tools are missing. Use a sanctioned alternative when available. For shape-check specifically, do not substitute textual search. grep / rg over a symbol name counts string occurrences, not callers or importers. A guessed blast-radius verdict is worse than an unknown.

  • Callers / callees: fall back to LSP textDocument/references / textDocument/prepareCallHierarchy when 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 it at [?], not low | medium | high. A guessed verdict is worse than an honest unknown. For gating, Sketch and culture must treat [?] like high until the user accepts the gap. The Grill gate engages, and culture labels the option [high blast radius].

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.

  • The touched symbol has zero callers (greenfield) — say so out loud.
  • The change affects one private function in one file and has no exports. Sibling signature lookup still applies. You can skip dependencies and callers.
  • The user explicitly said skip the shape check.

A skipped check prints one line in place of the block, shape check skipped: <reason>, and that line satisfies the “no block, no code” precondition in cook’s Contract and mold’s Sketch. Closed non-behavior work (docs-only, appearance-only) always takes this path.

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.

Direction matters. Upstream callers identify who breaks if the seam changes. Downstream callees identify what the change can pull in. Bidirectional structural context measurably improves accuracy on repo-level edits. The existing symbol query provides the downstream half at no additional cost.

Mold picks a tier at the end of the Bounds pass (../SKILL.md Flow step 1), once the goals, non-goals, and shape-check verdict are on the ledger. Announce the tier in one line with its reason before the first fork question:

tier: quick — clarity check passed, verdict low, no open fork

The user overrides with the quick, light, or full knob at any time. Mold upgrades on its own when the evidence changes. It never downgrades silently.

Tier Enter when every condition holds Runs Skips Artifact → handoff
Quick Cook’s standalone fast-path check passes on the bounded ask (../../cook/SKILL.md § Standalone fast-path), which includes zero fired leverage triggers (../../cheese/references/routing-policy.md § Leverage triggers); shape-check verdict low, or skipped as greenfield or a single private function; no consequential fork open after bounds Bounds, one wiki probe, strict mini-spec validation Explore, Shape, Sketch, Grill, Validate and Prototype cycles, fork taste test, typed planner, full coherence checklist, ADRs, follow-up publication draft mini-spec through mini-spec-mode.md, gated by validate-spec --strict; after the user requests Cook, pass the selected spec path to standalone Cook
Light Goal is clear after bounds; verdict low or medium; at most two consequential forks; no new public seam across modules; one expected curd Bounds with G-n clauses, Ground, Shape for the open forks, Sketch only when a public seam changes, fork taste test, goal coverage and narrowing delta, agent coherence check, Curdle draft write Explore; Grill unless the user asks or a fork turns high-blast; typed planner for standalone clear work; issue-draft publication draft full spec (source: mold-handshake); after a user Cook request, pass the selected spec path for standalone Cook; Light skips the planner, so it never enters bound curd execution, which requires a planner result
Full Anything else: verdict high or [?], three or more forks, a new cross-module public seam, two or more expected curds, a Diagnose input, or the full knob The whole Flow, including early curd checks when one becomes concrete Nothing draft spec + validated PlannerResult + CurdPlan; after a user Cook request, finalize the exact scope and pass ready direct refs

A fired leverage trigger rules Quick out: the fork it names is consequential, so the ask enters Light or Full by the rows above. Leverage picks whether the user steers; the verdict, fork count, and curd count pick how much of the Flow runs.

validate-spec --strict is Quick’s write gate. The coherence checklist in handshake.md applies to Light and Full before bound curd execution. Light marks each box that does not apply as n/a: <reason>. No tier treats spec writing as Cook consent.

Upgrade the moment any condition breaks. Announce the new tier with its trigger and keep every ledger entry.

  • A consequential fork opens after Quick’s bounds pass → Light. Keep the saved mini-spec as draft until the fork is picked.
  • The shape-check verdict rises to high or [?] → Full, Grill mandatory.
  • A second module or a new public seam enters scope → Full.
  • The expected curd count reaches two → Full. The typed planner is required.
  • Cook returns next: mold on a Quick mini-spec → re-enter at Light with Cook’s failure as prior evidence.

Downgrade only on the user’s knob. Say what the lower tier skips before continuing.

  • The wiki probe and its ledger record (grounding-recorded).
  • The agent-introduced-scope check: every distinguishing noun traces to the user’s words.
  • validate-spec --strict on whatever artifact ships.
  • The user’s say on every consequential fork.
  • The leverage-trigger check: a fired trigger never lands in Quick.

/cheese enters mini-spec mode directly at tier 1 when the clarity check passes. Mold’s Quick tier writes the same validated draft without a separate approval turn. A mold intent from /cheese still enters user mode and tiers itself here. Route selection and the Cook request stay separate; the agent coherence self-check in handshake.md is the only execution gate.

Any mode can invoke a Validate Cycle. Always announce the cycle before dispatching — the announcement is part of the discipline.

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.

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.

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 /briesearch cycles 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).

  • 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”.

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-1

Open hypotheses (no outcome:) block Curdle until they settle or are explicitly accepted as [TBD].