Build Custom Recipe Reports with CookCLI and Templates
Your .cook files already contain structured ingredient data — names, quantities, units. The cook report command lets you turn that structured data into anything: a shopping list with product URLs, a cost breakdown per serving, a LaTeX recipe card, a CSV for a spreadsheet. It uses a Jinja2-style template engine called minijinja, so the output format is entirely up to you.
Note: cook report is currently a prototype feature. The API may change as it matures, but the core template system is already capable enough to be worth building on.
The Basics
The simplest thing you can do is render a recipe card. Given a recipe file:
And a template at recipe-card.jinja:
Run:
The template variables available in every template are:
metadata— frontmatter fields (title,servings,time, plus anything you define)ingredients— list of objects withname,quantity, andunitsections— recipe sections containing the step contentscale— the scaling factor (1.0 by default)
That is the full data model. Everything else in the template system is about querying and transforming these.
The Ingredient Database
Shopping list generation requires more than what is inside the recipe file. You need store links, prices, and aisle assignments. The ingredient database handles this.
Create a config/db/ directory. Each ingredient gets a folder, and YAML files inside it hold whatever data you want attached to that ingredient:
A shopping.yml for eggs might look like:
Inside a template, access database values with db(path, default). The path uses dot notation with underscore-converted ingredient names:
The underscore() function converts "canned tomatoes" to "canned_tomatoes" to match filesystem paths. The db() function takes an optional default as a second argument, which is useful when not every ingredient has database entries yet.
Practical Reports
Smart Shopping List
A shopping list that links to specific products and skips things you already have in your pantry:
excluding_pantry(ingredients) filters out anything marked as a pantry item in your pantry config. Run with a pantry config file:
The from_pantry(ingredients) function does the inverse — useful if you want to generate a "check your pantry for these items" section.
Cost Analysis
Track what each recipe actually costs to make:
This reads from cost.yml files in your database. A cost.yml might be:
Run with the database path:
Aisle-Organized Shopping List
If you always shop the same store in the same order, an aisle-organized list saves significant time. The aisled() function groups ingredients by the aisle assignment in your database:
The | items filter converts the grouped dictionary to a list of (aisle, items) pairs. The result is a list organized by your actual path through the store — produce, then dairy, then dry goods — rather than alphabetical or recipe order.
Process a whole week of recipes at once:
get_ingredient_list(ingredients) normalizes and deduplicates the combined ingredient list across multiple recipes, so you get one entry for "spaghetti 800g" rather than two separate entries from two pasta recipes.
Scaling
The cook report command accepts the same scaling syntax as other cook commands. Append :N to the filename to scale by a factor of N:
The scale variable in the template reflects the multiplier. Ingredient quantities are already scaled when the template receives them — you do not need to multiply manually. This means a cost report for a party of 40 is a single command, and the per-serving cost stays accurate.
Output Formats
The template engine outputs whatever text the template produces. The format is entirely determined by your template — there is no built-in output format.
Markdown for sharing:
YAML for programmatic use:
CSV for spreadsheets:
HTML for display:
The available template filters help with formatting across output types: titleize for title case, format for number formatting (Python-style "%.2f"|format(n)), round for rounding, and default for fallback values when database entries are missing.
Where to Go From Here
The cook report command is a prototype — expect the function signatures and template API to evolve. But the core idea is stable: structured recipe data plus a template engine produces whatever output your workflow needs.
The existing community templates at github.com/cooklang/cooklang-reports are worth reading before writing your own. They cover more edge cases than a blog post can.
Further reading:
- report command reference — full flag reference and current template API
- reports use case — full documentation with more template examples
- shopping workflow — how the pantry config and shopping workflow fits together
- pantry management — pantry configuration reference
-Alex