Skip to content

Core Philosophy ​

Vyuh Workflows separates orchestration, side effects, history, and storage. The executable source is a Dart function or a constrained JSON document. The runtime never stores a Dart stack frame.

Definition Before Implementation ​

The public boundary and the executable body are different concepts:

NounResponsibility
Schema<T>Describes a reusable data contract. It can be shared by entities, events, configurations, stored records, workflows, and operations.
Workflow<I, O, E>Assigns input, output, and expected-failure schemas to an immutable workflow identity.
WorkflowHandler<I, O, E>Implements the definition with deterministic orchestration.
Operation<I, O, E>Assigns schemas to one versioned automated side-effect boundary.
OperationHandler<I, O, E>Performs the real external effect.
Work<I, R>Declares assigned work with a typed request and response.
Event<P>Declares a typed fact sent into a workflow run.

A definition says what may execute. A handler says how it executes. A payload schema belongs to the payload, not to a workflow.

Replay, Not Tokens ​

A run is history plus the current command projection. After every durable fact the runtime invokes the same versioned workflow from its entry point:

Completed awaits return recorded results. Unresolved awaits emit a command and mark the run blocked. running means a new fact is ready to reduce, not that a Dart isolate is parked.

Side Effects Belong in Operations ​

Workflow code may use if, switch, and loops over recorded values. It must not:

  • call a network or database;
  • read the wall clock or generate randomness;
  • mutate globals;
  • use Future.wait or unregistered futures.

Those belong in versioned OperationHandlers that receive a stable idempotencyKey. Assigned work uses request and respond, regardless of whether the actor is a person, group, role, agent, bot, or service. External communication uses waitForEvent and sendEvent. Time uses sleep.

One Vocabulary, Two Authoring Surfaces ​

ConceptDartJSONRuntime record
IdentityWorkflow(code, version, ...)code + versionversion plus run
Automated workflow.performoperationoperation command
Assigned workflow.requestworkwork command and WorkItem
External eventflow.waitForEventeventevent history
Timeflow.sleeptimertimer command
Branch / loopDart control flowswitch, joinsreplay decisions

JSON compiles to an executable handler. Arbitrary Dart cannot be converted losslessly back into a graph.

Identity Is Immutable ​

code + version is the public identity. The fingerprint/digest is an integrity check. A run stores all three. Changing behavior requires a new version. Workers refuse to replay history against a different digest.

Storage Is the Coordinator ​

Correctness comes from:

  • append-only history;
  • unique (run, operationKey, attempt) commands;
  • optimistic run revisions;
  • leases and claim-generation fencing;
  • atomic join and continue-as-new transactions.

Process affinity is not a correctness mechanism. API, decider, operation, and recovery roles can share a process or run separately.

Products Talk to the Service ​

Product Flutter apps and product APIs do not embed deciders or hold a service-role key. They call vyuh_workflow_service. cdx_feature_workflows renders inbox state. cdx_workflow_templates supplies the canonical approval definition.

The graph subsystem is named explicitly through LegacyWorkflowEngine and other Legacy* types. It is a separate surface, not a compatibility alias in the durable API.

See Also ​