Action Stages¶
Action stages allow workflows to execute actions in distinct phases, enabling powerful patterns like CI monitoring, automated feedback response, and iterative fixes.
Overview¶
Actions support a stage field with two values:
| Stage | Execution Time | Use Case |
|---|---|---|
primary (default) |
Before PR creation | Standard workflow actions - code changes, file updates |
followup |
After PR creation | CI monitoring, reviewer feedback, automated fixes |
Execution Flow¶
1. Setup working directory
2. Check conditions, clone repository
3. Execute PRIMARY stage actions (with commits)
4. Create PR or push changes
5. Execute FOLLOWUP stage actions (with cycling)
6. Cleanup
Primary Stage¶
Primary actions execute sequentially before any PR is created:
```toml [[actions]] name = "update-dependencies" type = "claude"
stage = "primary" # Default, can be omitted¶
task_prompt = "prompts/update-deps.md.j2"
[[actions]] name = "run-tests" type = "shell" command = "pytest tests/" ```
- Execute in order defined in workflow
- Each action can commit changes
- PR created after all primary actions complete
Followup Stage¶
Followup actions execute after the PR is created:
toml
[[actions]]
name = "monitor-ci"
type = "claude"
stage = "followup"
task_prompt = "prompts/monitor-ci.md.j2"
committable = true # Can commit fixes
Followup Behavior:
- All followup actions execute in sequence
- If any action commits, changes push to PR branch
- If commits were made, followup stage cycles again
- Cycles continue until no commits or max cycles reached
- If max cycles reached, workflow fails
Configuration¶
Workflow-Level Settings¶
```toml name = "update-and-monitor"
Maximum followup cycles (default: 5)¶
max_followup_cycles = 3
[github] create_pull_request = true ```
Action-Level Settings¶
toml
[[actions]]
name = "monitor-ci"
type = "claude"
stage = "followup" # Execute after PR creation
task_prompt = "prompts/monitor.md.j2"
committable = true # Allow commits (enables cycling)
ai_commit = true # AI-generated commit messages
Template Context¶
Followup actions receive additional context variables:
pull_request (GitHubPullRequest)¶
Full PR model with fields:
jinja2
PR Number: {{ pull_request.number }}
PR URL: {{ pull_request.html_url }}
PR State: {{ pull_request.state }}
Head SHA: {{ pull_request.head.sha }}
Head Ref: {{ pull_request.head.ref }}
Base Ref: {{ pull_request.base.ref }}
Mergeable: {{ pull_request.mergeable }}
Mergeable State: {{ pull_request.mergeable_state }}
pr_branch (str)¶
Branch name for the PR:
jinja2
Branch: {{ pr_branch }}
Example Followup Prompt¶
```markdown
Monitor CI and Fix Issues¶
You are monitoring PR #{{ pull_request.number }} in {{ github_repository.full_name }}.
PR URL: {{ pull_request.html_url }} Branch: {{ pr_branch }} Head SHA: {{ pull_request.head.sha }}
Your Task¶
- Check GitHub Actions workflow status for this PR
- If CI is still running, report status and wait
- If CI passed, report success (no changes needed)
- If CI failed:
- Analyze failure logs
- Identify root cause
- Make targeted fixes
- Commit changes
Use gh CLI to check workflow status:
bash
gh run list --branch {{ pr_branch }} --limit 1
gh run view <run-id> --log-failed
If you make fixes, ensure they are minimal and targeted. ```
Use Cases¶
1. CI Monitoring¶
Monitor GitHub Actions and fix failures:
```toml [[actions]] name = "update-code" type = "claude" task_prompt = "prompts/update.md.j2"
[[actions]] name = "monitor-ci" type = "claude" stage = "followup" task_prompt = "prompts/monitor-ci.md.j2" committable = true max_cycles = 5 ```
2. Reviewer Feedback Response¶
Respond to automated code review comments:
```toml [[actions]] name = "refactor-code" type = "claude" task_prompt = "prompts/refactor.md.j2"
[[actions]] name = "respond-to-feedback" type = "claude" stage = "followup" task_prompt = "prompts/respond-feedback.md.j2" committable = true ```
3. Test Verification¶
Wait for tests and fix any failures:
```toml [[actions]] name = "migrate-dependencies" type = "claude" task_prompt = "prompts/migrate.md.j2"
[[actions]] name = "verify-tests" type = "claude" stage = "followup" task_prompt = "prompts/verify-tests.md.j2" committable = true max_cycles = 3 ```
Cycling Behavior¶
When Cycling Occurs¶
Followup stage cycles when:
- A followup action with
committable = truecreates a commit - The commit is pushed to the PR branch
- The stage restarts from the first followup action
Cycle Completion¶
A cycle completes successfully when:
- All followup actions execute without error
- No commits are made during the cycle
Max Cycles¶
If max_followup_cycles is reached:
- Workflow fails with RuntimeError
- Error message indicates max cycles exceeded
preserve_on_errorcan save state for debugging
toml
max_followup_cycles = 3 # Fail after 3 cycles with commits
Error Handling¶
Primary Stage Failure¶
If a primary action fails:
- Followup stage is skipped entirely
- Normal error handling applies
preserve_on_errorsaves state
Followup Stage Failure¶
If a followup action fails:
- Workflow fails immediately
preserve_on_errorsaves state- PR remains open for manual intervention
Dry-Run Mode¶
In --dry-run mode:
- Primary actions execute normally
- Followup actions are skipped (no PR exists)
- Warning logged about skipped followup actions
Best Practices¶
1. Keep Followup Actions Focused¶
Each followup action should have a single responsibility:
```toml
Good: Focused actions¶
[[actions]] name = "check-ci-status" stage = "followup"
[[actions]] name = "fix-lint-errors" stage = "followup"
Avoid: Monolithic actions¶
[[actions]] name = "monitor-everything" # Too broad stage = "followup" ```
2. Set Reasonable Max Cycles¶
Balance automation with safety:
```toml
Too low: May not complete complex fixes¶
max_followup_cycles = 1
Too high: May loop indefinitely on unfixable issues¶
max_followup_cycles = 20
Good: Reasonable limit with room for iteration¶
max_followup_cycles = 5 ```
3. Use Conditional Commits¶
Only commit when changes are actually needed:
```markdown
Instructions¶
- Check CI status
- If all checks pass, report success (no commit needed)
- Only commit if you made actual fixes ```
4. Provide Clear Exit Conditions¶
Define when followup should stop:
```markdown
Success Criteria¶
- All CI checks pass
- No open review comments
- Tests pass
When to Stop¶
Return without committing if: - CI is passing - No actionable feedback exists ```
Complete Example¶
```toml name = "Update Python Version with CI Monitoring" description = "Update Python version and monitor CI for failures" max_followup_cycles = 5
[filter] project_types = ["api"] project_facts = {"Programming Language" = "Python 3.11"}
[github] create_pull_request = true
Primary stage: Make changes¶
[[actions]] name = "update-python-version" type = "claude" task_prompt = "prompts/update-python.md.j2" validation_prompt = "prompts/validate-update.md.j2"
Followup stage: Monitor and fix¶
[[actions]] name = "monitor-ci" type = "claude" stage = "followup" task_prompt = "prompts/monitor-ci.md.j2" committable = true ai_commit = true
[[actions]] name = "respond-to-reviews" type = "claude" stage = "followup" task_prompt = "prompts/respond-reviews.md.j2" committable = true ai_commit = true ```
See Also¶
- Workflow Configuration -
max_followup_cyclessetting - Claude Actions - AI-powered transformations
- Templating - PR context variables
- Workflows - Workflow overview