Data model
Each run is a row inworkflow_runs. Each step within that run is a row in workflow_steps. Steps are ordered by their position in the DAG and execute sequentially once their upstream dependencies resolve.
Step lifecycle
pending to running when it starts, then to completed or failed when the agent finishes. A failed step stops the run.
Orchestration
Runs are dispatched to a Trigger.dev task namedcelerflow-workflow-run. Trigger.dev only orchestrates — it walks the node list, handles retries, and calls back a webhook that updates the workflow_steps and workflow_runs rows. The actual agent work always runs on Railway, never inside Trigger.dev. That callback is what drives the status transitions you see in the UI.
A step can also fan out over an array, running its agent on each element with bounded concurrency and aggregating the results into one output.
Real-time updates
The UI subscribes to run progress via Supabase Realtime. Each open browser tab gets a channel with a unique subscriber suffix — so if you have the same workflow open in two tabs, they don’t overwrite each other’s state.Run result
When a run completes, aresult_markdown field is written to the run record. This is rendered on the run detail page. See Executions for the UI surface.
Rerun and dispatch failures
Rerun — triggering a rerun queues a new deploy command and starts a fresh run record. Previous run history is preserved. Dispatch failure — if Trigger.dev can’t accept the dispatch (capacity, network, or config issue), the UI shows adispatch_failed banner on the run detail page. This is a named error state, not a generic 500.
The
dispatch_failed state means CelerFlow could not hand the run off to Trigger.dev. It does not mean the workflow itself has a bug. Retrying the run is safe.