- rm config/ (cassandra/mysql/postgres/dual-cluster fork yamls)
- rm develop/ (fork docker-compose / grafana / temporalio-dashboards submodule)
- rm docs/{admin,architecture,development,_assets,ui-screenshots,Makefile,README.md,worker-versioning.md}
(kept docs/red-review-zap-sdk.md — pkg/sdk port review)
- rm k8s/{configmap.yaml,init-db.yaml,kms-secrets.yaml} (dynamic config + Postgres init for fork)
- rm .gitmodules (was: temporalio-dashboards Grafana, gone)
- Dockerfile: 27 lines, no CGO, no SQLite driver, exposes :9999 (ZAP) + :7243 (HTTP)
- Makefile: 30 lines, just build/ui/run/vet/test/tidy/clean
- k8s/deployment.yaml: single Deployment, single Service, single Ingress, /healthz probes
- k8s/kustomization.yaml: 2 resources (deployment + ingress)
Binary: 6.65 MB (-trimpath -ldflags="-s -w"), RSS 13 MB, boots <1s, all probes 200.
12 KiB
CHASM: Coordinated Heterogeneous Application State Machines
This document is a step-by-step introduction to the core architecture and domain entities of the CHASM framework.
Why CHASM?
Temporal Workflows are powerful, but they have real limits: too slow or heavyweight for some problems, unable to scale in every dimension (e.g. millions of signals, large payloads), and overly complex when a purpose-built solution would be simpler.
CHASM addresses this by treating Workflow as just one Application State Machine (ASM) among many. An ASM is a specialized state machine that leverages Temporal infrastructure like sharding, routing, atomic storage, failure recovery without the full cost of a Workflow — and hides those distributed systems details behind a clean, typed API so developers can focus on business logic.
Application State Machine (ASM)
An ASM is a registered state machine type, composed of a Library, Component types, and Tasks.
|
|
RegistryThe global catalog of all registered Libraries. LibraryA Library groups components, tasks, and service handlers into a namespace. Examples: Component typeA registered type that defines state (Fields) and behavior. Each Component type is identified by a name (aka Archetype), which CHASM converts to a stable ID (aka Archetype ID) for storage.
TasksAsynchronous work units (e.g. network calls, timers) that a Component type can schedule. Registered in Library alongside Component types. FieldsThe framework-managed containers for a component's persisted state. |
Component State
A Component's state is made up of typed Fields. CHASM uses these to persist and replicate data.
Execution
An Execution is a runtime instance of an ASM. Namespace retention, visibility records, and ID reuse policies all apply at the Execution level.
|
|
Node (state)The state of the Execution where
The root Node and its descendants form the CHASM Tree of the Execution. ComponentPathThe sequence of Names from the root to a child Node within an Execution (e.g. |
Component Lifecycle
Every Component implements a lifecycle method that CHASM uses to determine whether it has reached a terminal state.
Engine
The Engine is the entry point for interacting with Executions.
|
|
Write
MutableContextProvided during write operations. Allows writing Fields and scheduling Tasks. |
Transition
A Transition is the atomic unit of state change in CHASM. It operates on the entire Execution — any Node can be read or mutated.
|
|
EventAny external trigger delivered to a Component — e.g. a network callback, timer firing, or incoming signal. Transition FnDeveloper-provided code that runs when the Event is delivered. May write Fields and schedule Tasks. AtomicityAll Field writes and Task schedules from a transition commit together as a single database write, or roll back entirely. On commit, every modified Node is stamped with a new VersionedTransition. |
Tasks
Transitions can schedule Tasks for deferred work. There are two kinds, differing in when they run and what they can access. Tasks are written atomically with the component state (transactional outbox pattern), guaranteeing no work is silently lost on crash.
VersionedTransition
Every transition is stamped with a VersionedTransition — the logical clock of CHASM.
ComponentRef
When a component starts an external task and needs the result routed back as a callback, it creates a ComponentRef — a serialized token that acts as a return address.
|
|
Contains the full ExecutionKey and ComponentPath so the callback can find the right node. Also carries two VersionedTransition values:
Consistency CheckWhen a callback arrives, the Engine loads the Node at the given ComponentPath and verifies both VT values before allowing the transition to proceed. A mismatch on either value causes the callback to be rejected. |
Visibility
Visibility is a built-in child Component that manages an Execution's visibility record.
Typical Package Layout
Each ASM is a self-contained package.
my_asm/
├── proto/
│ └── my_asm.proto # Service API (gRPC) and state/field message types
├── <component>.go # Component struct, Field declarations, lifecycle method etc.
├── config.go # Dynamic config settings for the ASM
├── frontend.go # Frontend gRPC handler to map API calls to Engine operations
├── fx.go # fx module to wire the Library into the application
├── library.go # Registers component and task types with the Library
└── statemachine.go # (optional) Transition declarations using the statemachine framework