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” or “ship it” with clear acceptance criteria. Run it alone for an unambiguous task. 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 = press | age | mold).

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.

A red-required gate disposition identifies behavior work. Run the inner RED → GREEN TDD loop against the approved spec before you change production code. A closed not-applicable disposition identifies non-behavior work. Use its implementation and verification path for the requested documentation, refactor, test, or appearance change. N/A does not remove requested work. Use correction = true only for the active Press correction loop. 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.

Accept a pasted spec or issue, focused acceptance criteria, or an unambiguous task. Read explicit spec paths verbatim. Resolve a bare slug with SPEC=$(python3 skills/cook/scripts/cook.pyz artifact-path specs <slug>). A Mold handoff pointer, a spec path, and a slug enter through § Mold-to-Cook ingress and preparation. Flags:

  • --auto chains /press → /age → /cure.
  • --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.
  • --spec <spec-path> names the approved spec for a Mold pointer. A plan whose dependencies cross landing.layers is refused before any 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, gates, and applicability. 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 — Use inner RED → GREEN for behavior changes. Use the requested non-behavior path for closed N/A work; change only the applicable surface.
  3. Validate — Run the relevant quality gates again. Read the complete gate output; for closed N/A, verify the requested non-behavior 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. Hand off — Write the package report and slug. Route behavior work through /press → /age → /cure. A closed N/A change has no adversarial contract for Press. Route it directly through /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 ready Full MoldCookHandoff and validated CurdPlan. Run cook(CurdPlan) → reviewer(age) with confirmed diagnosis and CureDiagnosisBinding through the progress-aware fan state machine until clean, stalled, or blocked. Run one global /press → /age → /cure chain only after every curd passes. Incomplete fan work never emits next: press; stalls route to Mold remediation planning. Closed N/A bypasses Press.

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. Each downstream phase links to this reference instead of repeating it.

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. This slug lets downstream phases resume or chain without rereading the full report. The fan pathway also uses it during wave orchestration. Use this schema:

status: <canonical status field>
next: mold | press | 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 specification pointer. Leave artifact: empty when this run consumed no upstream artifact. Do not point artifact: at this Cook report. /cheese forwards the same pointer to the next phase.

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 \
--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 press after red-required behavior work. Use age after closed N/A. Never publish next: cook; needs-context is a parent-owned same-phase retry. Use mold after a spec failure. Use done only at true completion. Do not send contractless N/A to Press. 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. For behavior work, start each option with the verb. Use these options:

  • Harden tests before review (recommended)/press <slug>.
  • Plate it/press <slug> --auto --open-pr: run the remaining review chain, then /plate resolves topology and publishes.

Press does not apply to closed N/A. Set next: age. Replace the options with Review the change (recommended)/age <slug>. Also offer Plate it/age <slug> --auto --open-pr.

Both menus retain Checkpoint & stop/wheypoint and Stop — dispatch none. Do not dispatch before selection. Run the selected command immediately. When the user invokes --auto, skip this gate. Take the route for the applicable disposition 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.

Iron Law, Red Flags, and the TDD Rationalization table are in references/cook-discipline.md.

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

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.

Classify and prepare every input before execution; only the standalone fast-path skips this step. A spec needs no strict Mold format and no Mold handoff, because Cook asks for each missing plan and approval. Only a freshly accepted ready Full handoff may reach workflow.cook. Follow references/fan-pathway.md § Classified Mold-to-Cook ingress and § Preparation loop. 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 runs the inner RED → GREEN loop against the spec’s test contracts.

A closed not-applicable disposition routes the requested non-behavior change through its own verification path.

After inner TDD completes, Cook requires all inner tests and relevant gates to be GREEN before it invokes /press.

When correction = true, Cook limits the scope to the active Press corrective loop.

