Foundation for modern workflow apps

Build, run, and operate durable workflows on a composable foundation.

Elsa Foundation decomposes the workflow engine into explicit domains, stable contracts, replaceable implementations, and sanctioned extension patterns — so your platform evolves without turning every package into a dependency magnet.

MIT licensed.NET Foundation projectProvisional · REV 0.3
Elsa Studio workflow designer showing an HTTP Hello World workflow with the designer canvas, activities, and inspector panels
Elsa Studio · Workflow designer
II. The problem

What the refactor prevents

Seven shapes of accidental complexity that the Foundation refuses to allow.

God packages

One assembly knows everything.

Framework leakage

ASP.NET types in domain code.

Forced heavy dependencies

Pull EF Core to read a contract.

Infrastructure in contracts

.Core depends on a provider.

Inverted dependency direction

.Core references implementations.

Silent DI conflicts

Last-registered-wins surprises.

Names that hide meaning

Generic 'Service' / 'Manager' soup.

The Foundation does not eliminate complexity — it forces it into named, bounded places.

Before

Tangled package graph

After

Domains bounded by .Core
Design.CoreRuntime.CorePersistence.CoreSerialization.Core
III. The core idea

Every domain owns its contract

The same three-layer shape repeats for every feature in Elsa.

Layer 01
01

Domain / Feature Core

Contracts, models, value objects, events, exceptions, thin utilities.

e.g. Elsa.Workflows.Design.Core

Rule

No heavy dependencies.

Layer 02
02

Helper Libraries

Optional reusable implementations with focused dependencies.

e.g. Elsa.Tasks.Schedules

Rule

Never referenced by .Core.

Layer 03
03

Feature Implementation

DI registration and concrete services for a chosen technology.

e.g. Elsa.Serialization.Newtonsoft · Elsa.Locking.FileSystem

Rule

Implementations do not casually reference each other.

IV. Domain map

The Elsa domain tree

Domains grouped by role. Hover a card to see its boundary.

Workflow Core

Elsa.Workflows.Design

Contract

Authored workflow definitions: drafts, versions, validation, design-time persistence.

Design.Core · Design.Validation · Design.Persistence

Elsa.Workflows.Runtime

Contract

Executes workflow artifacts, instances, bookmarks, logs, runtime state.

Runtime.Core · Runtime.Bookmarks · Runtime.Logs

Platform Services

Elsa.Persistence

Contract

Storage commands and read-side abstractions.

Persistence.Core · Persistence.EFCore

Elsa.Locking

Provider

Distributed locks behind a single contract.

Locking.Core · Locking.FileSystem · Locking.Redis

Elsa.Serialization

Provider

Pluggable serialization surface.

Serialization.Core · Serialization.Newtonsoft · Serialization.SystemText

Elsa.Expressions

Contract

Expression languages and evaluation contracts.

Expressions.Core · Expressions.Liquid · Expressions.JavaScript

Elsa.Messaging

Provider

Outbound and inbound message integrations.

Messaging.Core · Messaging.MassTransit

Elsa.Scheduling

Provider

Time-based triggers and scheduled work.

Scheduling.Core · Scheduling.Quartz

Elsa.Tasks

Helper

Background tasks and schedule helpers.

Tasks.Core · Tasks.Schedules

Composition & Surface

Elsa.Modularity

Host-facing

Feature composition: registration, options, ordering.

Modularity.Core · Modularity.Features

Elsa.Api

Host-facing

HTTP-shaped surface for design and runtime endpoints.

Api.Core · Api.Endpoints

Elsa.Http

Helper

HTTP-related activities and runtime integrations.

Http.Core · Http.Activities

Elsa.Notifications

Contract

In-process pub/sub plus delivery strategies.

Notifications.Core

V. The load-bearing split

Design and Runtime are separate bounded contexts

Design owns authoring. Runtime owns execution. Runtime must not depend directly on Design.

DESIGNRUNTIMEWorkflowDefinitionStateauthored sourceRead Models / Projectionsderived viewsWorkflowExecutablethe artifact (seam)Runtime Executioninstances · bookmarks · logs

