Feature: fallback engines for resilient agentic workflow execution
- Dominant language
- Go
- Stars
- 5.1k
- Forks
- 541
- Avg merge
- 5h 48m
- Merged PRs (30d)
- 773
Description
## Summary
Today each workflow is compiled against exactly one engine (`engine: claude`, `engine: copilot`, etc.). If that engine is unavailable — quota exhausted, service outage, auth failure — the entire job fails with no recovery path. A `fallback-engines` list would let users declare an ordered preference and have gh-aw automatically retry with the next engine when the primary one cannot run.
## Proposed syntax
```yaml
engine: claude
fallback-engines:
- copilot
- codex
```
Resolution order: `claude` → `copilot` → `codex`. The first engine that succeeds wins; failures are logged but do not surface as job failures until all options are exhausted.
## Behaviour spec
| Scenario | Behaviour |
|---|---|
| Primary engine succeeds | No fallback triggered |
| Primary fails with transient error (rate limit, 5xx) | Try next engine in list |
| Primary fails with config/auth error | Try next engine in list |
| All engines exhausted | Job fails with aggregated error messages |
| `fallback-engines` omitted | No change from today |
## Why this matters
- **Multi-tenant runners** commonly have uneven quota across providers; a fallback avoids hard stops.
- **Copilot BYOK** setups may have primary keys scoped to one provider; a cheaper fallback engine can handle overflow.
- **Scheduled / unattended workflows** (no human to re-trigger) benefit most — they need resilience baked in.
## Implementation notes
The `ResolvedEngineTarget` chain already lives in `pkg/workflow/engine_definition.go`. A `fallback-engines` field on the workflow spec could be parsed alongside `engine` and compiled into a retry loop at the runner level rather than re-generating the full workflow YAML per fallback. The log-parsing fallback path in `pkg/cli/logs_parsing_engines.go` and the existing engine resolution fallback (runtime-ID prefix match) show patterns that could be adapted.
## Alternatives considered
- **User-side retry workflow**: callers can wrap the workflow in a retry loop, but this duplicates boilerplate across every workflow and doesn't capture transient errors that surface inside the compiled YAML.
- **Single engine with model fallback**: each engine already supports env-var model fallback, but that doesn't help when the whole provider is down.
Contributor guide
Research direction
Start with pkg/workflow/engine_definition.go to trace ResolvedEngineTarget parsing and resolution, then inspect the runner path that executes the selected engine. Review pkg/cli/logs_parsing_engines.go and the runtime-ID prefix fallback for related patterns. Done means fallback-engines is parsed in order, transient and configuration failures advance through the list, omitted configuration preserves current behavior, and exhausted engines produce aggregated errors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- ci-cd, devops
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100