Cook cannot weaken or bypass existing tests.

  1. After Cook completes the inner implementation and green gates, Cook writes the package-ready report. Cook then invokes /press <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. /press --auto runs its hardening pass. It invokes /age <slug> --auto when readiness is ready for /age or follow-up recommended. Both states mean that the cooked contract is sound. Both states also mean that every changed behavior has a hardening test. Documented follow-ups are review-safe. Only blocked stops auto. ../../press/references/gap-analysis.md defines the blocked criteria once.

  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. It selects an obviously cohesive single without asking. It asks before mutation when it recommends stacked or when the shape is ambiguous. This requirement also applies 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.

  • /press returns blocked. See the blocked criteria in ../../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 invokes /press --auto, which 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
accept Validate and accept a canonical Mold handoff pointer
approve Record the user’s literal approval response as a retained MoldCookApproval
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
prepare Classify a Cook input and return a closed preparation outcome
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
resubmit Recompute a Cook preparation outcome with new evidence
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
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

Do not write production code before you have a failing test.

The RED step requires you to write a failing test.
The RED step is mandatory.
Do not perform the RED step “right after” implementation.
If the test does not exist and does not fail, the Cook loop has not started.


Stop if you think any of these statements:

  • “The behavior is obvious from the spec; a test would just restate it.”
  • “I’ll add tests in the press pass.”
  • “This is a small change; tests are overkill.”
  • “The existing tests already cover this implicitly.”
  • “The type system / linter makes a test redundant here.”
  • Do not treat the post-implementation taste-test as proof that you can skip the RED step.

Each statement is a rationalization.
Name the rationalization.
Stop.


Rationalization Why it fails Required action
“The change is obvious; a test would just mirror the code.” A mirroring test still catches future regressions. It must fail when behavior changes. It does not have to surprise you today. Write the test.
“I’ll write the test in the press pass.” Press strengthens existing tests. It does not write the first test for new behavior. Behavior without a test has no harness. Write the test first, before you write production code.
“This is a one-line fix; tests are overkill.” Change size does not predict the probability of regression. One-line fixes often have subtle edge cases. Write the narrowest test that would have caught the original bug.
“The existing suite already covers this path.” Verify the coverage. Find the specific test that fails if the new behavior regresses. If you cannot name it, you imagined the coverage. Name the specific test, or write a new test.
“The type system makes a runtime test redundant.” Types verify shape. Tests verify behavior. A function with the correct signature can still return the wrong value. Write a test that asserts the return value, not only that the code compiles.
“The taste-test lenses will catch any issues.” Taste-test is a post-implementation smell check. It does not replace executable assertions. Write the test first.
“We’re under time pressure; I’ll skip the test for this task.” Regressions cause the most harm under time pressure. The test is the least expensive available insurance. Write the test. Never use time pressure as grounds to skip the RED step.

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

  1. Give the agent a canonical Mold HandoffPointer and its retained artifacts.
  2. Supply scope, plan, and runner approvals as scripted host events.
  3. Supply setup authorization before any package or browser setup.
  4. Require cook.pyz prepare or resubmit before accept.
  5. Capture the routed input kind, approval events, setup evidence, tool calls, and final artifact references.

The trace passes only when preparation reports ready, the real consumer loads every reference, and execution produces the requested artifact.

Give the agent a strict spec with no approvals. Preparation must report needs-approval; the agent must not execute work. Supply each requested approval in a later scripted host event and require resubmit to forward it.

Start with a named user-intent hold. Re-running preparation, using --auto, or attaching arbitrary evidence must retain the hold. Only a fresh scripted user dialogue that names the hold, records clear_holds, and sets execution_authorized may be passed through resubmit --clear-hold HOLD_ID=DIALOGUE_JSON.

A supported historical pointer must pass its original route, schema, digest, and receipt checks before Cook requests missing bindings. A tampered pointer must report invalid; it must not fall back to spec text or execute.

