Workflows
The workflow engine is the agent’s durable loop. An operator does not script tasks; the coordinator starts workflow runs, and each run advances one step at a time. A task is a unit of work the agent drives exclusively through the current step of its run.
Runs, steps, and mutexes
Section titled “Runs, steps, and mutexes”- A run is stored durably with its current step, status, retry count, and
step_state. - Each step has a retry policy, a timeout, a poll interval, and optional mutexes.
- Step timeout is the total wall-clock budget for one step across all attempts, including retry backoff. Schedule delay (waiting for the workflow’s parallelism limit) and worker-slot waits do not count against it.
- Retry backoff is the wait between a failed attempt and the next; the first retry waits exactly the strategy’s base.
- Mutexes such as
deploy:staginganddeploy:productionserialize deploys. A stale mutex — one held by a run that is no longer running — is reconciled at startup and on the watchdog cadence, so it stops blocking within one watchdog interval instead of at the next restart. - A fail-fast step has a zero timeout: it times out on its first observed tick before its action runs, so an unstarted fail-fast step fails at queue time.
Retries are recorded as step transitions. A run that exhausts its retry budget produces one retry row per errored attempt, then a failed row.
Workflow kinds
Section titled “Workflow kinds”| Kind | Role |
|---|---|
task_lifecycle | Issue delivery: implement, CI, staging, merge, production |
github_sync | Issue pickup and external PR review |
harness_converge | Diff the repo against the merged harness pack, open one sf/harness PR |
production_monitor | Poll environment health; escalate to investigation on threshold |
investigate_incidents | Spawn an investigator and file issues for findings |
optimize_performance | Observe → hypothesize → open PR-gated performance issues |
pentest | Periodic security audit (Cloudflare security-audit skill) of the repo source; files confirmed and needs-validation security issues |
self_heal | Turn agent failures, red default-branch CI, and code-health findings into pickup issues (source profile) |
task_lifecycle steps
Section titled “task_lifecycle steps”backlog → waiting_for_info → waiting_for_worker → implementing → waiting_for_ci_checks → deploying_to_staging → staging_healthchecks → merging_pr → [waiting_for_rebase_worker / rebasing_from_main] [waiting_for_ci_fix_worker / fixing_ci] → deploying_to_prod → prod_healthchecks → [reverting_pr] → donedelivery_profile=source short-circuits staging and production: once CI is green the run merges to main using pr_merge_method and is done. delivery_profile=live runs the full staging → production path. pr_merge_method (squash default, rebase/merge allowed) picks the merge method.
The workflow runs at most 3 in parallel and tolerates 5 failure recoveries.
Failure recovery
Section titled “Failure recovery”- A worker death with no observed result is a transient failure: the run probes the PR first. If the PR still needs that worker (CI failed, or the branch still needs a rebase) it returns to the matching
waiting_for_*step and respawns a fresh sandbox; if the worker’s goal was already achieved (its push turned CI green) it continues atwaiting_for_ci_checkswithout spending a failure recovery. - A completed coding-runtime session that opened no PR also respawns rather than escalating on the first occurrence.
- Transient GitHub API failures (
error connecting to api.github.com, HTTP 5xx, rate limits) keep the CI steps pending and retry on the next poll instead of permanently failing the run. Auth, permission, and validation errors still fail. - A recorded non-transient error (for example, an API error) fails the run.
- Triage can park a task: an epic or a request for clarification labels the issue
steelframe:needs_humanand stops the run. Parking is the intended outcome, not a defect, and the label holds pickup until a human responds. The park is durable: if the comment or label write fails,github_syncretries it and holds the issue out of pickup until the label lands. - If a run still fails, the issue may be labeled
steelframe:needs_human; failure is terminal by design. Start again from a new issue or run.
Step errors and failure recoveries are appended to the run’s step log, viewable in the run detail.
Operating runs
Section titled “Operating runs”| Method | Path | Purpose |
|---|---|---|
GET | /api/workflows | Summary counts by kind and status |
GET | /api/workflows/{kind} | Runs of one kind (?limit= &offset=) |
GET | /api/workflows/{kind}/runs/{id} | Run plus step log |
POST | /api/workflows/{kind}/runs/{id}/terminate | Terminate a running run |
POST | /api/workflows/optimize/trigger | Start or report an optimize_performance run |
POST | /api/tasks/sync | Force a github_sync run |
Termination sets the run’s error to terminated by @<user> via API/TUI, records workflow.terminate, and returns { "terminated": true }. Terminating a run that is not running returns terminated: false with a reason.
Gotchas
Section titled “Gotchas”- Singleton workflows (
github_sync,harness_converge,self_heal,optimize_performance,pentest,production_monitor) have max parallelism 1; their cadence keys are minutes or hours, and0disables them. delivery_profile=sourcenever startsproduction_monitorand never startsself_healwhen the profile islive.- A run terminated or failed after partial work leaves its sandbox cleaned up, not resumable.