Elsa.Workflows.Design

Drafts, versions, input/output definitions, activity trees, expression bindings, validation, layouts, design-time persistence.

Elsa.Workflows.Runtime

Executable artifacts, workflow instances, runtime state, bookmarks, logs, runtime integrations.

Design produces. Runtime executes. The artifact is the seam.
VI. Runtime contract

Runtime contract first

Two invariants describe everything the runtime is allowed to know about.

Invariant 01

Executable-always-runs

If an artifact is published as runnable, the runtime must be able to load and execute it. Missing runtime types, registry drift, or module misconfiguration are bugs — not business gates.

Invariant 02

Artifact-only runtime

Runtime depends on the runnable artifact and configured runtime features. Never on drafts, designer metadata, authoring history, or design persistence.

DESIGNRUNTIMEREF: ART-01 · the artifact is the seamdraftsdesigner metahistoryWorkflowExecutable· sealed artifact ·execute
§ Runtime execution model · emerging

Runtime as an actor system

Elsa's runtime is moving from a broad in-memory execution object model toward isolated, addressable execution actors — each with its own identity, mailbox, state boundary, and checkpoint behavior. This is the emerging Foundation execution model, not a ratified constitution rule.

Provisional · conceptual actors, not concrete class names
Elsa runtime actor systemREF: ACT-01 · WORKFLOWEXECUTION · MAILBOX · CHECKPOINTWorkflowExecutableartifact(pinned snapshot)Persistedruntime statecheckpointsdurable valuesbookmarksincidentsStartWorkflowPost-commit outboxActivityExecutionScheduleActivitySchedulerActivityCompletedBookmarkResumeBookmarkDurableValueCaptureDurableValueIncidentRecordIncidentCheckpointCommitCheckpointWorkflowExecutionactor · mailboxCommitCheckpointCreateBookmark

One execution, one durable identity.

Messages cross boundaries; state does not leak.

Runtime resumes from checkpoints, not from design documents.

Concurrency is explicit instead of accidental.

Conceptual actors

lifecycle owner

Workflow execution actor

Owns one workflow execution: start, run, suspend, resume, complete, fault, cancel. Pinned to one executable artifact snapshot for its entire lifetime.

per-node execution

Activity execution actor

One concrete execution of one executable node, with a durable identity distinct from the authored activity id. Survives loops, parallel branches, retries, and nested workflows.

pending & delayed work

Scheduler actor

Owns pending work, delayed work, branch and iteration scheduling, and resumable continuations.

external resume targets

Bookmark / stimulus actor

Resolves external stimuli into durable resume targets. Bookmarks point to stable resume target ids inside the pinned artifact — never to C# callback method names.

intentional state

Durable value boundary

Variables, workflow inputs and outputs, captured activity outputs, and external references are persisted on purpose. History is not runtime continuation state.

operational concerns

Incident & recovery actors

Faults, retries, leases, heartbeats, drain markers, and interrupted executions become explicit operational concepts rather than hidden side effects.

What it unlocks

Safer parallel execution

Cleaner suspension & resume

Better horizontal scaling

Inspectable runtime state

Deterministic snapshot pinning

Recovery without replaying authoring models

VIII. Extension model

Extend without coupling

PROPOSED· REF: EXT-04

Two axes describe every legitimate extension in Elsa.

Override

One implementation wins.

Replace a default implementation of a .Core contract — bring your own distributed lock provider or persistence commands.

.Coreimpl 1impl 2impl 3only one is registered
Extend

Many contributions, one aggregator.

Add implementations alongside built-ins. A single owner-owned aggregator runs all contributions — validators, sources, contributors, processors, handlers.

aggregatorall contributions run
Sanctioned patterns
Feature inheritanceEventsContribution interfacesReplacement contractsStartup tasksAdapter / BridgeProvider module decompositionCore-to-Core contractsApplication-level composition
§ Shell composition

Composable by shell

