Skip to main content
In strict-web mode (and in every meow test run), meow is hermetic by default: the sources of ambient nondeterminism — wall-clock time, randomness, environment variables, timezone, and locale — are routed through one governed seam that, by default, substitutes a deterministic stand-in for the real host source. A grant swaps the real source back in. The result: run the same code twice, on two different machines, in two different timezones, and you get byte-identical output.

The three sources

Clock

A fixed virtual clock instead of wall-time.

Randomness

A seeded ChaCha20 stream instead of OS entropy.

Environment

Invisible host environment instead of process.env.

The virtual clock

By default, Date.now(), new Date(), and performance.now() read from a fixed virtual origin — 2026-06-07T00:00:00Z — rather than the host wall clock. The clock advances only as the runtime’s own timer queue fires (setTimeout); it does not track real elapsed time.
console.log(Date.now());        // 1780790400000 — the virtual epoch, every run
const start = Date.now();
doSomeWork();
console.log(Date.now() - start); // 0 — wall-time hasn't moved
A program measuring elapsed wall-time sees zero progression under the default clock. That’s intentional and exactly what a test runner wants — it makes timing-dependent code reproducible instead of flaky.

Seeded randomness

Math.random() and crypto.getRandomValues() draw from a ChaCha20 CSPRNG seeded with a fixed 32-byte seed. The stream is identical across runs and machines.
console.log(Math.random()); // same value, every run, every machine
crypto.subtle (hashing, signing, key derivation) is unaffected — it’s deterministic by nature.

Timezone & locale pinning

A fixed clock value isn’t enough on its own: V8/ICU read the host TZ and LANG to render dates and locale-default Intl. So under the virtual clock, meow also pins the process timezone to UTC and the default locale to en_US.UTF-8 before the isolate is created.
new Date(0).toString();           // identical across host timezones
new Intl.NumberFormat().format(1234.5);  // identical default locale

// Explicit-locale APIs are never touched:
new Intl.NumberFormat("de-DE").format(1234.5); // "1.234,5" — as you asked

Granting the real host

Determinism is the default, not a cage. Opt back into real sources per-capability:
meow run app.ts --allow-clock     # real wall-clock + timezone + locale
meow run app.ts --allow-random    # OS entropy for Math.random / crypto
meow run app.ts --allow-env       # expose host environment variables
meow run app.ts --trust           # all of the above
In node-compat mode, the real clock, OS entropy, and full environment are on by default — no grant needed. See Permissions & trust for the full grant model.
When both the clock and RNG are real (under --trust or in node-compat), meow skips installing the JavaScript shadows entirely and routes straight to V8’s native intrinsics — so you pay no overhead in the hot path for determinism you aren’t using.

Why this matters

Reproducible tests

No more flaky tests that depend on the current time, a random seed, or the CI box’s timezone. Snapshot a value once; it holds forever.

Reproducible builds

The same inputs produce the same artifacts — across developer laptops and CI runners.

Edge & serverless

Code that’s deterministic by default ports cleanly to distributed, short-lived execution environments.

Easier debugging

A bug that reproduces on your machine reproduces on everyone’s. Nondeterminism is a grant you can see in the command line.

Scope

Hermeticity closes the ambient nondeterminism path — it’s defense-in-depth, not a security sandbox against adversarial code.A program that retains a reference to an intrinsic captured before the shadows are installed, reaches an unshadowed intrinsic, or uses eval/FFI can still read the real host. Determinism is not isolation: don’t run code you don’t trust and assume “hermetic” means “sandboxed.”

Next: the permission model

How grants compose, and what --trust actually turns on.