Skip to content

/cook

When to invoke: Implement an approved spec or focused task through stale-safe source edits. Use this skill when the user says “implement this”, “cook this spec”, or “fix this bug”. Use it for /cook .cheese/specs/<slug>.md. Also use it when the user says “go” with clear acceptance criteria. Run it alone for an unambiguous task. Use --prototype when the user says “prototype this”, “go prototype it”, or “spike this out” and wants to refine the result round by round. A spec helps but is not required. Do not use it for fuzzy planning (/mold). Do not use it for no-write discussion (/culture) or review-only work (/age).


cook(spec_ref, correction = false) -> handoff(next = age | mold | done).

Cook returns next: mold for a specification failure. A fan run also returns next: mold for a stalled remediation scope, a curd that does not pass, or partial coverage.

Cook does not require a failing test first and does not load a gate receipt. For behavior work, Cook owns first acceptance coverage before Press; see references/tdd-loop.md § Inner TDD. This is a reported obligation, not a gate. For documentation, refactor, test, or appearance work, change that surface and verify it directly. Use correction = true only for an active Press finding or coverage_gap; see references/press-loop.md. Do not weaken an existing test.

Run python3 skills/cook/scripts/cook.pyz wheypoint-resolve --ref <slug>. authoritative uses the record; its working_context is the first batched tilth_read. not-found proceeds cold; legacy shows its source and slug, then proceeds. gated, ambiguous, and error stop and show the payload. Show advisory stale-commit and grounded-path-missing findings. Keep its record.revision_id as <base> (§ Base revision).

Accept a pasted spec or issue, focused acceptance criteria, or an unambiguous task. Read explicit spec paths verbatim. Resolve a bare slug to path from python3 skills/cook/scripts/cook.pyz artifact-path specs <slug>. A Mold spec path or finalized direct inputs enter through § Mold-to-Cook ingress. Flags:

  • --auto chains /age → /cure after the in-Cook Press loop.
  • --prototype runs a plan → spike → check loop, then stabilizes; read references/prototype-mode.md.
  • --hard propagates through /plate.
  • --open-pr lets terminal /plate publish. Auto mode never adds this flag.
  • --resume <slug> resumes a typed fan handoff and its referenced artifacts.
  • --result <path> runs a ready Mold result.
  • --spec <spec-path> names the selected Mold spec. A plan whose dependencies cross landing.layers is refused before coder dispatch.

Optional context payload:

  • handoff_context.wiki_hits carries {page, line, why} entries from the repository wiki corpus. The key is optional, and its default is absent. Reject an entry that omits page, line, or why. Show every accepted hit in the Contract step so the user can challenge a stale decision; prefer these decisions over an invented approach. ../cheese/references/handoff-gate.md defines the payload.

Read references/auto-mode.md, references/fan-pathway.md, and ../cheese/references/formatting.md for these policies.

/cook bypasses /mold only when the inputs, outputs, scope, and verification are clear. The task must name a bug or call site in one or two files and have a failing test or an expected-output check. No leverage trigger may fire; see ../cheese/references/routing-policy.md § Leverage triggers. Derive a slug, then restate the Contract. Route the task to /mold if an ambiguity check fails.

  1. Contract — Confirm behavior, non-goals, scope, and gates. Print the shape-check block from ../mold/references/shape-check.md inside the Contract, or the line shape check skipped: single-module change per shape-check.md § When to skip. No block, no code. If .cheese/glossary/<slug>.md exists, use its canonical terms.
  2. Implement — Write the test first where it fits; no gate requires it. For non-behavior work, change only the applicable surface.
  3. Validate — Run the relevant quality gates again. Read the complete gate output; for non-behavior work, verify the requested path.
  4. Taste-test — Use a fresh-context review for multi-file or public-surface diffs. Otherwise use an inline review, limited to two rounds. Read references/tdd-loop.md for details.
  5. Press loop — For behavior work, Cook dispatches a fresh-context Press agent; no menu. Read references/press-loop.md. Non-behavior work skips this step.
  6. Hand off — Write the package report and slug, then route to /age → /cure.

/cook selects one of three shapes from the typed planner result. Read references/fan-pathway.md for topology and lifecycle.

Fast path. Use the single-coder path for one low- or medium-blast-radius curd.

Curded. Require a bound spec_ref, planner_result_ref, plan_ref, and exact MoldCookCoverage from a ready Mold finalization. The host validates them before execute_bound_plan dispatches any writer. Run cook(CurdPlan) → reviewer(age) with confirmed diagnosis and CureDiagnosisBinding through the progress-aware fan state machine until clean, stalled, or blocked. Each curd’s Cook loop runs its own Press loop. The barrier runs Cook’s integrated acceptance check on the merged tip. No global post-merge Press runs. Incomplete fan work never emits next: press; stalls route to Mold remediation planning.

Un-curded. Keep small work in the single-coder path. For big work, ask “12 ACs -> 5 curds, 2 waves, up to 25 agent dispatches. Go?” unless --auto. Keep waves at a maximum of four.

Use python3 skills/cook/scripts/cook.pyz worktree teardown for cleanup. Propagate --auto through dispatched phases.

Fan mode records its quality-debt comparison before any curd cooks; bare mode records it on the pre-change tree. references/quality-gates.md defines exact capture, classification, intentional-RED exclusion, and baseline-artifact rules.

For source changes, follow code-intelligence-routing.md and harness-portability.md. slash commands are host renderings, not the control model; invoke the equivalent installed capability.

Run only existing project commands. Run the most relevant tests for the changed area. Also run lint, type, and build commands when the project defines them. Do not remove, skip, or weaken unrelated tests to make the change pass.

Use the baseline for gate failures. references/quality-gates.md defines the policy, the classification terms, and the baseline artifact.

references/writer-views.md generates schemas for writer-view payloads inline. The normalize and validate CLIs apply these schemas before agent-authored JSON reaches host-owned identifiers.

Use the house style in ../cheese/references/formatting.md. Use references/package-report.md to report files, reasons, checks, risks, and the next skill.

Write a minimum-shape handoff slug at the top of .cheese/cook/<slug>.md. Use the same file for the report; do not create a second file. Use this schema:

status: <canonical status field>
next: mold | age | done
artifact: <path to the upstream artifact this run consumed, or empty>
taste_test: inline-pass | dispatched-pass | revised | deferred-to-orchestrator
durable_flags: none | <one line per flag: what durable knowledge changed -> target wiki page>
baseline: none | <path to the baseline artifact — shape in references/quality-gates.md § Baseline block shape>
<one-line orientation: what cook changed>

The handback contract defines the canonical status: grammar, including ok and halt. Only next: and the additional keyed lines are specific to a phase.

artifact: names the upstream artifact that this run consumed. For a Mold route, use the approved spec path. Leave artifact: empty when this run consumed no upstream artifact. Do not point artifact: at this Cook report.

Use the canonical boundary writer when you emit this handoff for the typed fan result. Carry the result schema explicitly:

