Run limits

What keeps a movement someone else wrote from harming the host that runs it. An embedder can let its customers write movements; these are the bounds it relies on.

The limits #

limitkept bydefaultthe host sets it withcode when exceeded
Steps: statements run plus expressions evaluated, per segmentengine10,000,000limits.maxSteps (TypeScript: RunInput.limits)MOVENG_LIMIT_STEPS
One text's size, in UTF-8 bytesengine16 MiBlimits.maxTextBytesMOVENG_LIMIT_TEXT_SIZE
One list's members, or one map's keysengine1,000,000limits.maxCollectionItemsMOVENG_LIMIT_COLLECTION_SIZE
The segment's result, as JSON textengine64 MiBlimits.maxResultBytesMOVENG_LIMIT_RESULT_SIZE
Call depth: named calls nested in one runengine32maxCallDepthCallDepthExceeded (lf prints MOVENG_CALL_DEPTH)
Wall clock per segment, waits includedrun host900 sMOVEMENT_MAX_SEGMENT_SECONDS (TypeScript: also RunInput.maxSegmentSeconds)MOVENG_LIMIT_WALL_CLOCK
Cost per run: model calls and priced pluginsengine and run hostno capspend.capMicrodollars (lf: maxRunCostUsd in lf.yaml)RunCostCapExceeded (the flow suspends where the host can park it)
Module calls per runrun host2,000lf: REMOTE_ADAPTER_MAX_CALLS_PER_RUNAdapterCallCeilingExceeded
type SegmentLimits = {          // on the segment's input, beside maxCallDepth
  maxSteps?: number;            // whole and positive; absent: the default
  maxTextBytes?: number;
  maxCollectionItems?: number;
  maxResultBytes?: number;
};

lf and the TypeScript host read each engine limit from the environment, as they read the call depth: MOVEMENT_MAX_STEPS, MOVEMENT_MAX_TEXT_BYTES, MOVEMENT_MAX_COLLECTION_ITEMS, MOVEMENT_MAX_RESULT_BYTES. A value that is set but is not a positive whole number refuses the run; it is never read as no limit. On the TypeScript host a run's own limits override the environment's, one limit at a time.

Provider limits #

Separate from the bounds above: what keeps a host's calls to modules and models inside what the provider allows. These never fail a run. They make a call wait.

How each is kept #

The cost cap is the same on every host #

A movement reaches the network only through modules #

Reviewed for this release:

Measured peaks, and why the defaults stand #

Measured 2026-10-18 by instrumenting the engine (a counter beside each check, not kept): every program the repository's tests run on the Rust engine. That is the Rust crates' tests (the oracle and frozen programs, lf, the embedding example), the TypeScript engine package's tests and the platform's movement_engine tests (both on the WASM build), 3,378 + 743 + 721 tests. The lf examples were not run: they need a live external system.

limithighest observed in one segmentdefaultdefault over peak
Steps19810,000,000about 50,000 times
One text902 bytes16 MiBabout 18,000 times
One list or map5 members1,000,000about 200,000 times
Result as JSON34,396 bytes64 MiBabout 2,000 times
Wall clocknot measured (the tests run in milliseconds)900 snot applicable

Not covered #