Composition is treated as an explicit architecture surface. Features have stable identities, activation boundaries, configuration surfaces, and dependency evidence that tools can reason about — not just bag-of-services registrations buried in code.

CShells provides the shell model that lets an Elsa host compose selected features into a running application: design-time features, runtime features, provider implementations, API surfaces, reconciliation sources, persistence providers, and bridges — each opted in independently. The capability is not new; the Foundation makes it explicit, inspectable, and toolable.

CShells compositionAVAILABLE FEATURE MODULESCSHELLS · SHELL CONFIGCOMPOSED Elsa.Server HOSTshell.config7/9 activehost.runtimeloadedDesign APIapidesign.apiDesign APIRuntimeruntimeruntimeRuntimeActivitiesruntimeactivitiesActivitiesExpressionsplatformexpressionsExpressionsSerializationproviderserializationSerializationLockingproviderlockingPersistenceproviderpersistencePersistenceReconciliationplatformreconciliationPublishing APIapipublishing.apiPublishing APIloading ≠ activation · host-pinned .Core may require restart · implementations are the hot-load boundary

What the shell model gives you

  • Features have stable IDs. Identity is the contract for tooling and diff.
  • Shell configuration selects which features are active. Activation lives in the shell, not in the feature.
  • Host-loading settings are separate from feature activation. A loaded module isn't necessarily an active one.
  • Provider implementations swap freely. Domain contracts don't move when implementations change.
  • Contributor features extend without coupling. Source/contribution patterns layer on without direct refs.
  • Nuplane loads, activates, and replaces modules at runtime. Inside the runtime + contract boundary.
  • Host-pinned .Core may need restart. Implementations are the natural hot-load boundary.

Feature selection is explicit.

Loading is separate from activation.

Contracts stay stable; implementations can vary.

Composition becomes inspectable.

Example shell configuration

A composed Elsa host emits a resolved shell document. It separates host.loading — which modules are present in the process — from shell.features — which feature IDs are actually activated, with their bound contracts and providers. Illustrative shape; not a final schema.

cshells · shell.resolved.jsongenerated · read-only
1{
2 "shell": {
3 "id": "elsa.server.default",
4 "version": "0.4.0-draft",
5 "features": [ // activation, not loading
6 { "id": "elsa.workflows.design.api", "active": true, "binds": ["Elsa.Workflows.Design.Core"] },
7 { "id": "elsa.workflows.runtime", "active": true, "binds": ["Elsa.Workflows.Runtime.Core"] },
8 { "id": "elsa.activities", "active": true },
9 { "id": "elsa.serialization", "active": true, "provider": "newtonsoft" },
10 { "id": "elsa.persistence", "active": true, "provider": "efcore.sqlite" },
11 { "id": "elsa.expressions", "active": true, "languages": ["liquid", "js"] },
12 { "id": "elsa.locking", "active": false, // loaded but not activated
13 "availableProviders": ["filesystem", "redis"] },
14 { "id": "elsa.reconciliation", "active": false },
15 { "id": "elsa.publishing.api", "active": true, "surface": "http" }
16 ],
17 "hostPinned": ["Elsa.Modularity.Core", "Elsa.Workflows.Runtime.Core"], // changing these requires restart
18 },
19 "host": {
20 "loading": { // assemblies present in the process
21 "strategy": "explicit",
22 "modules": [
23 "Elsa.Workflows.Design.Api",
24 "Elsa.Workflows.Runtime",
25 "Elsa.Persistence.EFCore.Sqlite",
26 "Elsa.Serialization.Newtonsoft",
27 "Elsa.Locking.FileSystem" // loaded, awaiting activation
28 ],
29 "hotLoadBoundary": "implementations",
30 "loader": "nuplane"
31 },
32 "restartRequiredFor": ["hostPinned"]
33 }
34}
feature id · bindingactivation statehost loading · modulesactivation ≠ loading

What it unlocks

Build design-only, runtime-only, or combined hosts.

Swap providers cleanly without touching domain contracts.

Keep optional integrations out of the core dependency path.

Prepare for generated shell configuration and composition tooling.

X. Events & contributions

