Waits & replay
Progress lives in the log. Processes, workers, and UI caches are disposable. When a thread needs to pause for a human, webhook, child, or timer, it parks with its progress preserved until a matching event arrives. Host scheduling, storage, and connected clients determine resource usage.
Waiting & parking#
Registering a Wait checkpoints state to the log and releases worker resources. Days or weeks later, an approval or webhook signal wakes the thread with the same state. Matching is by event type plus an optional payload subset (e.g. match: { approvalId }).
import { wait } from '@swirls/looms/core'// Wait for a matching domain event (optional payload subset):wait({ waitId: 'appr_1', on: { type: 'approval.decided', match: { approvalId: 'appr_1' } },})// Wait until a wall-clock time (sleep / deadline):wait({ waitId: 'sleep_1', on: { timerAt: Date.now() + 60_000 },})Workflows and approvals compose the same primitive: charge, then wait for payments.charge.authorized; gate a human, then wait for approval.decided. See Modules and Examples.
Wake#
After a signal or timer lands, the host wakes the run: load snapshot + delta, reduce outstanding events, dispatch effects, then park again if still waiting. Actor cells enforce a single writer per runId, so wake cycles stay simple: no distributed locks inside the execution loop.
Replay#
State is derived by folding events through pure reducers. Replay reconstructs thread state or views without re-executing nondeterministic effects. replayTo(runId, seq) returns state before and after that event. The debugger and @swirls/looms/testing use it.
Snapshots#
A snapshot is a persisted projection checkpoint that accelerates reconstruction for long streams. On cold start the cell loads the latest snapshot, then applies the delta of events since that point.
How and where the log lives in production: Hosting & storage. Authoring waits and effects: Modules. The systems behind these ideas are listed in Prior art.