Capture each trace with python3 -m tests.python.mold_cook_agent_driver --fixture-repository <repo> --mold-bundle <pyz> --cook-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 accepted handoff through easy_cheese.skills.cook.preparation.fan_execute.execute_fan. execute_fan adapts the existing writer, review, diagnosis, and Press dispatches into run_fan, which owns the progress-aware state machine.

  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 planworkflow.cookbind_diagnosisworkflow.cure calls define the linear steel thread. The accepted fan handoff uses execute_fanrun_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 and skip the question. Ask only when the spec has no landing block.

Apply /plate’s review-shape policy.

Preserve an explicit choice.

For one cohesive review unit, persist single without asking.

Ask only once when stacked is recommended or shape is ambiguous.

Record plate_layout in the typed handoff evidence.

Read plate_layout from that evidence.

Apply the policy do not ask 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 → age ↔ cure until clean, stalled, or blocked CurdResult + remediation state
Post-merge press → age ↔ cure → age over the merged typed results final CurdResult
Per curd, closed N/A coder(cook) → age ↔ coder(cure) until terminal not-applicable-curd
Post-merge, closed N/A age ↔ cure → age not-applicable-postmerge

Per-curd workers own incomplete implementation slices.

They never run Press while sibling curds remain unfinished.

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 global Press → Age/Cure chain only after every curd passes. 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 the global Press only after every curd passes.

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. 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. 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. Per-curd workers never run 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 global press → age → cure → age integration 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.

The fan pathway starts only after Cook has classified the input. Explicit mode wins over inference in this order:

  1. --continue enters the existing Wheypoint resolver.
  2. A canonical pointer enters strict handoff acceptance.
  3. --spec enters bounded spec ingestion.
  4. A bare slug resolves through the spec store.
  5. --task enters the focused-task path.

When no flag is supplied, inspect declared artifact structure before using a filename suffix. A malformed pointer or projection remains that artifact and returns a typed invalid outcome; it is never treated as task text. A direct spec independently checks matching continuity. A missing continuation is a cold start, while a hold, blocker, ambiguity, scope conflict, or integrity failure remains a hold even when a direct spec is also supplied.

Preparation is a pure orchestration boundary around host evidence. It may call workflow.plan with an orchestrator-provided planner result and must reuse materialize_planner_result; it does not dispatch an agent or create a human response. The transition sequence is:

scope -> planner result -> unchanged Full/partial plan approval
-> optional bounded runner setup -> accepted handoff -> execute

Each transition recomputes its outcome and revalidates every reference and hold. Only ready may enter execution. Linear plans pass their approved curd IDs to workflow.cook. Fan plans route through execute_fanrun_fan. Light work has one explicitly authorized curd and no planner ceremony. Partial work passes exactly the dependency-closed approved IDs to the selected route, while the canonical PlannerResult.unresolved_work remains durable for resumption. A changed subset or remainder invalidates the old approval and returns to needs-approval.

The agent drives the transitions with three bundle commands. Use one ARTIFACT_ROOT for the whole loop; for a Mold pointer, use the root that Mold used.

  1. Run cook.pyz prepare <source> --artifact-root "$ARTIFACT_ROOT" and save the JSON result. Name the source with --spec, --pointer, --slug, or --task.
  2. Read outcome, act, then run cook.pyz resubmit <saved result> --source <source> with every evidence flag that you supplied before plus the new one. Save each new result.
outcome Action New evidence flag
needs-approval Show the retained proposal_ref content. Ask the user once through the question transport. Run cook.pyz approve with the literal reply. --scope-approval or --plan-approval, as approval_kind names
needs-planning Dispatch a fresh-context planner on planner_request. Normalize its writer view on the host. --planner-result
needs-preparation Follow the setup authorization rules below. The host records the runner approval; approve does not. --runner-approval, --setup-authorization, --setup-evidence
blocked Show each hold. Only a fresh user dialogue clears a hold. --clear-hold HOLD_ID=DIALOGUE_JSON
invalid Stop and show the findings. none
ready Run cook.pyz accept <pointer> --spec <spec> on handoff_ref, then execute. none
Terminal window
python3 skills/cook/scripts/cook.pyz approve "$SPEC" \
--artifact-root "$ARTIFACT_ROOT" \
--request-id "<request_id from the result>" \
--kind scope \
--response "<the user's literal reply>"

