Plate 01 — The Foundation

Elsa
Foundation

The architectural blueprint for the next generation of Elsa Workflows.

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

12+
Domains
.Core
Contracts
1
Artifact seam
FIG. 01 — System Plan · scale 1:50
ELSA.WORKFLOWSELSA.RUNTIMEELSA.ACTIVITIESELSA.PERSISTENCEELSA.CATALOGSELSA.EXTENSIONSELSA.MODULARITYElsa.Server.COREA1F1A6F6
Plate IIThe 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
Plate IIIThe 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.

Plate IVDomain 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

Plate VThe 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.
Plate VIRuntime 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.

DESIGNRUNTIMEdraftsdesigner metahistoryWorkflowExecutablesealed artifactexecute
§ 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 Elsa 4 execution model, not a ratified constitution rule.

Provisional · conceptual actors, not concrete class names
Elsa runtime actor systemWorkflowExecutableartifact(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

Plate VIIIExtension model

Extend without coupling

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.

Plate XEvents & contributions

One event concept, explicit delivery strategy

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
Plate XICatalogs

Catalogs replace live guessing

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.

Plate XIIProvider modules

Providers are siblings, not leaks

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

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

Compatibility through import

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

Elsa 3 definition
legacy asset
Import Adapter
one-shot map
Elsa 4 entities
native models
Elsa 4 runtime
executes natively
Plate XIVImpact

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