/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).
Contract
Section titled “Contract”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.
Phase entry
Section titled “Phase entry”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.
Inputs
Section titled “Inputs”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:
--autochains/press → /age → /cure.--hardpropagates through/plate.--open-prlets terminal/platepublish. 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 whosedependenciescrosslanding.layersis refused before any coder dispatch.
Optional context payload:
handoff_context.wiki_hitscarries{page, line, why}entries from the repository wiki corpus. The key is optional, and its default is absent. Reject an entry that omitspage,line, orwhy. 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.mddefines the payload.
Read references/auto-mode.md, references/fan-pathway.md, and ../cheese/references/formatting.md for these policies.
Standalone fast-path
Section titled “Standalone fast-path”/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.
- Contract — Confirm behavior, non-goals, scope, gates, and applicability.
Print the shape-check block from
../mold/references/shape-check.mdinside the Contract, or the lineshape check skipped: single-module changepershape-check.md§ When to skip. No block, no code. If.cheese/glossary/<slug>.mdexists, use its canonical terms. - Implement — Use inner RED → GREEN for behavior changes. Use the requested non-behavior path for closed N/A work; change only the applicable surface.
- Validate — Run the relevant quality gates again. Read the complete gate output; for closed N/A, verify the requested non-behavior path.
- 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.mdfor details. - 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.
Fan pathway
Section titled “Fan pathway”/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.
Baseline capture
Section titled “Baseline capture”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.
Quality gates
Section titled “Quality gates”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.
Output
Section titled “Output”Use the house style in ../cheese/references/formatting.md.
Use references/package-report.md to report files, reasons, checks, risks, and the next skill.
Handoff slug
Section titled “Handoff slug”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 | doneartifact: <path to the upstream artifact this run consumed, or empty>taste_test: inline-pass | dispatched-pass | revised | deferred-to-orchestratordurable_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.
Handoff
Section titled “Handoff”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/plateresolves 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.
Auto mode
Section titled “Auto mode”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.
No-chain isolation directive
Section titled “No-chain isolation directive”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, orI think. - State what the gate output shows.
Discipline
Section titled “Discipline”Iron Law, Red Flags, and the TDD Rationalization table are in references/cook-discipline.md.
Agent resolution
Section titled “Agent resolution”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.
Mold-to-Cook ingress and preparation
Section titled “Mold-to-Cook ingress and preparation”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.
/cook — Auto mode chain mechanics
Section titled “/cook — Auto mode chain mechanics”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.
Cook entry preflight
Section titled “Cook entry preflight”--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.
What auto mode does
Section titled “What auto mode does”-
After Cook completes the inner implementation and green gates, Cook writes the package-ready report. Cook then invokes
/press <slug> --auto. Cook appends--open-pronly when the user supplied that flag.--open-pris publication permission, and auto mode never creates it. Without that flag, the chain stays commit-only. Cook also forwards--hardwhen the user supplied it. -
/press --autoruns its hardening pass. It invokes/age <slug> --autowhen readiness isready for /ageorfollow-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. Onlyblockedstops auto.../../press/references/gap-analysis.mddefines the blocked criteria once. -
/age <slug> --autowrites the report. It then invokes/cure <slug> --auto --stake medium+. Every Age dispatch carries the pipeline slug,--auto, and any user-supplied--hard. -
/cure --auto --stake medium+bypasses the selection gate. It applies every finding withblocker,high, ormediumseverity. It also applies every cheapLowfinding that has a contained fix. It then invokes/age <slug> --scope <touched-paths> --autofor 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> --autowithout the slug. The call also forwards--hardwhen the user supplied it. -
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.
-
In the linear chain,
/cooknever invokes/plate. At the chain terminal,/curedispatches/platefor an existing pull request. For a new pull request,/curedispatches/plateonly when the user supplied--open-pr. In the fan pathway, the Cook orchestrator owns its own terminal/platedispatch./platehonors 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.
Cap enforcement
Section titled “Cap enforcement”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.
When auto mode stops early
Section titled “When auto mode stops early”-
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. -
/pressreturnsblocked. 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.
No-chain isolation directive
Section titled “No-chain isolation directive”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.
Failure handling inside cure
Section titled “Failure handling inside cure”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.
Final report
Section titled “Final report”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 summaryPasses: <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/cook bundle commands
Section titled “/cook bundle commands”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 |
/cook — TDD Discipline
Section titled “/cook — TDD Discipline”Iron Law
Section titled “Iron Law”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.
Red Flags
Section titled “Red Flags”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 table
Section titled “Rationalization table”| 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. |
Cook evals
Section titled “Cook evals”Run these trace scenarios against a fresh OMP task agent in an isolated fixture repository. Supply the changed Cook bundle explicitly.
Canonical handoff reaches execution
Section titled “Canonical handoff reaches execution”- Give the agent a canonical Mold
HandoffPointerand its retained artifacts. - Supply scope, plan, and runner approvals as scripted host events.
- Supply setup authorization before any package or browser setup.
- Require
cook.pyz prepareorresubmitbeforeaccept. - 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.
Direct spec stays gated
Section titled “Direct spec stays gated”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.
User hold stays locked
Section titled “User hold stays locked”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.
Historical input fails closed
Section titled “Historical input fails closed”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.
Trace acceptance
Section titled “Trace acceptance”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.
/cook — Fan pathway mechanics
Section titled “/cook — Fan pathway mechanics”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.
Existing handoffs guard
Section titled “Existing handoffs guard”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, orremove 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.
-
Build a
PlannerRequestfrom the authored spec. Select the request kind from the failure class, as## Planner request kindsdefines. Dispatch the planner througheasy_cheese.shared.workflow.plan. The planner returns aPlannerResultWriterView.planmaterializes this view into onePlannerResult. IfPlannerResult.planis absent, stop before any worker dispatch. Preserve the failure in the handoff. -
Take
planner_result.plan. Calleasy_cheese_schemas.validate_curd_plan. Use the returnedCurdPlanfor every subsequent operation. Validation is the preflight. Complete validation before the first Cook writer, reviewer, or diagnosis dispatch.Read a
.curd-plan.jsonartifact througheasy_cheese_schemas.schema_runtime.load_curd_plan.load_curd_planaccepts a decoded JSON mapping or raw JSON, structures it into a typedCurdPlan, and runsvalidate_curd_planon that value.load_curd_planrejects YAML or Markdown frontmatter as the wrong artifact format. Never pass a decoded JSON mapping straight tovalidate_curd_plan. -
Schedule
CurdPlan.curdsin topological waves that respect dependencies. A blocked prerequisite produces a deterministic blockedCurdResultfor its dependents. Never use declaration order instead of the plan’s dependency graph. -
Keep the linear path on
easy_cheese.shared.workflow.cookwith the validated plan. The host resolves everyArtifactRefwithresolve_artifact. The host finalizes exactly oneCurdResultfor each selected curd throughnormalize_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_fanadapts the existing writer, review, diagnosis, and Press dispatches intorun_fan, which owns the progress-aware state machine. -
run_fanschedules the validated plan in topological waves. A blocked prerequisite produces a deterministic blockedCurdResultfor 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 aDiagnosisResultWriterView. The canonical normalizer produces aDiagnosisResult. Only a confirmed result can continue to Cure. Bind the result to the exact source plan and curd. Useeasy_cheese.shared.workflow.bind_diagnosis(plan, curd, diagnosis_result). -
The linear path calls
easy_cheese.shared.workflow.curewith the same validatedCurdPlan. The fan path calls its adapted Cure callback throughrun_fan. Supply the complete tuple or mapping ofCureDiagnosisBindingvalues. Before dispatch, Cure validates each binding’s plan reference, curd reference, digest, and confirmed disposition. Cure then repeats artifact resolution and host-ownedCurdResultnormalization. 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.
Planner request kinds
Section titled “Planner request kinds”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.
Mode selection
Section titled “Mode selection”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.
Publication topology preflight
Section titled “Publication topology preflight”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.
Milknado seam
Section titled “Milknado seam”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— Bothmilknado_todo_claimandmilknado_node_verifyare present. Milknado owns the DAG, per-node worktrees, and verify-until-green process./cookdispatches the typed curd operation for each claimed node.tracker— Onlymilknado_todo_addis present. Milknado records typed curd status but does not run curds./cookstill 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.
Phase-chain topology
Section titled “Phase-chain topology”| 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.
Recovery and aggregate gates
Section titled “Recovery and aggregate gates”-
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 returnsstatus: needs-context: <one-line gap>with compact observations, about 2,000 tokens maximum. Observations list completed work, remaining work, up to 16 targetedpath#start-endentries, 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’svalidatethencheckpointcommands; only that skill documents their executable form. Use Cook’swheypoint-resolvecommand for retry resolution. Require resolver outcomeauthoritativewith a non-empty, validatedworking_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 secondneeds-contexthalts. The parent never implements the unfinished slice. This is same-phase orchestration, not a Cook→Cook transition. Known-false lead: the compiled registry has nocook -> cookroute; do not re-investigate or publish--next cook. The publishedwrite-handoff-artifactremains--phase cook --next age; the checkpoint is not that terminal phase artifact. The host finalizes the blockedCurdResultand 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.
Worktree harvest and teardown
Section titled “Worktree harvest and teardown”-
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
CurdResultfor 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/meltcannot resolve the conflict, use per-curd PRs. The worktrees share one object store. Therefore, this operation does not requiregit fetch. -
Tear down with
python3 skills/cook/scripts/cook.pyz worktree teardown --path <worktree-path> --branch <curd-branch>. A completed run leaves noworktree-agent-*branch. It also leaves no stray worker directory. -
Run wiring in dependency order. Then run the one global
press → age → cure → ageintegration pass. -
/cookalone performs harvest. The Cook fan orchestrator owns the terminal/platedispatch. Terminal Cure owns publication only in the linear chain. Never dispatch/plateduring 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
Section titled “–resume ”--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.
Classified Mold-to-Cook ingress
Section titled “Classified Mold-to-Cook ingress”The fan pathway starts only after Cook has classified the input. Explicit mode wins over inference in this order:
--continueenters the existing Wheypoint resolver.- A canonical pointer enters strict handoff acceptance.
--specenters bounded spec ingestion.- A bare slug resolves through the spec store.
--taskenters 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 transitions
Section titled “Preparation transitions”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 -> executeEach 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_fan → run_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.
Preparation loop
Section titled “Preparation loop”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.
- Run
cook.pyz prepare <source> --artifact-root "$ARTIFACT_ROOT"and save the JSON result. Name the source with--spec,--pointer,--slug, or--task. - Read
outcome, act, then runcook.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 |
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.
Package-ready report
Section titled “Package-ready report”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.
Output shape
Section titled “Output shape”## 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)Honesty rules
Section titled “Honesty rules”- 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.mdrequires.
Stop conditions
Section titled “Stop conditions”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.
Baseline capture ownership
Section titled “Baseline capture ownership”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.
Classification taxonomy
Section titled “Classification taxonomy”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.
Three-way gate policy
Section titled “Three-way gate policy”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.
Baseline block shape
Section titled “Baseline block shape”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.yamlStore 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 platedrun_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.
Loud, never hidden
Section titled “Loud, never hidden”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.
Repair pathway
Section titled “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
- Dedupe — You must dedupe against a live
repair_dispatch. A liverepair_dispatchhas an existing branch. Its handoff chain has not reached terminalstatus: okorstatus: halt. Skip this dispatch when the baseline artifact already holds a live dispatch. Never dispatch a second repair for the same debt. - 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. - 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/cookexample:python3 skills/cook/scripts/cook.pyz worktree create --slug repair-<slug> --base origin/main. - Dispatch — Use the repair worktree to dispatch a concurrent
/pasteurizein an isolated worktree. In the brief, identify the recorded failures as the symptom. Includesuite,test_id, andsignaturefor 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> --autofor 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. - Record — Write
repair_dispatch: {slug, branch, run_branch}into the baseline artifact. Use the typed Cook handoff in both frames. Addprafter/platepublishes 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.
Merge-time topology
Section titled “Merge-time topology”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.
Consumers
Section titled “Consumers”/cookwrites thebaseline:block./press,/age, and/curehonor the block. Applyno re-halt, no re-flag of identical entries./cheese --continuetreats the block as settled state, not an open question./cook’s fan pathway validates the baseline artifact that the typed handoff names./plateapplies 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.
Inner TDD — failing tests first
Section titled “Inner TDD — failing tests first”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.
Implement — minimal green
Section titled “Implement — minimal green”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.
Reviewable by construction
Section titled “Reviewable by construction”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 (
ias a loop index,db,ctx) is exempt. Reviewers find defects about 19% faster with full words (Hofmeister et al., 2019)./agegrades this underdeslop. - 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
matchorswitchover a closed union exhaustive withassert_never(mypy/pyright) orassertNever(typescript-eslintswitch-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
### Risksso/platecan 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.
Risk flag
Section titled “Risk flag”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)atdefault/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
/agereport. - A general worker can qualify only under the shared prompt-only read-only degradation.
- Resolve the fresh-context taste-test through
- 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.
Two-round cap
Section titled “Two-round cap”best: implement → taste-test (all pass) → pressworst: 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.
Self-evaluation before handoff
Section titled “Self-evaluation before handoff”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.
Boundary-specific RED checks
Section titled “Boundary-specific RED checks”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-approvalbefore 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-view schemas
Section titled “Cook writer-view schemas”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”
Mold-to-Cook boundary
Section titled “Mold-to-Cook boundary”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.