Chapter 7 — Chefs and the Kitchen Board: Planning Paradigms
# Chapter 7 — Chefs and the Kitchen Board: Planning Paradigms
A line cook executes. A chef decides what to execute — and sometimes the decision is the deliverable: the plan itself, checked and signed, before any pan is hot.
The remaining four paradigms are the planning family. Where the linear
set (Chapter 6) draws lines and loops, these draw decompositions:
planner produces a plan and checks it, rewoo plans every tool call up
front so the model reads the world once, htn decomposes tasks into
methods, and blackboard lets specialists contribute to a shared board
in whatever order the board dictates. Same method as last chapter —
contract first, recipe second, receipts always — plus the craft question
this family exists for: when does planning beat doing?
# Where we left off
The linear drawer is stocked: add_truncate, summarize_funcs,
polish_docstring — linted, registered, with a three-layer validation
story and a lock-error scar to show for it. Today finishes the drawer.
# Technical requirements
- The end-of-Chapter-6 state: binaries, green workspace, Ollama serving
gemma4:e4b. - About thirty-five minutes; the one dispatch run is time-boxed and its outcome — a governance catch — is captured below.
- Captured on the verification machine as always.
# The four contracts
Each paradigm is a contract — data declaring its directives, their
grammar, their order. Read straight from cognitionzoo/<paradigm>/contract.go
as of the pin:
| Paradigm | Shape | Directives (order enforced) | Composes |
|---|---|---|---|
planner |
PlanExecute | plan "…" → step "…": → verify "…" → summarize "…" |
— |
rewoo |
StagedPlan | plan "…" (required) → step "…": → synthesize "…" |
— |
htn |
Decomposition | method "…": → task "…": (requires method) |
react |
blackboard |
Blackboard | source <name>: (repeatable) |
— |
Facts the contracts add beyond the grammar:
- A
stepblock’s body isdoonly — in planner, rewoo, and htn. The step legs invoke capabilities (do relurpic:…), not model tools. And here the honest boundary from Chapter 5 returns: there is no load-time check that adotarget’s input schema is satisfied, and no DSL form produces literal map arguments — so capabilities that need literal inputs (the docs nametest_run) are not authorable today. This is why the shippedplan.erpecarries no steps: its plan document is the product. - htn composes react — tasks execute “in-envelope over a react primitive executor.” Decomposition on the outside, the familiar bounded loop on the inside.
- Blackboard authored sources replace the built-in specialist set.
From
authored_source.go: sources run as a controller loop in declaration order, each with an optionalwheneligibility predicate,readstate keys, a requiredwritestate target, and an optionalcapabilitypin. And the sentence that explains a whole class of receipts: authored structure is authoritative — with no model calls beyond what a source’s own execution performs. A no-dosource is a data-flow skeleton, not a conversation.
# When planning beats doing
A choosing table you can argue with — that is the point:
| Reach for | When | Why |
|---|---|---|
planner |
The deliverable is the plan, or execution is a separate, reviewed act | plan → verify → summarize is a checkpoint machine; a human can grade the plan before any step runs |
rewoo |
The task needs several tool calls whose shape is knowable up front | one planning pass, steps that depend only on earlier results, one synthesis — the model reads the world once instead of thinking-acting-observing its way into context bloat |
htn |
The work decomposes into named subtasks with known structure | methods and tasks are the recipe’s own work breakdown structure, executed by react underneath |
blackboard |
The shape of the work is not knowable up front and specialists should react to what the board holds | data-driven order: each source runs when its when predicate says the board is ready for it |
And the negative space: planning beats doing when the plan is cheap
relative to the mistakes it prevents. For a one-function fix in a
two-file repo, react is the right tool — planning it first is
ceremony. The shipped corpus agrees: plan.erpe serves the planning
family and never writes; debug_tdd_repair serves the fixers.
# Hands-on
Three recipes, lint-first. All three passed the linter on the first
attempt — Chapter 6’s scars at work — including the blackboard clause
forms (read [state.x], write state.x), which the linter confirms at
grammar level.
# 1. planner — plan_repair
Modeled directly on the shipped plan.erpe (read it first —
relurpify_cfg/euclo/plan.erpe — it is the reference implementation of
the form). relurpify_cfg/euclo/plan_repair.erpe:
thoughtrecipe euclo.thoughtrecipe.plan_repair
"Produce a verified repair plan for a failing test in stringkit: plan, verify, summarize. Planning never writes."
trigger as capability:
may read workspace
may invoke ["file_read", "file_list", "file_search"]
family ["planning"]
keyword ["plan repair", "repair plan"]
input workspace: "**/*"
input prompt: user.request
agent planner uses planner
run planner:
may invoke ["file_read", "file_list", "file_search"]
from input.prompt
plan """Produce a concrete, ordered repair plan for the failing test described by the user. Ground every step in the real files and functions of this workspace. The user request is: {{ index . "task.instruction" }}"""
verify "Check that every step names a real file or function in stringkit and that the plan ends with running the test suite to confirm the repair."
summarize "Produce the final ordered repair plan, leading with the first step the user should take."
capture result -> state.planNo step blocks — deliberately. The plan is the product; Chapter 10’s
plan/build pair will consume it. The verify line is where the planner
earns its keep: the model checks its own plan against a stated standard
before summarizing.
# 2. rewoo — rewoo_outline
relurpify_cfg/euclo/rewoo_outline.erpe:
thoughtrecipe euclo.thoughtrecipe.rewoo_outline
"Plan the investigation steps up front, execute nothing, synthesize the outline. ReWOO separates planning from observation."
trigger as capability:
may read workspace
may invoke ["file_read", "file_list"]
family ["investigation"]
keyword ["rewoo", "outline"]
input workspace: "**/*"
input prompt: user.request
agent rewooer uses rewoo
run rewooer:
may invoke ["file_read", "file_list"]
from input.prompt
plan """For the user's request, list the tool calls an investigator should make, in order, with each step depending only on earlier results. The user request is: {{ index . "task.instruction" }}"""
synthesize "Turn the plan and any step results into a concise investigation outline for the user."
capture result -> state.outlineplan is the one required directive; steps are optional (and do-only
when present); synthesize closes the shape. Without steps, rewoo is a
plan-and-synthesize instrument — the form you want when the outline is
the artifact.
# 3. blackboard — board_survey
relurpify_cfg/euclo/board_survey.erpe:
thoughtrecipe euclo.thoughtrecipe.board_survey
"Two authored blackboard sources: explorer surveys stringkit, analyst reviews the findings. Authored sources are the data-flow skeleton; a no-do source performs no model calls."
trigger as capability:
may read workspace
may invoke ["file_read", "file_list"]
family ["investigation"]
keyword ["board"]
input workspace: "**/*"
input prompt: user.request
agent board uses blackboard
run board:
may invoke ["file_read", "file_list"]
from input.prompt
source explorer:
read [input.prompt]
write state.survey
source analyst:
read [state.survey]
write state.reviewRead it as the architecture, not a conversation: explorer’s output lands
in state.survey; analyst reads the board and writes state.review.
With no capability pinned and no do leg, neither source performs
model calls — this recipe is the skeleton, and it lints, registers, and
dispatches as exactly that. The built-in specialist lifecycle
(Explorer → Analyzer → Planner → Review → Executor → FailureTriage →
Verifier → Summarizer, per the package doc) shows what a fully-staffed
board looks like; wiring your own specialists to capabilities is builder’s
book territory.
# 4. Dispatch plan_repair — and watch governance make the catch
Restart, pin, dispatch:
/recipe euclo.thoughtrecipe.plan_repairPinned recipe for this session: euclo.thoughtrecipe.plan_repair (dispatch runs exactly this recipe; /recipe clear to unpin)Plan the repair for a failing slugify test: the function keeps punctuation.
Produce an ordered, verified plan.The captured session’s receipt chain, in order:
{"decided_by": "pinned", "node.id": "euclo.dispatch"}
{"node.id": "run.15.5.planner.0.execute"}
{"message": "node planner_execute execution failed: tool file_read blocked: input schema invalid: $.path required"}
{"outcome": "failure", "llm_calls": "0",
"outcome_kind": "execution failed: node planner_execute execution failed: tool file_read blocked: input schema invalid: $.path required"}Read that middle line slowly, because it is the governance system doing
its job in front of you: the planning model generated a file_read tool
call, the tool manifest’s schema requires a path argument, the model
omitted it — and the manifest schema validation blocked the call,
naming the exact JSON path ($.path required). The default step-error
policy aborted the route, and the failure surfaced with its full cause.
No silent garbage in, no confident garbage out.
Two things to take from the capture:
- The fix is a retry or a better model.
/retryre-rolls; a model that emits complete tool arguments passes. Schema-blocked tool calls are the system working, not the system failing. - The
llm_callscounter reads0again — as it did for the chainer in Chapter 6, while react turns counted their calls (Chapter 2’s five). Two paradigms, same symptom: the counter appears react-bound as of this pin.[NEEDS CONFIRMATION: llm_calls counting for non-react paradigms at your pin]— treat benchmark-style counters for planner/chainer/htn/blackboard runs as unverified until that is resolved.
# Gotchas
steplegs aredo-only in planner, rewoo, and htn — and capabilities needing literal inputs are not authorable today (no DSL form produces a map argument). Plan-and-report recipes like the shippedplan.erpeare the working form; execution legs belong torunblocks in routes or pipelines.- htn’s
taskrequiresmethod, and both are blocks, not lines — the D1 mixing rule from Chapter 5’s contract reading applies here too: authored structure without its governing objective is a load error. - Blackboard
writeis mandatory per source. A source that writes nothing is not a specialist; the linter and the lowering both insist. - Authored sources replace the built-ins wholesale. Your two-source board does not run alongside the Explorer→…→Summarizer lifecycle — it replaces it for that execution.
- Counter skepticism.
llm_callsreads 0 for planner and chainer runs as of this pin; do not benchmark on it across paradigms. - Planning never writes by convention. The shipped planning recipe’s description says so; your planning recipes should keep the discipline — read-only vocabulary in the trigger is the enforceable form.
# Summary
- Four contracts, four shapes: plan-execute, staged-plan, decomposition-over-react, and a specialist board.
- The
do-only step body and the literal-input limitation explain the shipped corpus’s design: planning recipes produce plans; execution lives in runs, routes, and pipelines. - Blackboard authored sources are a data-flow skeleton — declaration order, eligibility, read/write lanes — with model calls only where a source’s own execution puts them.
- The captured plan_repair dispatch shows governance catching a
malformed tool call at the schema layer, naming
$.path, and failing honestly — the system working. - The choosing table is a starting position: plan when the plan is the product or the checkpoint is cheap; do when the task is small; board when the work’s shape is data-driven.
# Check yourself
- Why does the shipped
plan.erpecontain nostepblocks, and what would a step block require that the DSL cannot currently give it? - In
board_survey, what happens during dispatch if you swap the two sources —analystbeforeexplorer— and why does the contract make that legal rather than a load error? - Your rewoo recipe’s
plandirective is missing entirely, butstepandsynthesizeare present. What happens, and which contract field decides it? - The planner’s model emitted a
file_readwithoutpath. Name the layer that blocked it, the exact diagnostic it produced, and the two operator responses the chapter offers. llm_callsread 5 for a react turn and 0 for planner and chainer turns. What should you conclude — about the turns, and about the counter?
Answers. 1. Its plan document is the product (read-only planning
family), and a step block’s body is do-only — capabilities whose input
schemas need literal arguments (like test_run’s command) are not
authorable today. 2. Sources run in declaration order with per-source
eligibility; analyst would read state.survey before explorer wrote it
— an empty read context, legally. The contract enforces order of
eligibility, not correctness of dataflow; the recipe author owns the
lane wiring. 3. It is a load error: rewoo’s contract marks plan
Required: true — authored structure without its governing objective is
rejected, the same D1 principle Chapter 5 applied to reflection. 4. The
tool-manifest schema validation layer, at execution; the diagnostic is
tool file_read blocked: input schema invalid: $.path required; the
responses are /retry (re-roll the model’s call) or use/switch to a
model that emits complete arguments. 5. About the turns: nothing — the
counter is the liar here. About the counter: as of this pin it appears
react-bound (5 on react turns, 0 on planner and chainer turns); flag it,
do not benchmark across paradigms with it.
# Try it yourself
- The board with teeth. Add a
wheneligibility predicate toanalyst(the route predicate grammar applies:when state.survey is …orwhen missing …), lint, and reason through which cycles each source is eligible in. Then pin and dispatch, and read the step events for the cycle count. - Method, then tasks. Write an
htnrecipe with onemethodand twotaskblocks whose bodies you leave empty. Lint it, read the error (both are blocks that require bodies), and then decide: given thedo-only body rule, what could a legal htn task body invoke today? Write the answer in one sentence next to the recipe.
# Where next
The drawer is full: eight paradigms, every directive, a choosing table
earned from contracts and receipts. But a recipe is still a single card
pinned for one turn. Chapter 8 opens the prompt DSL — the files that
shape what every one of these paradigms says to the model — and your
first edited system prompt goes live with a prompt.resolved receipt to
prove it.
The lab for this chapter lives in
docs/cooking-agentic-thoughts/labs/ch07-planning-paradigms/ — the three
recipes, the captured governance catch, and the contract pointers.