Understanding Recipes¶
Recipes are declarative YAML specifications that define multi-step AI agent workflows. They provide a structured way to orchestrate complex tasks that require multiple sequential or parallel operations, with built-in support for state persistence, error handling, and human approval gates.
What is a Recipe?¶
A recipe is essentially a blueprint for AI-assisted work. Rather than manually guiding an agent through each step of a complex process, you define the entire workflow upfront in a YAML file. The recipe system then executes each step in order, passing context between steps and handling failures gracefully.
Think of recipes like cooking recipes: they specify ingredients (context), steps (operations), and expected outcomes. Just as a cooking recipe ensures consistent results regardless of who follows it, an agent recipe ensures consistent, reproducible workflows.
Core Characteristics¶
Declarative: You specify what should happen, not how to do it. The recipe executor handles the mechanics of step execution, context management, and error recovery.
Sequential with State: Each step can access the accumulated context from all previous steps. This creates a natural flow where early steps gather information that later steps act upon.
Resumable: If a recipe is interrupted (network failure, timeout, manual stop), it can be resumed from the last successful checkpoint. No work is lost.
Composable: Recipes can be simple (3-4 steps) or complex (dozens of steps with conditional branching). You build what you need.
When to Use Recipes¶
Recipes shine in scenarios where manual orchestration would be tedious, error-prone, or inconsistent.
Ideal Use Cases¶
Code Review Workflows: A recipe can analyze code changes, check for security issues, verify test coverage, and generate a comprehensive review report - all in one automated flow.
Research and Synthesis: Gather information from multiple sources, analyze patterns, synthesize findings, and produce a structured report.
Multi-Stage Deployments: Validate configuration, run tests, build artifacts, deploy to staging, run smoke tests, and optionally promote to production.
Document Generation: Analyze a codebase, extract documentation, generate API references, and compile everything into a cohesive document.
Refactoring Operations: Analyze current code, identify patterns to change, plan modifications, execute changes across files, and verify results.
When NOT to Use Recipes¶
- Simple one-shot tasks: If a single agent call suffices, skip the recipe overhead
- Highly interactive work: Recipes are designed for autonomous execution, not back-and-forth conversation
- Exploratory tasks: When you don't know the steps upfront, manual guidance is better
Recipe Structure¶
A recipe file has a clear structure with metadata, context, and steps.
Basic Anatomy¶
# Recipe metadata
name: code-review
description: Comprehensive code review workflow
version: "1.0.0"
# Input context (flat dictionary of variables)
context:
file_path: "" # Must be provided at execution time
focus_areas: "general" # Has a default value
# The workflow steps
steps:
- id: analyze-structure
agent: foundation:explorer
prompt: |
Analyze the structure of {{file_path}}.
Identify key components, dependencies, and patterns.
output: "structure_analysis"
- id: security-check
agent: foundation:security-guardian
prompt: |
Review {{file_path}} for security vulnerabilities.
Previous analysis: {{structure_analysis}}
output: "security_findings"
- id: generate-report
agent: foundation:file-ops
prompt: |
Generate a code review report based on:
- Structure analysis: {{structure_analysis}}
- Security findings: {{security_findings}}
Key Elements¶
name: A unique identifier for the recipe. Used for execution and logging.
description: Human-readable explanation of what the recipe does.
context: A flat dictionary of input variables. Variables with empty string values must be provided at execution time; variables with non-empty values serve as defaults.
steps: The ordered list of operations to execute. Each step has an id, an agent to invoke, and a prompt template. Steps use the output field to store their result in a named variable for later steps.
Steps and Context¶
Steps are the building blocks of recipes. Each step represents a discrete unit of work performed by an agent.
Step Definition¶
steps:
- id: step-identifier # Unique id within recipe
agent: foundation:explorer # Agent to invoke
prompt: | # Instructions for the agent
Your task description here.
You can reference context: {{variable_name}}
output: "step_result" # Store result for later steps
Step Types¶
Not all steps require an agent. The recipe system supports multiple step types, each suited to a different kind of work.
Agent steps are the default. They delegate work to an Amplifier agent, which processes the prompt and returns a result. Most workflow logic lives in agent steps.
Bash steps execute shell commands directly, without invoking an agent. They are useful for build commands, test runners, file operations, and any task where a deterministic shell command is more appropriate than an AI agent. A bash step captures stdout and stderr as its output, making results available to subsequent steps just like agent output.
- id: run-tests
type: bash
command: "pytest tests/ --tb=short -q"
cwd: "{{project_root}}"
timeout: 120
output: "test_output"
Recipe steps call another recipe as a sub-recipe, enabling composition of complex workflows from simpler building blocks. See the Recipe Composition section below.
- id: lint-check
type: recipe
recipe: "./lint-recipe.yaml"
context:
target: "{{file_path}}"
output: "lint_results"
Context Flow¶
Context flows through recipes in a predictable way:
- Initial Context: Variables provided at recipe execution
- Step Outputs: Each step with an
outputfield stores its result as a named variable - Accumulated State: Later steps have access to all prior output variables
# Step 1 receives initial context
- id: gather-info
prompt: "Analyze {{target_directory}}"
output: "gathered_info"
# Step 2 receives initial context + step 1 output
- id: process-info
prompt: |
Based on: {{gathered_info}}
Process the information...
output: "processed_info"
# Step 3 receives everything
- id: synthesize
prompt: |
Original target: {{target_directory}}
Gathered info: {{gathered_info}}
Processed info: {{processed_info}}
Template Syntax¶
Recipes use double-brace templating for dynamic content:
{{variable}}: Insert a context variable or a previous step's named output
To make a step's result available to later steps, add an output field to the step. The value becomes the variable name you reference downstream.
Step Options¶
Steps support additional configuration:
- id: critical-operation
agent: foundation:modular-builder
prompt: "Implement the feature..."
output: "implementation"
# Error handling
on_error: continue # Options: fail (default), continue, skip_remaining
# Timeouts
timeout: 300 # Seconds before timeout
# Conditional execution
condition: "{{validation_passed}} == 'true'"
Approval Gates¶
For workflows that require human oversight, recipes support approval gates. These pause execution at critical points, allowing humans to review progress before continuing.
Staged Recipes¶
Approval gates are implemented through staged recipes -- recipes divided into stages that require explicit approval between them. Each stage groups related steps together, and an approval block on the stage controls whether execution pauses after that stage completes.
name: production-deployment
description: Deploy to production with approval gates
version: "1.0.0"
stages:
- name: preparation
steps:
- id: validate-config
agent: foundation:explorer
prompt: "Validate deployment configuration..."
output: "config_validation"
- id: run-tests
agent: foundation:test-coverage
prompt: "Execute full test suite..."
output: "test_results"
- name: staging-deployment
approval:
required: true
prompt: |
Preparation complete. Test results:
{{test_results}}
Approve to deploy to staging?
timeout: 3600
default: "deny"
steps:
- id: deploy-staging
agent: foundation:modular-builder
prompt: "Deploy to staging environment..."
output: "staging_result"
- name: production-release
approval:
required: true
prompt: |
Staging deployment successful.
Approve production release?
timeout: 3600
default: "deny"
steps:
- id: deploy-production
agent: foundation:modular-builder
prompt: "Deploy to production..."
Approval Workflow¶
- Recipe executes until it hits a stage with
approval: required: true - Execution pauses and the approval prompt is displayed
- Human reviews the state and either approves or denies
- On approval: execution continues to the next stage. The approver can include a message (e.g., "merge" or "pr"), which becomes available in subsequent steps as
{{_approval_message}} - On denial: execution stops with the provided reason
Managing Approvals¶
# List pending approvals across all sessions
amp recipes approvals
# Approve a pending stage
amp recipes approve --session-id <id> --stage-name staging-deployment
# Deny with reason
amp recipes deny --session-id <id> --stage-name production-release \
--reason "Test coverage below threshold"
Use Cases for Approval Gates¶
- Production deployments: Human sign-off before going live
- Data migrations: Review migration plan before execution
- Bulk operations: Approve after seeing what will be affected
- Compliance workflows: Required human verification for audit trails
Advanced Features¶
Foreach Loops¶
Execute a step once for each item in a collection. The foreach field takes a variable reference containing a list. Use as to name the loop variable and parallel to control concurrency.
- id: process-files
foreach: "{{discovered_files}}"
as: current_file
parallel: 3
agent: foundation:explorer
prompt: "Analyze {{current_file}} for code quality issues."
collect: "file_analyses"
When parallel is omitted (or set to false), iterations run sequentially. Setting it to an integer allows that many iterations to execute concurrently, which is useful for independent tasks like reviewing a list of files. Setting it to true runs all iterations simultaneously.
While/Convergence Loops¶
Some workflows need to iterate until a quality threshold is met rather than running a fixed number of times. The while_condition field causes a step to repeat as long as the condition evaluates to true. Combined with update_context (to mutate variables each iteration) and break_when (for early exit), this enables convergence patterns.
- id: refine-draft
agent: foundation:zen-architect
prompt: |
Current draft quality score: {{quality_score}}
Improve the draft and return a revised version with a new score.
Return JSON: {"draft": "...", "sufficient": "true" or "false"}
output: "refinement"
parse_json: true
while_condition: "{{quality_sufficient}} != 'true'"
break_when: "{{iteration_limit_reached}} == 'true'"
max_while_iterations: 10
update_context:
quality_sufficient: "{{refinement.sufficient}}"
The step re-executes after each iteration with updated context. Once quality_sufficient becomes "true", the loop exits. The break_when guard and max_while_iterations prevent runaway loops if convergence is slow.
Conditional Execution¶
Steps can be skipped entirely based on a condition. The condition field accepts an expression that evaluates against the current context. If it evaluates to false (or an empty/falsy value), the step is skipped and execution moves to the next step.
- id: security-scan
condition: "{{security_required}} == 'true'"
agent: foundation:security-guardian
prompt: "Perform security scan on {{file_path}}..."
Conditions are evaluated at runtime, so they can depend on the output of earlier steps.
Expression Operators¶
Recipe expressions in condition, while_condition, and break_when fields support the following operators:
- Comparison:
==,!= - Logical:
and,or
condition: "{{severity}} == 'critical' or {{severity}} == 'high'"
while_condition: "{{converged}} != 'true' and {{max_reached}} != 'true'"
Numeric comparisons (<, >, >=, <=), the not operator, and parentheses for grouping are planned but not yet implemented. Structure conditions around string equality checks.
Recipe Composition¶
A step with type: recipe calls another recipe file as a sub-recipe. This enables building complex workflows from smaller, tested building blocks. The sub-recipe runs to completion, and its final output becomes the step's result.
- id: lint-and-format
type: recipe
recipe: "./lint-recipe.yaml"
context:
target: "{{file_path}}"
fix_mode: true
output: "lint_result"
- id: run-tests
type: recipe
recipe: "./test-recipe.yaml"
context:
test_dir: "{{test_directory}}"
output: "test_result"
Composition keeps individual recipes focused and reusable. A deployment recipe might compose a build recipe, a test recipe, and a deploy recipe rather than inlining all those steps.
Step Dependencies¶
Within a stage, steps normally execute in the order they are listed. The depends_on field lets you declare explicit dependencies between steps, enabling the recipe executor to determine safe execution order. Steps whose dependencies are all satisfied can potentially run in parallel.
steps:
- id: fetch-data
agent: foundation:explorer
prompt: "Fetch data from the API..."
output: "fetched_data"
- id: fetch-config
agent: foundation:explorer
prompt: "Read configuration files..."
output: "fetched_config"
- id: merge-results
depends_on:
- fetch-data
- fetch-config
agent: foundation:zen-architect
prompt: |
Combine data: {{fetched_data}}
With config: {{fetched_config}}
Rate Limiting¶
For workflows that interact with external services or APIs, recipe-level rate limiting prevents overwhelming those systems. The rate_limiting field controls how fast LLM calls execute across the entire recipe tree.
name: bulk-api-calls
version: "1.0.0"
description: Workflow with rate limiting
rate_limiting:
max_concurrent_llm: 3
min_delay_ms: 500
backoff:
enabled: true
initial_delay_ms: 2000
steps:
# ...
The max_concurrent_llm field limits concurrent LLM calls globally. The min_delay_ms field adds pacing between calls. The backoff block configures adaptive backoff for handling rate limit (429) errors. This is especially useful in foreach loops where many iterations could otherwise fire simultaneously.
Error Recovery¶
Configure how failures are handled:
- id: optional-optimization
agent: foundation:zen-architect
prompt: "Optimize if possible..."
on_error: continue # Don't fail the whole recipe
Key Takeaways¶
-
Recipes are declarative workflows: Define what you want, not how to do it. The recipe system handles execution mechanics.
-
Multiple step types: Agent steps for AI work, bash steps for deterministic commands, recipe steps for composition. Use the right type for each task.
-
State flows through named outputs: Each step's
outputfield stores its result as a named variable accessible to subsequent steps via{{output_name}}. -
Resumability is built-in: Interrupted recipes can be resumed. Checkpointing happens automatically.
-
Approval gates enable human oversight: Staged recipes pause between stages for human approval. Approvers can pass messages that subsequent steps can act on.
-
Loops handle iteration: Foreach loops process collections (with optional
parallelconcurrency). While loops converge on quality thresholds or exit conditions. -
Compose, don't monolith: Build complex workflows by composing simple, tested sub-recipes. Keep individual recipes focused and reusable.
-
Start simple, grow as needed: Begin with linear sequences of steps. Add stages, conditions, loops, and composition only when your workflow demands it.
Recipes transform complex, multi-step processes into repeatable, reliable workflows. They bridge the gap between manual agent interaction and fully automated pipelines, giving you control over the workflow design while letting AI handle the execution.