python3 skills/cook/scripts/cook.pyz write-handoff-artifact \
--slug <slug> --status <status> --phase cook --next age [--base <base>] \
--artifact <artifact-path> --orientation "<one-line orientation>" \
--payload-schema https://schemas.easy-cheese.dev/curd-result \
--grounded <path[#start-end]> \
--body-file <path to the package report body>

The writer replaces the target file. Pass --body-file to keep the package report in the same file. Without that flag, the writer emits the preamble alone and removes the report.

For a replan or a specification failure, use --next mold with the https://schemas.easy-cheese.dev/planner-request payload. references/fan-pathway.md defines the request kind for each failure class. These phase and next values route only the legacy handoff file. The validated CurdPlan and normalized CurdResult remain the live fan state.

In a fan run, read each phase’s handoff slug file from disk. Do not infer the handoff from stdout.

Set next: to the next runnable phase. Use age after the Press loop returns green, and after non-behavior work. Never publish next: press or next: cook; needs-context is a parent-owned same-phase retry. Use mold after a spec failure. Use done only at true completion. Omit taste_test: when its cost gate does not apply.

Set durable_flags: to none by default. Record only durable changes to architecture, protocols, conventions, or rationale. Record the target wiki page for each change. Set baseline: to the path of Cook’s optional comparison artifact. That artifact holds baseline-identical debt and new or changed failures from the current broad gates. Use the shape in references/quality-gates.md. The preamble accepts one physical line for each key, so never inline the mapping.

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

After you write the report and slug, use the shared handoff gate. Read its Standard forward-step menu in ../cheese/references/handoff-gate.md. The menu never offers Press. Behavior work reaches it only after the Press loop returns green. Start each option with the verb. Use these options for behavior and non-behavior work:

  • Review the change (recommended) — /age <slug>.
  • Plate it — /age <slug> --auto --open-pr: run the remaining review chain, then /plate resolves topology and publishes.
  • Checkpoint & stop — /wheypoint.
  • Stop — dispatch none.

Do not dispatch before selection. Run the selected command immediately. When the user invokes --auto, skip this gate. Take the route to /age directly.

Read references/auto-mode.md before auto mode. It defines validation, phase chains, early stops, Cure limits, publication ownership, fan isolation, and failure handling. Show each stopping report and reason; never downgrade the result. In the linear chain, Cook does not invoke /plate. In the fan pathway, the Cook orchestrator owns its own terminal /plate dispatch. Fan progress state, not the legacy phase tables, decides each next action.

A spawned phase agent does not chain forward by itself; the orchestrator controls the chain.

A terminal Age is publishable only with next: done. next: cure or a missing next halts the chain.

  • Keep changes scoped to the accepted contract.
  • Prefer existing dependencies and patterns.
  • Build for the reviewer on the first pass: references/tdd-loop.md § Reviewable by construction.
  • Keep import direction and crust integrity per ../cheese/references/sliced-bread.md.
  • Stop before a new crust export, a cross-slice import of an internal, or a schema or contract change the spec does not name. Ask the user.
  • Do not invent architecture that the spec already rejected.
  • Stop and ask the user when implementation reveals a design decision that the spec does not answer.
  • Stop and show the false premise before you write code if the spec or fast-path request uses one.
  • Do not use an incorrect approach to satisfy the request literally.
  • Apply the shared voice kernel in ../age/references/voice.md; start the report with the answer and name loaded assumptions in the contract.
  • Mark residual risk as certain | speculating | don't know.
  • Verification before status: ok: Identify the gate command, run it during the current turn, and read the complete output before you make the claim.
  • Do not use should, probably, or I think.
  • State what the gate output shows.

Resolve through agent-resolution.md. Implementation uses a coder. Taste-test uses a reviewer. Harvest and plate stay parent-owned.

Work Preferred types Permissions/isolation Minimum power Effort Fallback
Decompose the spec planner, general write (manifest only), fresh-context powerful high compatible planner, then general
Press loop coder write (tests only), fresh-context preferred default medium general, then inline in the Cook session (degraded: true)

The handoff carries the agent_resolution block. Publish a terminal Age only when it contains next: done. Stop when it contains next: cure or does not contain next.

Generated bundle command inventory: references/commands.md.

A saved Mold spec is not execution authority. Start Cook only when the user requests the selected scope and route. A standalone task, including --spec alone, may skip finalization. Spec-hold refusal: refuse a --spec run whose frontmatter has execution_holds or a do-not-implement or do-not-proceed request_directive. Refuse a non-ready --result file; a ready one passes cook.pyz validate-result before execute_bound_plan. Follow references/fan-pathway.md § Direct Mold-to-Cook ingress. Run the fresh-agent regression scenarios in references/evals.md when this boundary changes.

This file defines the full mechanics for --auto, the autonomous pipeline switch.

It defines the per-step chain, two-cure-pass cap enforcement, early-stop conditions, no-chain isolation for the fan pathway, and the final-report template.

SKILL.md’s ## Auto mode contains the one-paragraph summary and the publishable-gate rule. This file defines all behavior after that summary.

--auto uses the same cook(spec_ref, correction = false) contract as manual Cook.

For behavior work, Cook writes tests against the spec’s acceptance criteria where they fit.

For non-behavior work, Cook verifies the requested change through its own path.

Cook requires all tests and relevant gates to be GREEN before it runs the Press loop.

When correction = true, Cook limits the scope to the active Press finding or coverage_gap.

Cook cannot weaken or bypass existing tests.

  1. After Cook completes the inner implementation and green gates, Cook runs its Press loop for behavior work. See press-loop.md. Only green continues the chain. Cook writes the package-ready report. Cook then invokes /age <slug> --auto. Cook appends --open-pr only when the user supplied that flag. --open-pr is publication permission, and auto mode never creates it. Without that flag, the chain stays commit-only. Cook also forwards --hard when the user supplied it.

  2. The chain is cook with its Press loop, then age, cure, age, and so on. Non-behavior work skips the Press loop. Cook halts on halt: correction-cap and halt: coverage-gap. Press reports blocked for invalid evidence or a production change.

  3. /age <slug> --auto writes the report. It then invokes /cure <slug> --auto --stake medium+. Every Age dispatch carries the pipeline slug, --auto, and any user-supplied --hard.

  4. /cure --auto --stake medium+ bypasses the selection gate. It applies every finding with blocker, high, or medium severity. It also applies every cheap Low finding that has a contained fix. It then invokes /age <slug> --scope <touched-paths> --auto for verification. The scoped call keeps the pipeline slug, because Age needs it for its lock and its report path. Never dispatch /age --scope <touched-paths> --auto without the slug. The call also forwards --hard when the user supplied it.

  5. In the linear chain, the age → cure cycle has a maximum of two cure passes total. Pass 1 fixes the initial findings. Pass 2 fixes all findings that the second age pass identifies. After pass 2, the chain stops and writes a final summary. The chain stops even if new findings remain. This fixed two-Cure behavior does not change.

  6. In the linear chain, /cook never invokes /plate. At the chain terminal, /cure dispatches /plate for an existing pull request. For a new pull request, /cure dispatches /plate only when the user supplied --open-pr. In the fan pathway, the Cook orchestrator owns its own terminal /plate dispatch. /plate honors explicit topology. Otherwise it decides the shape without asking, also under auto.

The chain length enforces the two-cure-pass cap. Age does not enforce the cap.

Age starts in a fresh context for each pass. Therefore, age cannot count prior passes.

Each age pass writes next: from the conditions that it observes during that run.

Age writes next: cure when a medium+ finding remains.

Age writes next: done when no medium+ finding remains.

Before the terminal position, next: done causes an early stop.

For cap enforcement, the next: value is informational.

The fixed two-pass loop structure terminates the chain. Age’s own next: value does not enforce the cap.

/cook does not pass a pass-ordinal hint to age.

Age does not need to know whether it performs the first or second post-cure check.

The orchestrator owns the pass position.

  • A quality gate fails new or changed against baseline, as defined in quality-gates.md. Auto mode stops when the two fix rounds end. Auto mode also stops when the no-progress check trips. Auto mode also stops when the fix requires a design decision. Record Identical-to-baseline failures outside the cooked contract. These failures never stop auto mode.

  • The Press loop halts with halt: correction-cap, halt: coverage-gap, invalid evidence, or a production change. See press-loop.md and ../../press/references/gap-analysis.md.

  • A cure pass cannot apply any finding. This condition occurs when every selected fix breaks tests during revert-or-keep evaluation.

  • Two cure passes complete. This condition is the success path.

For every early stop, show the report from the skill that failed.

Tell the user whether the chain reached the cap or encountered a blocker.

Do not silently downgrade.

By default, each phase’s existing --auto contract chains forward in the same session.

/cook --auto runs its Press loop, then invokes /age --auto, and so on.

When /cook runs as its fan-pathway orchestrator, fan-pathway.md overrides this default.

The override applies to every per-curd or post-merge dispatch. Fan remediation uses the progress-aware state machine. Incomplete work never emits next: press; stalls route to Mold remediation planning.

Each phase sub-agent runs only its own phase.

Each phase sub-agent writes its handoff slug and stops.

It never chains forward to the next phase, although its own --auto contract documents that behavior.

The fan-pathway orchestrator loop decides and dispatches the next phase.

fan-pathway.md’s ## Phase-chain topology defines this loop.

The retired /ultracook orchestrator previously owned the same responsibility.

The spawn prompt carries the override as an explicit no-chain directive.

The directive uses /ultracook’s original wording verbatim:

“Do not chain forward to the next phase even though your auto-mode contract documents that. Write your handoff slug and stop. /cook’s fan pathway is driving the chain. Run in the foreground — do not background yourself, spawn detached processes, or defer work to a later session. If you cannot complete the phase within your context window, write a partial slug with status: halt: <reason> and stop; do not silently timeout.”

Each phase applies the directive from its own ## Auto mode section.

See ../../press/SKILL.md, ../../age/SKILL.md, and ../../cure/references/auto-mode.md.

See skills/cure/SKILL.md ## Auto mode for cure’s revert-or-defer behavior for each finding.

Cook does not duplicate this contract.

Cure owns the contract.

The skill that ends the chain prints the following summary.

On the success path, the final /age --auto prints it after the chain reaches the two-cure-pass cap.

On an early stop, the skill that identifies the blocker prints it.

Auto-mode summary
Passes: <1|2>
Findings fixed: <count by severity>
Deferred: <count, with cure-report path>
Final age: <path>
Next step: review the diff, then /plate when ready

scripts/render_generated_regions.py generates this file from the static COMMANDS manifest in src/easy_cheese/skills/cook/commands.py. Do not edit this file. Run each command as python3 skills/cook/scripts/cook.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
baseline Classify a current test-failure list against a stored baseline
findings Render an /age report’s selection table or coder brief and resolve selection verbs render-table, parse-selection, render-brief
gates Map a quality-gate scoreboard’s booleans to a readiness verdict classify
handoff Render, parse, and dispatch-split handoff preambles render, parse, dispatch
manifest-update Apply an atomic, schema-validated update to a fan-out run manifest set-phase, set-curd-status, set-post-review, set-wiring-status, check-files
milknado Probe the milknado engine seam used by parallel mode
mode Select the fan-out mode from the canonical size thresholds
normalize Normalize a typed contract payload on the host
paths Slugify, validate, resolve, and list .cheese artifact paths slugify, validate, existing, resolve, list, domain-model-target
phase-decision Decide what the fan-out pathway does after a phase sub-agent returns
pr-plan-to-branches Convert a fan-out PR plan into branch, cherry-pick, and PR commands
read-handoff-slug Read the handoff preamble back from a phase artifact
remediation-decision Apply one fan-remediation event and publish the next scope state
render-html Render a markdown report into one self-contained offline HTML file
slugify Derive a kebab-case slug and durable spec path from task text from-task
validate Validate a typed contract payload against its registered schema
validate-decomposition Validate a fan-out decomposition manifest
validate-manifest Validate a fan-out run manifest
validate-pr-plan Validate a fan-out PR-plan document
validate-result Validate a ready Mold finalization result before any writer starts
wheypoint-resolve Resolve a phase slug through the shared Wheypoint kernel (JSON out)
wiring-topo-sort Topologically sort a manifest’s wiring into ordered waves
worktree Create, harvest, and tear down isolated sub-agent worktrees create, harvest, teardown
write-handoff-artifact Write a handoff preamble plus optional body atomically; pass –grounded paths

Run these trace scenarios against a fresh task agent in an isolated fixture repository. Supply the changed Mold bundle explicitly.

  1. Give the agent a selected Mold spec and a typed planner result.
  2. Require Mold finalization to return ready spec_ref, planner_result_ref, plan_ref, and coverage.
  3. Require host validation of the retained result before any feature writer dispatch.
  4. If runner setup is needed, retain an explicit response to exact command and path limits, then successful setup evidence.
  5. Capture the input route, bound references, setup evidence, actual execution, and final artifact.

The trace passes only when the checker accepts it, the real bound validator loads every reference, and Cook executes the requested curd.

Give the agent a strict spec without planner output. Mold finalization must return saved-not-ready; no writer may run. Supply a typed planner result and the same selected scope before retrying. Changed scope needs a new user selection.

Start with a named execution hold or whole-request stop directive. Re-finalization, --auto, or arbitrary setup evidence must not clear it. Only a fresh user decision and updated bound spec can change the selection.

Tamper with a retained spec or plan digest, or pair the planner with a different plan. The bound validator must reject it before writer dispatch.

Capture each trace with python3 -m tests.python.mold_cook_agent_driver --fixture-repository <repo> --mold-bundle <pyz> --responses <json> --output <trace.json> -- <command>; it exits non-zero when the transcript check fails. Frozen fixtures cover checker regressions, but they do not replace one live captured run for this workflow change.

This file defines the full mechanics for /cook’s wave-fan pathway.

It covers the existing-handoffs guard, typed Planner-to-Cook-to-Cure execution, mode selection, publication topology, and the optional milknado seam.

It also covers worktree harvest, recovery, and resolution provenance.

SKILL.md defines the three-shape gate and wave cap.

This file defines the executable pathway after that gate.

The canonical PlannerResult and its validated CurdPlan always provide semantic authority.

A handoff file records resumable evidence.

Legacy manifest state is not live workflow state.

Never read legacy manifest state to select the phase to execute.

Before planner dispatch for an un-curded big spec, check these files:

  • .cheese/cook/<slug>.md
  • .cheese/press/<slug>.md
  • .cheese/age/<slug>.md
  • .cheese/cure/<slug>.md

If any file exists, stop and print only the files that exist.

Tell the user to run /cheese --continue <slug> to resume from the latest typed handoff.

Alternatively, tell the user to remove the listed files to start fresh.

Never silently remove an existing handoff:

Slug `<slug>` has existing handoffs:
.cheese/cook/<slug>.md (when present)
.cheese/press/<slug>.md (when present)
.cheese/age/<slug>.md (when present)
.cheese/cure/<slug>.md (when present)
Use `/cheese --continue <slug>` to resume from the latest typed handoff, or
remove the listed files to start fresh.

Read a handoff with the phase and the slug, not with a path:

python3 skills/cook/scripts/cook.pyz read-handoff-slug --phase <phase> --slug <slug>

The command exits with status 2 when either flag is absent.

Canonical planner → Cook → Cure steel thread

Section titled “Canonical planner → Cook → Cure steel thread”

The live fan route has one typed path.

Do not use the legacy curd-block decomposer as the semantic planner.

Do not pass raw mappings between phases.

Do not create a preflight helper.

  1. Build a PlannerRequest from the authored spec. Select the request kind from the failure class, as ## Planner request kinds defines. Dispatch the planner through easy_cheese.shared.workflow.plan. The planner returns a PlannerResultWriterView. plan materializes this view into one PlannerResult. If PlannerResult.plan is absent, stop before any worker dispatch. Preserve the failure in the handoff.

  2. Take planner_result.plan. Call easy_cheese_schemas.validate_curd_plan. Use the returned CurdPlan for every subsequent operation. Validation is the preflight. Complete validation before the first Cook writer, reviewer, or diagnosis dispatch.

    Read a .curd-plan.json artifact through easy_cheese_schemas.schema_runtime.load_curd_plan. load_curd_plan accepts a decoded JSON mapping or raw JSON, structures it into a typed CurdPlan, and runs validate_curd_plan on that value. load_curd_plan rejects YAML or Markdown frontmatter as the wrong artifact format. Never pass a decoded JSON mapping straight to validate_curd_plan.

  3. Schedule CurdPlan.curds in topological waves that respect dependencies. A blocked prerequisite produces a deterministic blocked CurdResult for its dependents. Never use declaration order instead of the plan’s dependency graph.

  4. Keep the linear path on easy_cheese.shared.workflow.cook with the validated plan. The host resolves every ArtifactRef with resolve_artifact. The host finalizes exactly one CurdResult for each selected curd through normalize_agent_output. Treat writer output only as an observation. The host owns identity, digests, provenance, dispositions, and coverage. Executor or normalization failure still produces a host-finalized blocked result. Never produce zero results for this failure.

    For fan topology, route the validated plan and selected curd IDs through easy_cheese.skills.cook.preparation.fan_execute.execute_fan. execute_fan adapts the existing writer, review, diagnosis, and acceptance-check dispatches into run_fan, which owns the progress-aware state machine.

    The host passes three Press-related inputs to execute_fan and execute_bound_plan. dispatch_press runs one Press round; a host without sub-agents runs that round inline, per press-loop.md § Dispatch. A behavior curd with no dispatch_press fails fast at start, before any Cook dispatch. dispatch_acceptance runs the integrated acceptance check. non_behavior_curds names the curd ids exempt from Press.

  5. run_fan schedules the validated plan in topological waves. A blocked prerequisite produces a deterministic blocked CurdResult for its dependents. Never use declaration order instead of the plan’s dependency graph. A failed review starts a host-controlled Review → Diagnosis transition. The diagnosis callback returns a DiagnosisResultWriterView. The canonical normalizer produces a DiagnosisResult. Only a confirmed result can continue to Cure. Bind the result to the exact source plan and curd. Use easy_cheese.shared.workflow.bind_diagnosis(plan, curd, diagnosis_result).

  6. The linear path calls easy_cheese.shared.workflow.cure with the same validated CurdPlan. The fan path calls its adapted Cure callback through run_fan. Supply the complete tuple or mapping of CureDiagnosisBinding values. Before dispatch, Cure validates each binding’s plan reference, curd reference, digest, and confirmed disposition. Cure then repeats artifact resolution and host-owned CurdResult normalization. Never accept a diagnosis from another plan or curd.

The direct plan → workflow.cook → bind_diagnosis → workflow.cure calls define the linear steel thread. The accepted fan handoff uses execute_fan → run_fan without a second workflow state machine.

run_workflow is the typed convenience entrypoint when a host requires one call.

Use phase="cook" or phase="cure" with the same binding requirements.

run_workflow does not define a separate semantic path.

Cook emits the validated request. Mold owns planning after a Cook failure. Cook never plans on its own after a specification failure.

Select one PlannerRequestKind for each failure class:

Failure class kind Required fields Rejected when
The spec has no plan yet decompose objective source_plan_ref is present
A deliberate replan of an approved plan replan objective, source_plan_ref source_plan_ref is absent
A specification failure during execution remediate objective, source_plan_ref, at least one evidence entry source_plan_ref or evidence is absent

Every request also requires contract_version and request_id. Publish the validated request, then name its typed pointer in artifact:. Write next: mold with the https://schemas.easy-cheese.dev/planner-request payload schema. Use status: ok, because gated and halt stop the chain.

Select linear or wave-fan mode deterministically.

Do not use deliberation to select the mode.

src/easy_cheese/shared/fanout/mode.py is the single source of truth.

PARALLEL_THRESHOLD = 2.

select_mode(curds) returns "parallel" when len(curds) >= PARALLEL_THRESHOLD.

This condition means 2 or more curds.

Otherwise, select_mode(curds) returns "linear".

The installed route exposes the same selector as python3 skills/cook/scripts/cook.pyz mode --count <curd-count>.

Get the count from the validated CurdPlan.

Never get the count from a legacy phase file.

No-plan fallback.

Use select_mode_from_score(score) only for a PR or fresh branch without a planner handoff.

It returns "linear" when score <= DECOMPOSE_FIRST_THRESHOLD (250).

It returns "decompose-first" above this threshold.

It never returns "parallel" without a validated plan and disjointness proof.

Fast path.

Use the fast path when /mold’s curd-count hint = 1 and the blast radius is low or medium.

Skip the decomposer spawn.

Use the single-coder path.

The 1-curd spec runs in linear mode.

Trust the hint only to skip work, never to pick parallel or bypass validate_curd_plan.

Run /plate in topology-preflight mode when the selected mode is parallel, the user supplied --open-pr, and no pull request exists.

Complete this decision before Phase 1 seed or any worker commit.

Derive plate_layout from the spec’s landing.shape first, via easy_cheese_schemas.manifest.plate_layout_for.

Record that derivation. When the spec has no landing block, /plate decides the shape from the curd plan.

The decision rules live in ../../plate/references/topology.md. Follow them. Do not restate them here.

Record plate_layout and the chosen shape in the typed handoff evidence.

Read plate_layout and shape from that evidence.

Pass both values to the PR planner as {plate_layout} and {shape}.

Apply the policy do not decide twice.

Do not use a legacy manifest to make this decision.

Preserve the detected topology for existing PRs.

Keep runs without --open-pr commit-only.

Complete this decision before the Phase 1 seed or any worker commit.

Seed (coder).

After you fix the topology, prepare only files that two or more curds share.

Do not hide curd-owned behavior in the seed.

Before any curd runs, probe which role the available toolset supports.

Use src/easy_cheese/shared/fanout/milknado.py::probe.

The installed route exposes the probe as python3 skills/cook/scripts/cook.pyz milknado --tools "<available tool names>".

The probe returns one of three roles:

  • engine — Both milknado_todo_claim and milknado_node_verify are present. Milknado owns the DAG, per-node worktrees, and verify-until-green process. /cook dispatches the typed curd operation for each claimed node.
  • tracker — Only milknado_todo_add is present. Milknado records typed curd status but does not run curds. /cook still owns native fan-out.
  • none — No milknado tools are present. Native fan-out owns worktrees from start to finish. Native curds self-verify once in-worker.

This parity difference is deliberate.

Native curds self-verify once.

Milknado verifies until green when it is present.

Announce milknado’s absence once.

Then proceed.

none never blocks the workflow.

none never changes the typed contract.

Stage Chain Canonical handoff
Planner planner-request → PlannerResult → validated CurdPlan PlannerResult
Per curd cook (with its Press loop) → age ↔ cure until clean, stalled, or blocked CurdResult + remediation state
Post-merge integrated acceptance check → age ↔ cure → age over the merged typed results final CurdResult
Per curd, non-behavior work coder(cook) → age ↔ coder(cure) until terminal not-applicable-curd
Post-merge, non-behavior work age ↔ cure → age not-applicable-postmerge

Per-curd workers own incomplete implementation slices.

Each behavior curd runs its Press loop inside its own Cook phase. The orchestrator dispatches Press after each behavior Cook and owns the round count; non-behavior curds skip it. Per-curd workers never run a global Press. The orchestrator also bounds each Press loop at six rounds in total. A seventh round never starts. The run halts with halt: press-round-limit and routes to Mold.

The progress-aware state machine records each review, Cure receipt, debt score, and stop reason. A clean review completes the scope. Two non-improving reviews stall the scope and route to Mold remediation planning. A blocked scope blocks every dependent curd without worker dispatch.

After wiring and merge, the orchestrator runs one integrated acceptance check, then the Age/Cure chain, only after every curd passes. The integrated acceptance check is not a Press run. Incomplete fan work never emits next: press.

The host still records one normalized result.

The host also keeps the plan’s dependency closure consistent.

A failed review never continues directly to Cure.

The host must materialize and confirm a diagnosis.

Then the host must bind the diagnosis to the exact curd.

Publish a terminal age only when it writes next: done.

Projected dispatch count.

The progress-aware loop has no fixed per-curd phase table.

Count one Cook, one Age per review, and one Cure per selected finding round.

A clean first Age skips Cure.

A stalled or blocked scope stops its loop and routes to Mold.

Count one Press dispatch per behavior curd for each Press round. There is no global Press dispatch. Non-behavior curds add no Press dispatch. Count the integrated acceptance check once per post-merge round.

Exclude wiring dispatches.

Wiring rows exist in the manifest, not the curd block.

  • Worker exhaustion. Runtime context pressure reaches the host as WriterBudgetExceeded, not a raw worker handback. When the host handles that exception, manual orchestration does not persist a duplicate checkpoint. A direct worker returns status: needs-context: <one-line gap> with compact observations, about 2,000 tokens maximum. Observations list completed work, remaining work, up to 16 targeted path#start-end entries, gates, worktree and base, and locked decisions. The worker does not guess an artifact or next phase, and it does not run checkpoint at the hard limit. The parent delegates checkpoint persistence to the Wheypoint capability as one structured checkpoint task. The task follows Wheypoint’s validate then checkpoint commands; only that skill documents their executable form. Each command over an existing record passes --base with the revision_id the parent read; after a compaction, the parent reads again first. Use Cook’s wheypoint-resolve command for retry resolution. Require resolver outcome authoritative with a non-empty, validated working_context. The first source read contains only the resolved ranges. Start one fresh writer in the same Cook phase and worktree. Set --retry-count 1. Missing, invalid, or empty observations; failed save or resolve; or a second needs-context halts. The parent never implements the unfinished slice. This is same-phase orchestration, not a Cook→Cook transition. Known-false lead: the compiled registry has no cook -> cook route; do not re-investigate or publish --next cook. The published write-handoff-artifact remains --phase cook --next age; the checkpoint is not that terminal phase artifact. Pass that command --base with the revision_id from Cook’s wheypoint-resolve when a record exists. The host finalizes the blocked CurdResult and continues to harvest the other results.

  • Aggregate-gate conflict. After you harvest all wave results, run the project gates over the merged tree. When the gate output exceeds one screen, dispatch a gate-runner (cheap / low, no-write) and read its failures-plus-counts digest instead of the log. Distinguish a real cross-curd conflict from harmless generated drift. A real cross-curd conflict occurs when curds pass individually but collide in aggregate. The post-merge Cure can absorb harmless generated drift. Never automatically resolve a real conflict.

  • Compute the verdict — Normalize each typed CurdResult. A halted result stops the workflow. A clean review finalizes that curd without another Cure. A stalled or blocked scope routes to Mold remediation planning. After wiring and merge, the project gates must pass before the global post-merge chain.

  • Give each curd its own worktree. First create the worktree when the host has no native worktree-isolated sub-agent primitive. Use python3 skills/cook/scripts/cook.pyz worktree create --slug <id> --base <orchestrator-branch>. The command returns {path, branch}.

  • Run the disposition-specific sequential chain for each curd. Persist one normalized CurdResult for each curd. Each behavior curd runs its own Press loop inside Cook. Non-behavior curds skip Press.

  • After every curd returns, harvest its commits. Then tear down each curd worktree.

  • Harvest with python3 skills/cook/scripts/cook.pyz worktree harvest --branch <curd-branch> --onto <orchestrator-branch>. On conflict, invoke /melt. If /melt cannot resolve the conflict, use per-curd PRs. The worktrees share one object store. Therefore, this operation does not require git fetch.

  • Tear down with python3 skills/cook/scripts/cook.pyz worktree teardown --path <worktree-path> --branch <curd-branch>. A completed run leaves no worktree-agent-* branch. It also leaves no stray worker directory.

  • Run wiring in dependency order. Then run the one integrated acceptance check → age ↔ cure → age pass.

  • /cook alone performs harvest. The Cook fan orchestrator owns the terminal /plate dispatch. Terminal Cure owns publication only in the linear chain. Never dispatch /plate during the run.

After each wave, persist the typed PlannerResult, CurdResult values, diagnosis bindings, and gate evidence in the handoff artifact.

These records support recovery and publication provenance.

They do not create a second workflow state machine.

--resume <slug> re-enters a crashed wave-fan run.

It loads the latest typed handoff from .cheese/cook/<slug>.md and its referenced artifacts.

Fail fast if the handoff is missing, malformed, stale, or unresolved.

Also fail fast if its referenced PlannerResult or CurdPlan has these conditions.

Use resolve_artifact to resolve the references.

Run validate_curd_plan again before selecting the next dependency wave.

Verify that every retained commit or artifact reference still exists.

Resume only curds whose typed result is incomplete.

Never infer progress from an old phase name.

A bare re-run has no --resume.

If a bare re-run finds an existing handoff, stop.

Tell the user to resume or remove the handoff.

Never silently remove typed evidence.

Resolution provenance and the output contract

Section titled “Resolution provenance and the output contract”

Resolve every planner, curd, review, diagnosis, and Cure dispatch against the typed-role table in SKILL.md’s ## Agent resolution section.

Also use the shared protocol in ../../cheese/references/agent-resolution.md:

Work Preferred types
Plan the spec planner, general
Cook, press, cure, seed, or wiring coder
Every age pass reviewer
Taste-test per curd reviewer (taste-test) — default power, medium effort
Gate digest for a curd worktree gate-runner, general — cheap power, low effort, no-write
Harvest and plate parent

The resolver first filters required capabilities, tools, permissions, and isolation.

Then the resolver selects minimum power and maximum specificity.

A prompt-only, read-only general fallback can continue with degraded: true.

A missing required tool or write permission halts the workflow.

Every handoff and final summary includes the resulting agent_resolution block.

This block keeps the role, fallback, and degradation visible.

The fan pathway and single-coder path use the same final-summary shape.

SKILL.md defines this shape in ## Handoff slug and ## Output.

Publish a terminal age only when it writes next: done.

Do not publish a terminal age that writes next: cure.

Do not publish a terminal age that omits next.

A saved parent spec or early curd mini-spec is not execution authority. Start Cook only after the user selects the scope and route. A clear standalone task can use Cook’s fast path without Mold finalization.

For bound curd work, Mold finalization returns ready only with a validated request_id, spec_ref, planner_result_ref, plan_ref, and coverage. It stores a durable result path, not a handoff pointer. saved-not-ready records unmet requirements and holds; do not dispatch a writer from that result. An explicit whole-request stop or unresolved spec hold blocks direct execution.

Before any writer starts, run cook.pyz validate-result --result <path> --artifact-root <root>, where <root> is the parent of the results/ directory that holds the --result file; a non-zero exit refuses execution. The host then calls easy_cheese.skills.cook.execute_bound_plan with the exact finalized values and the same artifact root. The shared validator resolves the spec and contracts, checks digests, matches the planner to the plan, and checks exact coverage. Complete planning selects every curd. Partial planning keeps the canonical PlannerResult.unresolved_work unchanged and selects only a dependency-closed curd set. A changed spec, scope, or plan needs a new bound selection.

Runner setup remains a separate, bounded host authority. Retain an explicit response to exact authorization limits, then run only an allowed command against an allowed fixture path. Pass the retained authorization, response, and successful setup evidence references to execute_bound_plan. Setup authority cannot clear a feature hold or authorize feature writes.

Linear plans dispatch selected curds through workflow.cook. Fan topology routes through preparation.fan_execute.execute_fan and run_fan. The returned CookExecutionOutcome reports completed curds, unchanged remainder, the fan next step, and remediation state references. Neither route needs a preparation or acceptance CLI command.

Before Cook opens a PR or hands off to /age, Cook produces a package-ready report.

formatting.md defines the cross-cutting house style and citation format.

This file defines the package report structure.

formatting.md defines the voice rules and the footnote primitive.

quality-gates.md defines quality-gate failure handling, baseline classification, the three-way policy, and the baseline: block.

This file defines only how the report shows that policy.

## Cook Report — <slug>
### Contract
- Behaviour: <one line>
- Non-goals: <list or "none">
- Quality gates: <commands>
### Files changed
- <path>: <one-line reason>
- <path>: collateral repair: <one-line reason> — for a repair outside the cooked contract, per the three-way policy in [`quality-gates.md`](#quality-gates--baseline-aware-three-way-policy)
### Tests
- <command>: <pass | fail | skipped with reason>
### Risks
- <bullet — known unknown, deferred decision, or anything you'd want a reviewer to look at>
### Baseline (if any recorded)
- <suite>/<test_id>: <signature> — identical to baseline, outside the cooked contract, not fixed (see [`quality-gates.md`](#quality-gates--baseline-aware-three-way-policy))
### Acceptance evidence (behavior work)
- Smallest complete path: <the path run first>
- Detection proof: <the check failed on the original bug, or rejected an absent or incorrect result>
- Revision: <commit or tree>
- Environment: <runtime, services, live or offline>
- Command: <exact command>
- Observed result: <what the check showed>
- Status: verified | unverified: <reduced claim>
### Press loop (behavior work)
- Rounds: <count>
- Round <n>: green | finding | coverage_gap | invalid_evidence | production_changed
- Press report: `.cheese/press/<slug>.md`
### Self-eval
- [x] Tests cover the changed behavior.
- [x] Acceptance evidence names the detection proof and its verified or unverified status.
- [x] Cook made tests pass without speculative behavior.
- [x] Taste-test passed.
- [x] Quality gates pass, or all remaining red is recorded baseline failure (see Baseline section).
### Next step
- /age <slug> — review the diff
- /cure <slug> — apply selected age findings (after /age)
  • Never claim green on partial work. If you skip a test, list the command and the reason.
  • Never hide a failed gate. If lint fails, report the failure when you do not fix it. Recommend follow-up work.
  • Never claim “ready for /age” when an unresolved taste-test lens returns revise. This claim is the cardinal sin.
  • When the Baseline section lists any recorded failures, state in the final summary that the full suite is not green. The final summary lists those failures clearly, as quality-gates.md requires.

Cook stops and does not produce a “ready” report in these conditions:

  • The specification requires a decision, and the user has not answered.
  • Cook cannot make the tests fail for the expected reason.
  • Cook reaches the two-round taste-test limit, and findings remain.
  • A quality gate fails because of new or changed behavior, and the fix requires a design decision outside the specification.

Record each identical-to-baseline failure. Such a failure is not a stop condition.

Record these failures as quality-gates.md specifies.

For each stop condition, the report says “blocked” and gives the precise reason.

Cook owns the Press loop for behavior work. Press is the adversarial pass that Cook dispatches automatically. The user never selects Press from a menu. Non-behavior work skips the Press loop.

After the taste test passes, Cook dispatches a fresh-context Press agent. Resolve the agent through ../../cheese/references/agent-resolution.md. Use the coder role with writes limited to tests. The spawn prompt carries the no-chain directive from auto-mode.md. Press writes .cheese/press/<slug>.md and returns to Cook. See ../../press/SKILL.md and ../../press/references/gap-analysis.md.

When the host has no fresh-context sub-agent, run the round inline instead of halting. Write the package report first, then follow ../../press/SKILL.md for one round in the same session, writing tests only. Record topology: inline and degraded: true in agent_resolution, and name the lost isolation in the ### Press loop section. Never skip the round because no sub-agent exists.

Press outcome Cook action
green Hand off to Age.
finding Run a correction (correction = true). Press replays the same attack.
coverage_gap Run a coverage addition (correction = true). Press reruns.
invalid_evidence or production_changed Halt with halt: invalid-evidence or halt: production-changed.

A correction fixes only the reported finding. A coverage addition adds first acceptance coverage only. It makes no production change beyond what that coverage exposes.

Cook is the single round counter. Press has no memory across fresh dispatches. Cook records each round in the package report’s ### Press loop section. Cook passes the round number and the attack identity in each dispatch. Press emits a halt only from that round number.

  • A correction runs at most 2 times for one attack. A third finding halts with halt: correction-cap.
  • A coverage_gap retries once. A second coverage_gap in one Cook run halts with halt: coverage-gap.
  • A Cook run allows 6 Press rounds in total, on the linear and fan paths. A round that does not end green after round 6 halts with halt: press-round-limit.

In the linear path each halt reports status: halt: <name> and next: done. In the fan path the orchestrator blocks the curd and routes to Mold. Cook never publishes next: press.

Record each round in the package report’s ### Press loop section. Link .cheese/press/<slug>.md.

Prototype mode is a steered build loop for an idea that has no spec. The user says “here is an idea, go prototype it.” Cook builds a working first cut, shows it, and refines it with the user round by round. The code stays. When the shape settles, Cook stabilizes it into tested, reviewable work.

Enter on --prototype, or when the ask has a prototype signal:

  • “prototype this”, “go prototype it”, “spike this out”, “hack up a first version”.
  • “build a rough version and we’ll iterate”, “let’s try it and see”.

Prototype mode is for exploration. It is not a replacement for the standalone fast-path when the task is already clear. It is not the Mold Prototype Cycle. The Mold cycle answers one design question in a throwaway worktree and discards the code. Prototype mode keeps the code and grows it.

  1. Derive a kebab-case slug from the ask.
  2. If the working tree is dirty, stop and ask the user to commit or stash first.
  3. Record the base commit and the original branch. Stabilize uses the base commit to prove new tests fail without the prototype.
  4. If the current branch is the default branch, create a branch before the first edit. Record that Setup created it. Otherwise, record the current branch as the original branch and that Setup made no new branch.
  5. Run the leverage-trigger check in ../../cheese/references/routing-policy.md § Leverage triggers. Announce each fired id. A fired trigger does not stop the loop, but it changes the stabilize route.
  6. Start the prototype log in .cheese/cook/<slug>.md under ## Prototype log. Do not create a second file.

Each round has three steps. Keep each round small enough for the user to check in one read.

  1. Plan — Show three to five bullets. Name the next step, the files it touches, and what the user sees at the end of the round. Do not write a spec file. Do not wait for approval unless the step is destructive or a new trigger fires.
  2. Spike — Build the step for real in the working tree. Prefer the simplest working path and existing project patterns. Run the cheapest check that shows the step works. Use an existing test, the app, a command, or a script. Spike code needs no test first; stabilize adds the tests.
  3. Check — Report what changed, the evidence that it works, and each open question. Append one entry to the prototype log: the plan, the files, and the evidence. Then offer this menu and wait:
    • Refine — the user gives feedback; start the next round.
    • Stabilize — the shape is right; go to § Stabilize.
    • Discard — delete the prototype; see § Discard.
    • Checkpoint & stop — /wheypoint. Append the user’s reply to that entry before the next round, Stabilize, or Discard.

Run the leverage-trigger check again in each Plan step. Announce a newly fired id before the Spike step.

  • Keep every change on the prototype branch; never commit to the default branch.
  • Do not run /plate, push, or open a pull request during the loop.
  • Do not delete user work or run a destructive operation without an explicit yes.
  • Do not add scope the user did not ask for; list ideas as open questions instead.
  • Report a failed check as failed; never present an unrun check as passing.
  • --auto does not skip the Check step; it applies only after stabilize.

Stabilize converts the prototype into normal Cook work.

  1. Draft the acceptance criteria from the behavior the user accepted in the prototype log. Each criterion traces to a log entry.
  2. Route by the leverage triggers:
    • No fired trigger — invoke /mold in agent-invoked mini-spec mode (../../mold/references/mini-spec-mode.md) as a visible handoff. Record the prototype log path in ## Provenance. If the user declines Cook consent, keep the prototype branch and the saved draft. Then stop Stabilize and return to the prototype menu.
    • A fired trigger — stop and route to /mold at Light tier. Pass the prototype log and the branch as prior evidence. Mold confirms each consequential fork before Cook continues.
  3. Run the normal Cook Flow from Contract against the spec, with the prototype tree as the start state.
  4. Write a test for each criterion. Check that each test fails without the prototype behavior where that is cheap. Run it against the base commit, or disable the behavior and restore it afterward.
  5. Remove spike debris that no criterion needs, such as debug output and unused paths.
  6. Continue with Validate, Taste-test, and Hand off as the Flow defines. The handoff slug artifact: names the minted spec. Pass --body-file with a body that keeps the full ## Prototype log section.

Show the files and branch that the discard removes. Ask for an explicit yes. After the yes, restore the working tree to the base commit. Check out the original branch. Delete the prototype branch only when Setup created it. Keep the prototype log; it records what the loop learned. Write the handoff slug with next: done and a one-line orientation that names the discard. Pass --body-file with a body that keeps the full ## Prototype log section.

Quality gates — baseline-aware three-way policy

Section titled “Quality gates — baseline-aware three-way policy”

This document defines how /cook, /press, and /cure handle quality-gate failures against a baseline. Every downstream skill links here instead of repeating these rules.

The quality-debt snapshot supplies data to the bundled baseline classifier. Fan mode records this snapshot once before any curd cooks. Fan mode records it in the baseline artifact that .cheese/cook/<slug>.md names on its baseline: line. The typed Cook handoff is the only live recovery record. The retired .cheese/ultracook/<slug>/manifest.yaml is a lossless projection. Never read that manifest to select the phase to execute.

If no baseline exists, bare Cook (no frame) lazily captures the same failure records from the pre-change tree. The baseline capture and each current-gate run use the same worktree and toolchain.

Run the tested classifier through python3 skills/cook/scripts/cook.pyz baseline. Do not classify failures by eye.

The tested bundled helper calculates each classification deterministically. An agent does not classify failures by eye.

FailureRecord = {suite, test_id, signature}, where signature is the whitespace-normalized first line of the failure message.

  • identical — The test and signature are the same as the baseline.
  • new — The failure is not in the baseline.
  • changed — The test is the same, but the signature is different. Treat this failure as new.
  • resolved — The failure is in the baseline, but the test is now green. Record it for the summary. It is not a failure.

The handoff baseline: line points at the Cook comparison summary. That summary holds the identical, new, changed, and resolved records. It also holds every repair dispatch.

  • Identical, outside the cooked contract — Record the failure in the baseline artifact. Continue under policy never halt, never fix silently.
  • New or changed — The cook fixes the failure. Use no more than 2 fix rounds per gate. Do a no-progress check after each round. The cook must halt when the same failure signature appears twice in sequence. Repair collateral damage outside the cooked contract when it blocks the gate. Record each repair in the report’s Files-changed section. Use reason collateral repair: <one line>.
  • Halt only when rounds exhaust, the no-progress check trips, or the fix is design-shaped. A design-shaped fix requires a decision outside the spec. Put the classification in the halt handoff. This ensures resume never re-asks.

The baseline is optional and additive. Statuses stay ok or halt. The baseline introduces no new status value.

The handoff preamble accepts one physical line for each key. Therefore baseline: holds one artifact reference, not a nested mapping. Write baseline: none when Cook records no comparison. Otherwise write one path, as this example shows:

baseline: .cheese/cook/<slug>-baseline.yaml

Store the record itself in that artifact:

captured_at: <UTC ISO-8601>
gates:
- cmd: <gate command>
failures: [{suite, test_id, signature}]
repair_dispatch: # optional — present once a repair is dispatched
slug: <pasteurize slug>
branch: <repair worktree branch>
run_branch: <originating run branch>
pr: <PR number or URL> # optional — present once plated

run_branch names the branch that recorded the debt. /plate requires this field for its merge-time topology check. Every consumer reads the artifact through the baseline: path.

Record identical-to-baseline failures visibly. List them in the final summary. State that the full suite is not green. A concurrent repair can already be in progress. See § Repair pathway.

Recording a debt does not fix it. This pathway applies when baseline capture records ≥1 identical-to-baseline failure. Both frames use the same repair pathway.

cook/SKILL.md links to this pathway instead of repeating it.

Use the frame’s existing record point:

  • fan mode: the pre-Seed write of the typed Cook handoff
  • bare cook: the post-classify write of the typed Cook handoff
  1. Dedupe — You must dedupe against a live repair_dispatch. A live repair_dispatch has an existing branch. Its handoff chain has not reached terminal status: ok or status: halt. Skip this dispatch when the baseline artifact already holds a live dispatch. Never dispatch a second repair for the same debt.
  2. Consent — Set consent automatically under --auto. Otherwise, prompt once at record time with the failure count. Use ../../cheese/references/ask-user-question.md. If the user declines, skip the repair. The debt stays recorded in both cases.
  3. Worktree — Create a repair worktree with the shared primitive: python3 skills/cook/scripts/cook.pyz worktree create --slug repair-<run-slug> --base origin/main. Do not use the cook’s own tree. The repair worktree has an independent lifecycle. Exclude it from the run’s worktree teardown. Bare /cook example: python3 skills/cook/scripts/cook.pyz worktree create --slug repair-<slug> --base origin/main.
  4. Dispatch — Use the repair worktree to dispatch a concurrent /pasteurize in an isolated worktree. In the brief, identify the recorded failures as the symptom. Include suite, test_id, and signature for each entry. Add one explicit per-dispatch override to the brief. At Phase 6, chain forward with /cook <repair-handoff-path> --auto --open-pr. Pass the canonical Pasteurize handoff path, not a bare slug. Cook resolves a bare slug as a specification, so a bare slug breaks the repair chain. Do not use pasteurize’s documented /cook <repair-slug> --auto for this dispatch. This instruction applies only to this dispatch brief. It does not change pasteurize’s SKILL.md. It is more specific than the skill’s generic default and governs this invocation. Therefore, the repair publishes its own PR by default. This instruction does not change /pasteurize’s own contract.
  5. Record — Write repair_dispatch: {slug, branch, run_branch} into the baseline artifact. Use the typed Cook handoff in both frames. Add pr after /plate publishes one.

The run never waits for the repair. A failed, halted, or still-in-flight repair leaves the recorded debt unchanged. The repair never blocks the run’s completion or publication.

Report the repair status in the final summary when known. Otherwise, use the repair_dispatch link and the pasteurize slug as the resume path.

The repair worktree’s own /plate step performs a mechanical file-overlap check at publication time. This check occurs before the ordinary New-PR topology policy.

Read run_branch from the baseline artifact. Halt when that field is absent. Verify that the branch still exists before you compare. Compare the repair’s changed files against that branch.

Count the changed lines from git diff --numstat <merge-base>..<repair-branch>. Use the merge base of the repair branch and the run branch. Count a rename as one changed file and count its changed lines. Count a binary file as one changed file and 50 changed lines.

  • No shared files (or the run branch is already gone). Plate the repair as an ordinary independent PR against main. This uses /plate’s existing New-PR flow. No run-diff comparison is necessary.

  • Shared files, repair ≤2 files and ≤50 changed lines — Skip publication. Harvest the repair’s commits onto the run branch with the bundled command:

    python3 skills/cook/scripts/cook.pyz worktree harvest \
    --branch <repair-branch> --onto <run-branch> --repo <run-worktree>

    Resolve <run-worktree> from verified Git worktree state. Halt at topology when the command fails.

  • Shared files, repair over that threshold — Restack the branches. The repair becomes the base PR. The run’s PR(s) rebase on top through /plate’s existing stack machinery.

  • /cook writes the baseline: block.
  • /press, /age, and /cure honor the block. Apply no re-halt, no re-flag of identical entries.
  • /cheese --continue treats the block as settled state, not an open question.
  • /cook’s fan pathway validates the baseline artifact that the typed handoff names.
  • /plate applies the repair pathway’s merge-time topology check when it publishes a repair-worktree branch. See § Repair pathway, Merge-time topology.

The TDD loop: test first where it fits → implement → taste-test

Section titled “The TDD loop: test first where it fits → implement → taste-test”

TDD is recommended practice in Cook. No gate enforces it. Each phase should have a clear exit before the next phase starts.

Docs, refactor, test, and appearance work uses its own implementation and verification path. It changes only the requested surface.

When a change adds or modifies behavior, write the test before the implementation where it fits. This test is Cook’s vertical loop.

A test that passes against unimplemented code gives a false positive. Check that the test fails for the expected reason when that is cheap to do.

Shape each new test by ../../cheese/references/test-shape.md. Extend the existing test file. Write one table row for each equivalence class. Use a property test instead of range(N) trials. Stack tables only when each axis selects a branch.

For behavior work, Cook owns the acceptance demonstration before Press. This is a reported obligation, not a gate. It adds no gate, no receipt, and no enforcement command.

  1. Run the smallest complete path first.
  2. For a bug fix, confirm the check detects the original failure. For new behavior, confirm the check rejects an absent or incorrect result.
  3. Run the check against the final integrated artifact.
  4. Record the revision, environment, command, and observed result in the package report’s ### Acceptance evidence.

Apply a live check only where the claim depends on a live boundary. When a live check cannot run, report the behavior unverified and name the reduced claim. Never substitute an offline check silently.

For behavior work, make the smallest production change that makes the tests green.

For docs, refactor, test, or appearance work, make the requested change and verify it directly.

Implement must:

  • Use existing dependencies and project patterns.
  • Run the narrowest useful inner test.
  • Run relevant wider gates: the project formatter, lint, type check, and build.
  • Stop and ask if implementation identifies a design decision that the spec does not answer.

Write the change so the taste-test and /age pass on the first round. Most rules below map to a taste-test lens or /age dimension that otherwise sends the work back; the size ceiling is enforced by /plate.

  • Full-word identifiers. No abbreviation or single letter whose scope outlives one short block. A conventional short name used conventionally (i as a loop index, db, ctx) is exempt. Reviewers find defects about 19% faster with full words (Hofmeister et al., 2019). /age grades this under deslop.
  • Local reasoning. A reviewer must understand each changed function from its own body plus the signatures it calls. Do not add monkey-patching, side-effecting decorators, __getattr__ or __getattribute__ tricks, operator overloading, metaclass logic, or exception-based control flow that crosses a module boundary.
  • Let the type checker review. Annotate every new parameter and return. Use a closed union or enum instead of a string tag. Make every match or switch over a closed union exhaustive with assert_never (mypy/pyright) or assertNever (typescript-eslint switch-exhaustiveness-check); never rely on a silent default arm. Idioms: deslop-python.md § 15, deslop-typescript.md § 16.
  • Stay under the comprehension ceiling. Keep the semantics-altering surface under roughly 400 changed code lines. When the contract needs more, name the layer boundaries under the package report’s ### Risks so /plate can recommend a stack.

These rules do not license speculative types, helpers, or abstractions. Scope and Simplify still apply.

Before the Press loop, make every inner test and relevant gate GREEN.

For non-behavior work, complete the requested non-behavior verification and taste-test. Then, hand off directly to Age. Non-behavior work has no Press loop.

A corrective Cook (correction = true) applies only to the active Press finding or coverage_gap. It must not weaken, replace, or bypass an existing test.

If Cook reports partial or skipped work, stop and resolve it before taste-test.

Taste-test — drift, readability, scope, simplify, plus three fresh-context lenses

Section titled “Taste-test — drift, readability, scope, simplify, plus three fresh-context lenses”

After Cook says “I completed all the changes”, run a taste test before Press. The taste-test is a fresh-context review.

For a non-trivial cooked diff, dispatch the review to a read-only reviewer that did not write the code. For a small diff, use the low-cost inline check.

Cost gate — where it runs.

Dispatch the fresh-context reviewer unless all four conditions are true:

  • The diff changes one file.
  • The diff adds no new public surface.
  • The diff has <~40 changed lines.
  • The diff has no risk flag.

If all four conditions are true, run the coder self-check. If one condition is false, dispatch 1 fresh reviewer (taste-test) at the tier that Who runs it names below.

A risk flag identifies one of these categories:

  • auth/secrets/crypto/tenant isolation
  • payments/ledgers/irreversible effects
  • concurrency/idempotency/ordering/retries
  • schema/migration/protocol/public-API change
  • production-destructive ops
  • weak integration coverage around a global invariant

Who runs it.

  • Top-level /cook:
    • Resolve the fresh-context taste-test through ../../cheese/references/agent-resolution.md.
    • Request a read-only reviewer (taste-test) at default / medium.
    • Pass {spec/contract, diff, inner-test list, any locked/user-approved decisions}.
    • The reviewer returns the per-lens verdict below.
    • The reviewer does not return a full /age report.
    • A general worker can qualify only under the shared prompt-only read-only degradation.
  • Coder-nested /cook:
    • If the active coder cannot dispatch, run the inline self-check.
    • Record taste_test: deferred-to-orchestrator.
    • The orchestrator must run the authoritative reviewer before it accepts the handoff.

Lenses.

The inline or dispatched taste-test returns pass | revise | escalate for each lens. The Locked-decision lens can also return halt.

Lens Question Pass criterion
Spec Did the implementation drift from the spec? Every behavior described in the spec is present; nothing extra.
Readability Is the change as concise and clear as possible? A reviewer can understand each changed function from its body and the signatures it calls, without external context, and the diff meets § Reviewable by construction (full-word identifiers, local reasoning).
Scope Did Cook add more than asked? The diff matches the spec’s bullets; no speculative helpers.
Simplify Does the diff reuse what exists, stay clean, and avoid wasted work? See sub-checks below; all three must pass.
Production path Does every spec acceptance criterion have a production path that exercises it? The behavior is reachable from real callers, not only from tests that manufacture the state.
Wired callers Does each new public function have a non-test caller? A non-test caller exists, or the diff carries an explicit “wired in phase X” note.
Locked-decision If the dispatch prompt carries a locked/user-approved decision, does the diff implement that decision? The diff honors the locked decision, or the reviewer returns halt flagging the divergence.

The last three lenses are fresh-context additions. They identify failures that the inline taste-test historically passed:

  • A missing production path.
  • Public functions with no non-test callers.
  • A silently substituted design decision.

A halt from the Locked-decision lens stops the chain for a human decision. It is not a corrective Cook finding. On a /cure run, each selected finding’s recommendation: and invariants: lines are the locked decision for that fix.

Escalate-unverifiable.

If available evidence cannot verify a lens claim, return escalate for that lens. Never return a guessed pass or revise.

This rule implements cross-cutting contract 1 in the spec: “a claim no evidence can settle returns escalate, never a guessed pass or fail”.

The Simplify lens uses the same three sub-checks as /simplify:

  • Reuse
    • New code must not duplicate an existing utility, helper, or component.
    • Inline logic must use an available project helper.
    • New code must not create a near-duplicate of an existing function.
  • Quality
    • Do not add redundant state, such as a cached value that the code can derive.
    • Do not add parameters when code restructuring is appropriate.
    • Do not use copy-paste-with-variation.
    • Do not create a leaky abstraction that exposes internals across a slice boundary.
    • Do not use stringly-typed code when a constant, enum, or union exists.
  • Efficiency
    • Avoid unnecessary work, including redundant compute, repeated reads, and N+1.
    • Use concurrency for independent operations.
    • Avoid recurring no-op state or store updates in loops or handlers.
    • Do not use pre-existence checks when the operation can handle the resulting error.
    • Do not use unbounded structures.
    • Do not leak listeners or timers.
    • Read a slice instead of a full file or dataset when a slice is sufficient.

Each lens returns pass, revise, or escalate. The Locked-decision lens can also return halt.

Send every revise finding into a bounded corrective Cook pass. Include the original spec, the Cook report, and the taste evidence.

best: implement → taste-test (all pass) → press
worst: implement → taste-test → implement → taste-test → implement (final)

After the second taste test, allow only one final corrective Cook pass. Stop when the final pass cannot resolve all taste findings. Report the result as blocked. Do not continue to Press.

Confirm every item that the package report asserts (package-report.md § Self-eval). Also confirm these two items:

  • Spec or acceptance criteria are clear.
  • The report documents every remaining risk and every skipped check.

For Mold-to-Cook changes, the inner test loop covers the consumer seam rather than only a helper function:

  • classify explicit mode before inference and reject malformed declared pointers/projections without task fallback;
  • plan Full work on invocation, with no scope or plan approval step;
  • materialize a Full plan once and recompute coverage when the acknowledged remainder changes;
  • keep holds across every resubmission and permit execution only from ready;
  • accept Light on invocation with no invented planner artifact;
  • reject runner evidence that is stale, failed, or outside its authorized paths and commands; and
  • preserve incomplete work and exact missing-decision requests.

The command under test supplies no agent callback and no user response. The orchestrator supplies planner output and runner approval explicitly; the Cook result is recomputed from those references on each call. The final execution-boundary test uses execute_bound_plan with real dispatch callbacks. It proves that non-ready, held, stale, and overbroad handoffs stop before workflow.cook, while a ready Full handoff forwards the exact plan curd IDs and leaves the canonical planner remainder untouched.

Cook writer agents emit AgentWriterView documents that contain kind and payload.

Before the host persists each document, it normalizes the document and validates its structure against the catalog contracts.

For each WriterViewKind, a writer agent must produce the applicable payload shape below.

The scripts/render_generated_regions.py script refreshes these shapes from src/easy_cheese_schemas/contracts.py.

Do not edit the generated region manually.

// A ? marks an optional field. = value shows the applied default. map WriterViewKind -> WriterPayload { curd_plan -> CurdPlanWriterView curd_result -> CurdResultWriterView diagnosis_result -> DiagnosisResultWriterView planner_result -> PlannerResultWriterView review_result -> ReviewResultWriterView }

type AgentWriterView { kind WriterViewKind payload WriterPayload }

type BoundedContextWriterView { shared_input_keys? tuple[str, …] = () constraints? tuple[str, …] = () invariants? tuple[str, …] = () }

type BoundedScope { paths? tuple[str, …] = () excluded_paths? tuple[str, …] = () }

type CriterionResultWriterView { criterion_id str disposition CriterionDisposition evidence_keys? tuple[str, …] = () reason? str | None = None }

type CriterionWriterView { description str check str }

type CurdPlanWriterView { objective str curds tuple[SemanticCurdWriterView, …] context? BoundedContextWriterView | None = None }

type CurdResultWriterView { criterion_results tuple[CriterionResultWriterView, …] deliverables? tuple[DeliverableWriterView, …] = () unresolved_work? tuple[str, …] = () }

type DeliverableWriterView { role str path str media_type str }

type DiagnosisCauseWriterView { summary str evidence_keys tuple[str, …] location? SourceLocationWriterView | None = None }

type DiagnosisHypothesisWriterView { statement str disposition HypothesisDisposition evidence_keys? tuple[str, …] = () }

type DiagnosisResultWriterView { disposition DiagnosisDisposition reproduction ReproductionWriterView hypotheses tuple[DiagnosisHypothesisWriterView, …] confirmed_cause? DiagnosisCauseWriterView | None = None regression_seam? SourceLocationWriterView | None = None unresolved_evidence_keys? tuple[str, …] = () reason? str | None = None }

type PlannerResultWriterView { disposition PlannerDisposition plan? CurdPlanWriterView | None = None unresolved_work? tuple[PlannerUncertaintyWriterView, …] = () reason? str | None = None }

type PlannerUncertaintyWriterView { description str scope UncertaintyScope evidence_keys? tuple[str, …] = () }

type ReproductionWriterView { status ReproductionDisposition steps tuple[str, …] observed? str | None = None evidence_keys? tuple[str, …] = () }

type ReviewFindingWriterView { severity ReviewSeverity dimension ReviewDimension summary str evidence_keys tuple[str, …] fix_cost_now FixCostNow location? SourceLocationWriterView | None = None }

type ReviewResultWriterView { disposition ReviewDisposition findings tuple[ReviewFindingWriterView, …] reason? str | None = None }

type SemanticCurdWriterView { key str outcome str scope BoundedScope outputs tuple[str, …] criteria tuple[CriterionWriterView, …] input_keys? tuple[str, …] = () dependencies? tuple[str, …] = () }

type SourceLocationWriterView { path str start_line int end_line int start_column? int | None = None end_column? int | None = None }

enum CriterionDisposition = “passed” | “failed” | “blocked” | “skipped”

enum DiagnosisDisposition = “confirmed” | “inconclusive” | “not_reproduced” | “blocked” | “invalid” | “executor_failure”

enum FixCostNow = “contained” | “moderate” | “sprawling”

enum HypothesisDisposition = “confirmed” | “rejected” | “unresolved”

enum PlannerDisposition = “complete” | “partial” | “no_work” | “blocked” | “invalid” | “executor_failure”

enum ReproductionDisposition = “reproduced” | “not_reproduced” | “blocked”

enum ReviewDimension = “correctness” | “security” | “encapsulation” | “spec” | “complexity” | “deslop” | “assertions” | “nih” | “efficiency” | “telemetry” | “conventions” | “altitude” | “reframe”

enum ReviewDisposition = “clean” | “findings” | “blocked” | “invalid” | “executor_failure”

enum ReviewSeverity = “critical” | “high” | “medium” | “low”

enum UncertaintyScope = “omitted_work” | “emitted_work” | “dependency” | “shared_constraint”

enum WriterViewKind = “curd_plan” | “planner_result” | “review_result” | “diagnosis_result” | “curd_result”

The planner_result writer view is the planner payload normalized by the host. Mold returns bound spec_ref, planner_result_ref, plan_ref, and coverage only after it validates the exact bytes and scope. Cook’s execute_bound_plan validates them again before dispatch. The host alone retains runner authorization, explicit response, and setup evidence. An agent response cannot grant execution authority.