Skip to content

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.

  • 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:staging and deploy:production serialize 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.

KindRole
task_lifecycleIssue delivery: implement, CI, staging, merge, production
github_syncIssue pickup and external PR review
harness_convergeDiff the repo against the merged harness pack, open one sf/harness PR
production_monitorPoll environment health; escalate to investigation on threshold
investigate_incidentsSpawn an investigator and file issues for findings
optimize_performanceObserve → hypothesize → open PR-gated performance issues
pentestPeriodic security audit (Cloudflare security-audit skill) of the repo source; files confirmed and needs-validation security issues
self_healTurn agent failures, red default-branch CI, and code-health findings into pickup issues (source profile)
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] → done

delivery_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.

  • 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 at waiting_for_ci_checks without 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_human and 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_sync retries 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.

MethodPathPurpose
GET/api/workflowsSummary 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}/terminateTerminate a running run
POST/api/workflows/optimize/triggerStart or report an optimize_performance run
POST/api/tasks/syncForce 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.

  • Singleton workflows (github_sync, harness_converge, self_heal, optimize_performance, pentest, production_monitor) have max parallelism 1; their cadence keys are minutes or hours, and 0 disables them.
  • delivery_profile=source never starts production_monitor and never starts self_heal when the profile is live.
  • A run terminated or failed after partial work leaves its sandbox cleaned up, not resumable.