Step Identification
Step Identification¶
Assign unique IDs to steps for explicit output referencing. This is particularly useful in complex workflows where multiple steps produce outputs and you need to reference specific results.
Available Step Reference Fields¶
When you assign an ID to a step, you can reference multiple fields from that step's execution:
| Field | Type | Description | Example |
|---|---|---|---|
${step-id.output} |
string | Standard output (stdout) from step | ${test-step.output} |
${step-id.exit_code} |
number | Process exit code (0 = success) | ${build.exit_code} |
${step-id.success} |
boolean | Whether step succeeded (exit_code == 0) | ${lint.success} |
Source: Field resolution implemented in src/cook/expression/mod.rs:187-200
These fields are automatically available for any step with an id field. They're commonly used in conditionals and error handling:
Basic Step IDs with Auto-Captured Fields¶
- shell: "cargo test"
id: "test-step"
# Reference step's automatic fields
- shell: "echo 'Exit code: ${test-step.exit_code}'"
- shell: "echo 'Success: ${test-step.success}'"
- claude: "/analyze-test-output '${test-step.output}'"
when: "${test-step.exit_code != 0}"
Note: The .output, .exit_code, and .success fields are automatically captured for any step with an id. You don't need to explicitly configure output capture for these standard fields.
Custom Output Fields¶
For capturing specific files or structured data, use the outputs field:
- claude: "/prodigy-code-review"
id: "review"
outputs:
spec:
file_pattern: "*-spec.md"
# Reference custom output field
- claude: "/prodigy-implement-spec ${review.spec}"
id: "implement"
Source: Real example from src/cook/mod_tests.rs:223-228 and src/config/command.rs:1049
Custom outputs are useful for: - Capturing generated files (specs, reports, configs) - Passing structured data between steps - Referencing specific artifacts by name
When to Use Step IDs¶
1. Conditional Execution Based on Step Results
Step IDs enable precise control flow using the auto-captured .exit_code and .success fields:
- shell: "cargo test --lib"
id: "unit-tests"
- shell: "cargo test --test integration"
id: "integration-tests"
# Execute only if specific test suite failed
- claude: "/analyze-failures '${unit-tests.output}'"
when: "${unit-tests.exit_code != 0}"
- claude: "/analyze-failures '${integration-tests.output}'"
when: "${integration-tests.exit_code != 0}"
Source: Conditional evaluation from src/cook/workflow/conditional_tests.rs:95-97
2. Error Handling with Step-Specific Outputs
Use step IDs to pass the exact output from a failed step to error handlers:
- shell: "npm run build"
id: "build"
- shell: "npm run lint"
id: "lint"
- shell: "npm test"
id: "test"
# Pass step output to Claude for analysis
- claude: "/debug-build-failure '${build.output}'"
when: "${build.exit_code != 0}"
Source: Real pattern from src/cook/mod.rs:721 and src/cook/execution/mapreduce_integration_tests.rs:230
3. Multi-Step Conditional Logic
Combine multiple step results to control workflow execution:
- shell: "cargo clippy"
id: "clippy-check"
- shell: "cargo fmt --check"
id: "format-check"
# Only proceed if both checks pass
- shell: "cargo build --release"
when: "${clippy-check.exit_code == 0 && format-check.exit_code == 0}"
# Fix clippy warnings if present
- claude: "/fix-clippy-warnings '${clippy-check.output}'"
when: "${clippy-check.exit_code != 0}"
Source: Boolean logic support from src/cook/workflow/conditional_tests.rs:56
4. Passing Step Outputs to Subsequent Commands
Reference earlier step outputs in later commands, including in on_failure handlers:
- shell: "cargo test"
id: "test"
on_failure:
claude: "/fix-failing-tests '${test.output}'"
max_attempts: 3
# Use test results in summary
- shell: "generate-report.sh '${test.output}' ${test.exit_code}"
Source: Real on_failure pattern from src/cook/mod.rs:721-722
When NOT to Use Step IDs¶
Step IDs add complexity, so skip them when:
- Single command workflows: If you only have one or two steps,
${shell.output}is clear enough - No output references: If you never reference a step's output, exit code, or success status
- Simple sequential execution: Steps that always run in order without conditionals
Example of when step IDs are unnecessary:
None of these steps reference each other, so IDs would add no value.
Implementation Details¶
How It Works:
- When a step with
id: "my-step"executes, Prodigy automatically captures: ${my-step.output}- stdout from the command${my-step.exit_code}- process exit code (0 = success, non-zero = failure)-
${my-step.success}- boolean indicating success (computed asexit_code == 0) -
Custom outputs (via
outputs:field) are stored separately and accessed by their output name: -
${my-step.custom-output-name}- file path matching the pattern -
Variable resolution happens at runtime when constructing subsequent commands
Source: Implementation in src/cook/expression/mod.rs:187-200 and src/cook/orchestrator/execution_pipeline.rs:650-654
Troubleshooting¶
"Variable not found" errors:
- Ensure the step has completed before referencing its outputs
- Verify the step ID matches exactly (case-sensitive)
- Check that the step actually has an id field
Empty output values:
- Step output is only captured if the command writes to stdout
- Use outputs: for file-based artifacts instead of stdout
- Verify the command actually produces output
Conditional not working:
- The .success and .exit_code fields are only available for steps with id set
- Ensure your when: expression uses correct syntax: "${step-id.exit_code != 0}"