One event concept, explicit delivery strategy

DRAFT· REF: EVT-02

Contribution flows use a single aggregating handler — not scattered anonymous dispatch.

Publisher
raises
IEvent
one concept
Strategy
sequential · parallel · background
Handlers / Contributors
aggregated
Result
single response
XI. Catalogs

Catalogs replace live guessing

PROVISIONAL· REF: CAT-01

If an activity appears in the picker, it has a persisted catalog entry.

CLR modulesJSON definitionsWorkflow definitionsReconciliationtrusted sources → catalogActivity Catalogpersisted source of truthPicker/ API

Visibility is structural: catalog presence first, context filtering later.

XII. Provider modules

Providers are siblings, not leaks

IN REVISION· REF: PRV-03

The .Core package exposes the contract. Provider packages opt into concrete technology.

Elsa.*.CorecontractElsa.Serialization.NewtonsoftproviderElsa.Serialization.SystemTextproviderElsa.Locking.FileSystemproviderElsa.Scheduling.QuartzproviderElsa.Messaging.MassTransitprovider
XIII. Elsa 3 compatibility

Compatibility through import

PROVISIONAL· REF: CMP-01

Import-only. No dual-run, no round-tripping, no Elsa-3-shaped runtime surface.

Elsa 3 definition
legacy asset
Import Adapter
one-shot map
Foundation entities
native models
Foundation runtime
executes natively
XIV. Foundation

Elsa Foundation

The architecture foundation for modern workflow applications.

Elsa Foundation establishes redesigned runtime contracts, cleaner persistence boundaries, better import and export, and a more predictable execution model — the substrate for production-grade workflow platforms.

01

Unified workflow JSON

A canonical authored workflow document for Studio, REST APIs, import, and export — storable and importable without constructing runtime activities.

02

Better serialization & value persistence

Runtime values are explicit and durable only when declared. JSON-first logical types, aliases, references, and storage policies replace silent CLR persistence.

03

Workflow values

Inputs, outputs, and variables become roles of declared workflow values — less duplication, clearer semantics.

04

Actor-style workflow runtime

Provider-neutral execution agents coordinate one active mailbox per workflow execution ID — no lock-in to Orleans, Dapr, or any specific framework.

05

Generator activities

Long-lived in-workflow generators emit execution events over time and schedule downstream work, distinct from external triggers.

06

Volatile waits & durable suspension

Short-lived in-memory waits are separated from durable suspension, supporting both request-affine and long-running workflows.

07

Runtime artifact boundary

Runtime executes a pinned workflow executable artifact rather than the design-time document, making resume behavior more deterministic.

08

Checkpoints, recovery & diagnostics

Checkpoints, incidents, history, post-commit work, and recovery are modeled as separate runtime concerns — not one monolithic workflow state.

The result is a workflow foundation that is easier to reason about, safer to extend, and better suited for production-grade platforms.

XV. Impact

Why this matters

The Foundation is judged by what it makes possible for three audiences.

For users

  • Smaller dependency surfaces
  • Clearer deployment shapes
  • Design-only, runtime-only, and combined hosts
  • Replaceable infrastructure
  • More predictable upgrades

For contributors

  • Obvious ownership boundaries
  • Cataloged extension points
  • Less accidental coupling
  • Safer refactoring

For Elsa itself

  • Modular evolution
  • Provider ecosystem growth
  • Runtime hot-loading via Nuplane where appropriate
  • Architecture verifiable with maps and tests
§ Coda

A workflow engine made of explicit parts.

Elsa Foundation turns the workflow engine from a single gravitational center into a composed system of domains, contracts, providers, catalogs, and bridges. The result is an architecture that can grow without hiding its dependencies.

Elsa.ServerhostModularity · Nuplane composition.Workflows.Design.Coreimpl.Workflows.Runtime.Coreimpl.Persistence.Coreimpl.Locking.Coreimpl.Serialization.CoreimplWorkflowExecutableDesignRuntime
Status — draft in places · subject to refinement

Elsa Foundation · transitional architecture brain for Elsa Workflows