Core concepts
Journaled replay, exactly-once effects, and deterministic time — in plain terms.
Tide makes ordinary TypeScript durable: a workflow that crashes, restarts, or is redeployed resumes exactly where it stopped, without repeating completed work. Four ideas make that work.
The journal
As your workflow runs, Tide records every operation — file writes, sleeps, console output, steps, ontology mutations — as an entry in a journal, persisted to a storage backend. The journal is the single source of truth for what the workflow has already done.
Replay
Re-run a workflow with the same invocation id and Tide enters replay mode. Your code runs again from the top, but each operation returns its stored result from the journal instead of executing live. Once the journal is exhausted, execution switches to live mode and new operations are appended. A crash is just a replay that runs a little further than the last one.
This is why an invocation id matters: it names the journal. The same id replays;
a new id starts fresh. (Omit -i and Tide generates a UUID — a one-shot run
with no replay.)
Determinism
Replay is only safe if the code produces the same sequence of operations every time. Tide enforces this: if a replayed run asks for a different operation than the journal recorded at that position, it raises a determinism violation.
In practice this means: don't branch on Math.random() or wall-clock time, and
don't reorder already-journaled operations. You can freely change log
messages, add operations after the last journaled one, and change logic inside a
step (a step is one atomic entry from the journal's point
of view). See Durable execution for the full
rules.
Exactly-once effects
Some operations reach beyond the workflow — a human-approval request, an LLM
call, an ontology mutation. Tide reserves a deterministic effect intent
before such a call runs, keyed by (invocation id, effect ordinal). The
reservation is idempotent: a crash-and-replay re-reads the existing reservation
instead of re-invoking the host. So these effects happen at most once, even
across crashes — on every storage backend, not only in a database.
Deterministic time
On first run, Tide captures Date.now() and freezes it. Every Date.now()
and new Date() for the rest of the invocation returns that same value, and the
frozen timestamp is replayed on later runs. A workflow that ran at 2 PM and
replays at 3 PM sees the same time — so time-dependent branching never breaks
replay. (performance.now() always returns 0.)
Steps
A step wraps several operations into an atomic unit: they all commit together or roll back together. On replay a completed step returns its stored result without re-running its body. Steps are how you make multi-operation work reliable and how you isolate logic that might change across deploys. See Steps.
Putting it together
- Write
{ schema, main }.schemavalidates and persists the input. - First run: validate → run
main→ journal every operation. - Re-run with the same id: replay the journal, then go live.
- Steps commit atomically; external effects are reserved exactly-once; time is frozen.
Next
- Durable execution — the journal, replay, and determinism in depth.
- Steps — atomic transactions and retries.
- Driving Argon — typed, journaled ontology state.