This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
The original design asks for deterministic workflows next to dynamic agent reasoning: "Agent = dynamic reasoning, Workflow = deterministic orchestration, both should coexist", with DAG execution, conditions, retries, compensation, timers, approvals, events and agent, tool and human steps. WorkflowEngineService is that engine. It validates and caches workflow definitions published as assets (BC-04), opens a projection for every accepted run, computes the steps that are ready, evaluates conditions on recorded outputs, fires durable timers, plans compensation and tells Run Control what to dispatch and when the run is complete.
The engine is deliberately not an authority. Run Control owns run, step and attempt state (ADR-0014); the engine emits StepReady and Run Control creates the step and the lease; the engine consumes AttemptOutcomeRecorded and advances. This split keeps one writer of truth and lets the engine be re-projected from Run Control's journal after a loss.
flowchart LR
S["WorkflowEngineService"]
RunControlService["RunControlService"] -->|grpc| S
StudioBff["StudioBff"] -->|sync-http| S
S -->|event| RunControlService["RunControlService"]
S -->|grpc| AgentRegistryService["AgentRegistryService"]
S -->|grpc| PolicyEngineService["PolicyEngineService"]
S -->|grpc| ArtifactService["ArtifactService"]
S -. "WorkflowDefinitionLoaded" .-> E_WorkflowDefinitionLoaded(("event"))
S -. "WorkflowRunStarted" .-> E_WorkflowRunStarted(("event"))
S -. "StepReady" .-> E_StepReady(("event"))
S -. "StepRunStateChanged" .-> E_StepRunStateChanged(("event"))
S -. "TimerFired" .-> E_TimerFired(("event"))
S -. "CompensationStarted" .-> E_CompensationStarted(("event"))
S -. "WorkflowRunCompleted" .-> E_WorkflowRunCompleted(("event"))
S -. "WorkflowRunFailed" .-> E_WorkflowRunFailed(("event"))
S -. "WorkflowRunCancelled" .-> E_WorkflowRunCancelled(("event"))
Hold "Alt" / "Option" to enable pan & zoom
Step kinds and what they become:
Kind
Becomes
Gate
Agent
an attempt of the named agent dispatched by Run Control
the agent's tool calls carry their own classes
Tool
an attempt that executes one tool call through the executor
the declared action class (D21)
Human
an approval request (exact version) or an input request
always a decision
Condition
evaluated by the engine on recorded outputs and variables
none; never a model call
Timer
a durable reminder
none
SubWorkflow
a child run of another Published workflow
inherits scope and budget
Fanout / Join
parallel branches with quorum
none
Compensation
the compensation step of a succeeded step, run in reverse order on failure
WorkflowDefinitionVersion — Immutable, validated graph of a Published workflow asset — steps, edges, conditions, timers, compensation map, input and output schemas — cached in the runtime for execution. (catalog entry)
Field
Type
Required
Description
definitionId
string
yes
version
string
yes
releaseId
string
yes
Asset release of the workflow (BC-04).
tenantId
string
yes
graphHash
hash
yes
stepCount
int
yes
inputSchemaRef
string
yes
outputSchemaRef
string
yes
maxLoopIterations
int
yes
loadedAt
datetime
yes
Invariants:
The graph is acyclic except for explicitly declared loops with a bounded iteration count.
Every Agent, Tool and Human step declares its action class (D21) and its failure policy; publication is refused otherwise (validated by the engine at validate time and at load).
A Condition step reads only recorded step outputs and run variables; it never calls a model.
A definition version is immutable once loaded; a changed graph has a new release id.
WorkflowRun — The engine's state of one run — cursor over the graph, step runs, variables, timers and compensation plan — projected from Run Control's accepted run and attempt outcomes. (catalog entry)
Field
Type
Required
Description
runId
guid
yes
Same id as the Run in Run Control.
tenantId
string
yes
projectId
string
yes
definitionReleaseId
string
yes
graphHash
hash
yes
state
enum:WorkflowRunState
yes
variablesRef
string
yes
Artifact reference of the run variables (JSON).
activeStepRuns
int
yes
lastOutcomeSequence
long
yes
Last Run Control attempt outcome applied; makes Advance idempotent.
version
long
yes
Invariants:
The engine never changes a run's authoritative state; it emits StepReady for Run Control to dispatch and WorkflowRunCompleted, WorkflowRunFailed or WorkflowRunCancelled for Run Control to record.
Advance is idempotent on the outcome sequence; an outcome applied twice changes nothing.
One StepRun per step is active unless the step is inside a Fanout; a Join waits for every branch or the declared quorum.
Timers are durable reminders; a fired timer that finds its step already advanced is a no-op.
Compensation runs the declared compensation steps of succeeded steps in reverse completion order; a failed compensation ends the run Failed with an operator follow-up, never silently.
Validate a workflow DSL document: acyclicity, declared action classes and failure policies, schema references, bounded loops; used by authoring and by publication (BC-04) as a gate.
GET
/runtime/workflow-runs/{runId}
GetWorkflowRunGraph
factory.runs.read
read
natural
GW-03
The graph of a run with the state of every step run, timers and compensation entries, for the Studio run view.
Loaded versions of a definition with graph hashes.
gRPC service
Method
Streaming
Visibility
Side effects
Summary
WorkflowEngine
PlanNextSteps
none
internal
read
Given the run and the last applied outcome sequence return the steps that are ready to dispatch with their input mappings and action classes; idempotent.
WorkflowEngine
GetRunGraph
none
internal
read
Current engine projection of a run for Run Control and the BFF.
Example of the workflow DSL the engine validates (the schema is registered as a descriptor; see shared contracts):
Registers an Orleans reminder for every timer entry and applies the fired timer to the run.
StuckRunReconciler
schedule */5 * * * *
StepReady, StepRunStateChanged
fixed
stepRunId + lastOutcomeSequence
Finds workflow runs whose active step runs have no corresponding open attempt or approval in Run Control and re-emits StepReady or fails the step per policy.
DefinitionCacheWarmer
event
WorkflowDefinitionLoaded
exponential
releaseId
Validates and caches newly published workflow definitions.
Serialises Advance for one run, holds the cursor and active step runs, registers timer reminders and commits step-run rows with the outbox in one transaction.
The engine runs inside AgentRuntimeWorker; it is a module of the worker rather than of the Control plane host because its state is runtime state (projection, timers, adapter workflow graphs), not authority, and because the Microsoft Agent Framework workflow graph executes in the same process as the attempts (durability spike).
Nothing executes workflows. ConnectSoft.AI.SoftwareFactory.Platform holds six placeholder workflow definitions and schemas; the coordinators (bootstrap, sprint, milestone, assembly, release) are documents. Those documents are the seed for the first workflow definitions (B1, coordinators).
Workflow simulation (dry-run cost and duration against synthetic inputs, with Usage Accounting); versioned migration of in-flight runs to a newer definition on explicit operator decision; visual authoring in Workflow Studio producing the same DSL; cross-run event triggers (a workflow started by a product telemetry event, Fleet Operations).