“Research this, compute some percentage of it, write a poem about the result.”Every plan the planner re-derives the same steps. You pay for the LLM time every time. What if you could write the plan down once, in plain markdown, and have the planner load it on demand when it recognizes a match? That’s a recipe.
The core idea: progressive disclosure
You could try solving this by dumping a big “how to coordinate these agents” paragraph into the planner’s system prompt. Fine for one pattern. Doesn’t scale — after 20 patterns, your system prompt is 20,000 tokens and the planner is paying to read it all on every request, even the ones that don’t need any of them. You paid for the body’s tokens exactly once per plan, and only when the recipe was actually relevant.Your first recipe
Let’s write one. Create a file atgateway/recipes/research-math-poem/RECIPE.md:
gateway/recipes/research-math-poem/RECIPE.md
Watching it load
Restart the gateway (Ctrl-C in its terminal,npm run dev again). You’ll see a new log line on boot:
Three because two recipes shipped with the gateway by default —
multi-agent-research and payment-required-flow — plus your new one.load_recipe, and now has your playbook in context. The rest of the plan — research, math, poet — follows the recipe.
Does it actually change behavior?
Sometimes yes, sometimes no. The planner was already good at this class of question; the recipe mostly pins the behavior (forces the specific tool order, specific call shapes) rather than enabling something new. Where recipes shine:Edge-case handling
A recipe that says “if you see
state: payment-required, surface the payment URL to the user and STOP — do not retry” is a policy the planner wouldn’t invent on its own.Tenant-specific rules
A recipe visible only to a certain agent can encode rules like “always include a disclaimer” or “always call the compliance agent first.”
Multi-hop orchestration
A recipe describing a 5-step workflow is a document your team can review, version, and reason about. Inline planner reasoning isn’t.
Recipe layouts
Two supported shapes:- Flat
- Bundled
When the planner loads a bundled recipe, the
load_recipe tool result includes a <recipe_files> listing of the sibling files (capped at 10 for token sanity). The planner can refer to them by relative path in its response or follow instructions in the body like “run scripts/validate.sh before responding.”Frontmatter reference
Unique `name`
Unique `name`
Duplicate recipe names cause boot to fail with a clear error — silent precedence would make behavior depend on filesystem order.
No `call_` prefix
No `call_` prefix
Planner tool ids look like
call_agent_skill; a recipe named call_anything would visually collide in the load_recipe tool description. Rejected at load time.Per-agent recipe visibility
The gateway’s agent configs (ingateway/agents/*.md) have a permission: block. You can use it to scope recipes:
gateway/agents/planner.md
The planner only sees (and can only load) recipes matching its allowed patterns. Default is
allow — agents with no recipe: rules see everything.The full authoring loop
Read the SSE stream for a load_recipe tool call.
That’s the planner saying “I recognized this pattern.”
Recipes are the single highest-leverage operator tool in the gateway. Spend an afternoon writing five for your common question shapes and you’ll notice your planner’s behavior firming up across the board.