For --kind plan or --kind partial_plan, add --planner-result. When a scope proposal has no plan and the spec declares no landing, name each covered curd with --curd-id. The command prints approval_path; pass that path to resubmit. A reply that is not an approval records a rejection, and the next resubmit does not advance. Only a reply to the question that showed this proposal counts. The invocation text, --auto, a status string, and a taste verdict are never a reply.

Setup authorization names one prerequisite, a finite path set, and a finite command set. Evidence must include that prerequisite, exact command and fixture, environment identity, successful exit result, and captured-output digest. Setup authority cannot clear a feature hold or authorize feature writes. Historical pointers pass their original route, schema, payload, and receipt checks before Cook asks for missing spec or approval bindings.

The host integration calls the public easy_cheese.skills.cook.execute_accepted_handoff API for the final Full handoff seam. It accepts the pointer through the shared gateway, resolves the approved plan, and checks dependency closure. A linear plan forwards handoff.coverage.curd_ids to workflow.cook. Fan topology routes through preparation.fan_execute.execute_fan, which adapts the existing dispatches into run_fan. The returned CookExecutionOutcome carries the selected execution results, covered curd ids, unchanged remainder, fan next step, and remediation state references. The callback-bearing library API is the production entrypoint; the accept CLI only validates and normalizes a pointer.

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))
### Self-eval
- [x] A failing test existed before production changes.
- [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
- /press <slug> — harden tests and check coverage
- /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.

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: inner RED → implement → taste-test

Section titled “The TDD loop: inner RED → implement → taste-test”

Cook uses a sequential TDD discipline. Each phase must have a clear exit before the next phase starts.

Closed not-applicable work routes requested docs/refactor/test/appearance work through its non-behavior implementation and verification path. N/A never means that requested work is not necessary.

When a change adds or modifies behavior, write an inner failing test before implementation. This test is Cook’s vertical loop.

For behavior changes, only the inner TDD loop can modify production code. Closed N/A work must use its declared non-behavior implementation path. It can edit only the requested surface.

If an inner test cannot fail for the expected reason, stop and fix the test before implementing. A test that passes against unimplemented code creates false-positive results.

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

For closed N/A work, make the requested docs/refactor/test/appearance change through its non-behavior path. Verify that path instead of replaying RED.

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 handoff to Press, make every inner test and relevant gate GREEN.

For closed N/A work, complete the requested non-behavior verification and taste-test. Then, hand off directly to Age. N/A has no Test Contracts for Press to attack.

A corrective Cook (correction = true) applies only to the active Press corrective loop. 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, route the review to 1 fresh opus reviewer.

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 RED 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;
  • return needs-approval before planning when scope evidence is absent;
  • materialize a Full plan once, reuse unchanged approval, and renew it when coverage or the acknowledged remainder changes;
  • keep holds across every resubmission and permit execution only from ready;
  • accept Light only with explicit bounded authority and no invented planner artifact;
  • reject runner evidence that is stale, failed, or outside its authorized paths and commands; and
  • read supported historical pointers through their original integrity route, preserving 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 approval/setup artifacts explicitly; the Cook result is recomputed from those references on every transition. The final execution-boundary test uses execute_accepted_handoff 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 approved 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”

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 only planner payload Cook accepts from an agent. The host supplies request identity, canonical curd IDs, bound artifacts, approval evidence, and any setup authorization; an agent response cannot grant execution authority. Cook preparation returns a closed outcome (ready, needs-planning, needs-approval, needs-preparation, blocked, or invalid) and only ready carries an accepted MoldCookHandoff.