Practical guide for reading, maintaining, and creating new mando-cli recipe YAML files. Covers every step type, template variables, conditional execution, and common authoring patterns.
What Are Recipes?
Recipes are YAML files in recipes/ that define interactive CLI workflows. They’re run via cargo run -- run <path> (e.g., cargo run -- run debug/memray-container). Each recipe is a linear sequence of steps — choices, prompts, checks, commands — that guide the user through a task.
Recipes are not code generation templates. They’re interactive scripts with a UI layer.
Recipe File Structure
name: Human-readable recipe namedescription: One-line description shown in menussteps: - <step_type>: name: Step label (shown to user) command: Shell command to run when: "optional condition" ignore_errors: true # optional
Every recipe starts with name and description (used by the menu system), followed by a steps list. Steps execute top-to-bottom.
Step Types Reference
Step Type
Purpose
Key Fields
Example Use
check
Verify a precondition (fails recipe if command exits non-zero)
name, command
Check containers are running
choice
Present options to user, store selection in a variable
name (becomes var name), message, options (array of label/value)
Select target service
prompt
Free-text input from user
name, message, type (text), default
Enter endpoint path
capture
Run command silently, store stdout in a variable
name (becomes var name), command
Auto-detect port number
run
Execute a shell command, showing output
name, command, when, ignore_errors, cwd
Run docker exec
Template Variables
Variables are set by choice, prompt, and capture steps. They’re referenced as {{variable_name}} in any subsequent step field. Variables are string-replaced before execution and remain in scope from the step that sets them until the end of the recipe.
In this example, {{target}} resolves to local-forecast-1 if the user picks “Forecast”.
Conditional Execution (when)
The when field accepts simple string comparisons. If the condition evaluates to false, the step is silently skipped. If when is omitted, the step always runs.
when: "{{trace_allocators}} == True" compares the literal string "True". There is no boolean logic — true and True are different strings. Match the exact value produced by the step that sets the variable.
The ignore_errors Field
When true, the recipe continues even if the command exits non-zero. Use for:
open commands (may fail in headless environments)
Optional cleanup steps
Steps that are “nice to have” but not critical
Without it, a non-zero exit code stops the recipe immediately.
How to Create a New Recipe
Create a YAML file in the appropriate recipes/ subdirectory
Add name and description at the top
Start with a check step for preconditions (e.g., are containers running?)
Add choice/prompt steps to gather user input
Use capture steps for computed values (port detection, timestamps, etc.)
Add run steps for the actual work
Use when conditions to branch on user choices
Keep it linear
Recipes execute top-to-bottom. There are no loops, no goto, no subroutines. Use when conditions to skip steps you don’t need. This keeps recipes predictable and debuggable.
Run a recipe: cargo run -- run debug/memray-container
Or use the menu: cargo run -- run menu
Maintainability Tips
Readability
Use comment separators (# ═══════════) between logical sections in long recipes
Give every step a descriptive name — it’s what the user sees during execution
Group related steps together with comments
Repetition
memray-local.yaml repeats 4 near-identical blocks for each target x mode combination. This is a known trade-off — YAML doesn’t support functions or loops, so repetition is unavoidable. When editing, make sure to update all copies of repeated blocks.
Testing recipes
Run with -e flags to skip interactive prompts:
cargo run -- run debug/memray-container \ -e container_target=local-forecast-1 \ -e profile_mode=snapshot \ -e trace_allocators=False