Concepts

Workflow modes

Workflow code has to run somewhere, and Hopskip runs it in one of four modes: a Wasm module, a V8 isolate, a deterministic microVM, or an HTTP integration for code it cannot host at all. Which one your workflow uses depends on the language it is written in.

The mode changes what is under your code, not what your code can rely on. Every mode gives the workflow the same contract:

  • deterministic replay: the same recorded history reproduces the same execution (Determinism & the sandbox),
  • a checkpoint at every await, with snapshots and millisecond resume (Memory snapshots),
  • the same event log, the same hop commands, the same activity dispatch.
ModeWhat executes your codeLanguagesDeterminism enforced by
Wasm modulethe universal worker, embedding WasmtimeRust, Python, Go, Haskellthe host imports the module is allowed to link
V8 isolatethe V8 worker, a real V8 engine in the worker processTypeScriptthe same ABI surface, rebound by the host
AD-VM microVMa forked Firecracker microVManything that runs on Linux: JVM, BEAM, Ruby, native binariesthe hypervisor, at the syscall layer
HTTP integrationyour own systemsystems with no code accessnot enforced; Core owns retries and idempotency

Wasm module

Most guest languages compile to a Wasm module, and the worker executes that module with Wasmtime. The module imports exactly the versioned workflow ABI (hopskip:workflow@0.1): logical time, a seeded random, durable sleep, activity invoke and await, searchable-state emission, and logging. There is no network, no filesystem, and no wall clock to link against, which is why non-deterministic workflow code fails at instantiation instead of misbehaving at replay (Compatibility & versioning).

A snapshot of a suspended Wasm workflow is its linear memory plus exported globals, nothing else, so instantiation and resume are sub-millisecond.

How each language gets to a module differs, and the build handles it:

  • Rust compiles to wasm32-unknown-unknown directly.
  • Go builds a reactor module with Go 1.24’s wasip1 support; its runtime’s WASI imports are rewritten into deterministic local functions at build time.
  • Haskell compiles through the GHC Wasm backend into a reactor with no WASI imports at all.
  • Python wraps your workflow in a pinned interpreter compiled to Wasm.

See each SDK page for the build commands.

V8 isolate

TypeScript workflows do not compile to Wasm. They run on a real V8 engine inside the V8 worker process, as ordinary JavaScript with the SDK’s async machinery.

The determinism rules are the same and are enforced the same way, at the boundary: Date.now() returns logical event time, Math.random() is seeded from the workflow ID, and fetch inside workflow code is not available. The SDK’s bundler wraps your entry point with shims that speak the same workflow ABI a Wasm module would.

At each await, V8 parks the suspended frame on its own heap, so a snapshot is that heap. hop dev runs the V8 executor in-process, which is why a TypeScript workflow runs with the same one command as a Rust one. See the TypeScript SDK.

AD-VM microVM

Some code cannot compile to Wasm at all: JVM services, Ruby or Python native extensions, threaded native binaries. The AD-VM tier runs those unchanged inside a deterministic microVM: a forked Firecracker whose device models are patched so the guest’s clock, entropy, and external input come from the engine rather than the hardware. The hypervisor traps the timestamp counter, serves deterministic entropy seeded from the workflow ID, and advances time only when the engine applies an event, which is the same clock rule the other modes enforce with host imports.

A snapshot in this tier is a full VM image, and restoring one takes on the order of 5 to 10 milliseconds rather than sub-millisecond, so the tier exists for the languages that need it, not as the default. It also needs KVM, so it runs on Linux hosts.

The hop sandbox command gives you the same determinism guarantees on a laptop using a container runtime and a supervisor instead of a hypervisor: useful for testing code destined for either tier, since recordings made locally replay on the production tier.

HTTP integration

For workloads Hopskip cannot host, the engine can hand dispatches to your own system as signed HTTP calls: a webhook gateway translates a task dispatch into a request, with a synchronous 200 for quick work or 202-plus-callback for long-running work, and Core owns the retries, timeouts, and idempotency keys. A related co-process agent embeds in an existing monolith, maintaining the worker stream and executing tasks by spawning language-native processes. In this mode Hopskip schedules and remembers but does not execute your code, so determinism is your side of the contract.

Which mode will my workflow use?

You do not pick a mode directly; the language does:

  • TypeScript: V8 isolate
  • Rust, Python, Go, Haskell: Wasm module
  • JVM, BEAM, Ruby, native binaries: AD-VM microVM
  • no code access (an existing HTTP system): webhook gateway

Whatever the mode, the workflow’s history, replay, snapshots, activity dispatch, and the hop command surface are the same.