Browse docs

Start here

examplesGetting started with Flowdocumentation

Design

FoundationsLanguage architecturePhilosophy

Language specification

Program checkingConcurrencyDataEffectsResults, Tool problems, and faultsGrammarHistoryModules and importsLanguage specificationEvaluationStandard libraryToolsTypes

Runtime

Runtime architectureThe host boundaryDiagnosticsRunning a programThe history format

Guides

Writing programs that reach checkpointsImplementing Tools with a toolkitLoops that never returnRecursive delegationSharing types between Tool modulesHarnesses over tool registries

Foundations

This document sits between philosophy.md and the language and runtime architectures. The philosophy says why Flow exists. Foundations states the invariants that follow: facts Flow cannot choose, scope decisions it does choose, and requirements those facts and decisions force.

Mechanisms belong in language/architecture.md and runtime/architecture.md. Exact behavior belongs in the specifications. A lower layer cites a foundation by name; it does not make a new foundation by describing a mechanism, and where a lower layer disagrees with this document the disagreement is a defect in the lower layer.

Everything here is target normative design. Flow is pre-release; the runtime architecture owns the ledger of what is not yet implemented.

Three kinds of statement appear here:

  • Givens are facts about orchestration and the world outside a program.
  • Decisions define what Flow owns and deliberately leaves elsewhere.
  • Requirements are properties every conforming Flow implementation must satisfy.

The givens

Outside answers are not derivable

A program cannot derive what a service, person, clock, random source, or other external system will answer. Those values enter the execution from outside its deterministic computation. External answers may also be mistaken, dishonest, or inconsistent; satisfying a type does not make their content true.

Effects cannot always be repeated

A call may send a message, publish data, charge money, or alter another system. Repeating it to rediscover its outcome can repeat the effect. A process can also fail after an attempt may have reached the world but before an admissible reply reaches the program. Uncertainty is therefore an ordinary possible outcome of effectful orchestration.

Runs outlive process memory

Automated work may wait for a person or service and outlast both the process executing it and the tool implementations that began it. An in-memory continuation is not a durable account of what the run meant.

Concurrency can select an outcome

Concurrent work does not always have one derivable interleaving. When an orchestration accepts one among several possible results, that selection can change what the program does next. Such arbitration is part of the execution's meaning even when ordinary computation remains deterministic.

Every record has a boundary

Flow can record only what crosses a boundary it owns, what its evaluator decides, and the continuity facts a host supplies through that boundary. It cannot observe hidden work inside a tool or unrelated work in the surrounding application. No record can authenticate its own writer, and a stored history holds whatever it recorded, so its confidentiality and integrity depend on the host that keeps it.

The decisions

Flow owns a closed evaluation model

Flow is a language rather than an unrestricted library API. Outside values that can affect a Flow run enter through declared inputs or typed tools. Ordinary computation between those observations follows deterministic language rules, and a selection among concurrent outcomes enters only as a recorded non-derivable choice. There is no ambient host-language callback, native effect, or environment read inside the Flow boundary. A restricted host-language profile that enforces the same closed semantics is another surface for the Flow language, not an escape from it.

Tools are declarations, not implementations

A Tool is a function declared in Flow source whose body is outside Flow: its signature defines what Flow may request and the value shapes that may cross. Programs call Tools like functions and pass them like any function value; they never construct or inspect the implementation behind one. A Tool may hand back a host-made value, such as a browser page or a model instance, that only the host can create; inside the run it is an opaque token.

The application or host supplies the implementation. It may be in process, in another process, on another machine, or behind infrastructure Flow does not know. A Tool's signature does not authenticate the provider, prove its reply truthful, or confine authority the implementation holds elsewhere.

History carries non-derivable meaning

Flow records the outside observations and runtime arbitration needed to reconstruct an execution. It does not log every deterministic branch or instruction. Given the exact program, inputs, and admissible history, ordinary computation is derived again under the language semantics.

Replay and resume read one history

Replay is re-execution against semantic history. Deterministic Flow computation runs again, while recorded Tool observations and orchestration outcomes are served from the record rather than dispatched. Resume is the same re-execution continued past the end of the record: a new process starts from the latest checkpoint, reads what is recorded, and continues live. A runtime may keep its own snapshot to resume faster, but that snapshot is a cache with no meaning and can always be rebuilt from history.

Applications remain applications

Flow owns one bounded orchestration. Applications own their model loops, sessions, subagents, prompts, goals, product policy, durable application state, and recovery outside the Flow run. Applications and hosts decide which implementations back the run's Tools; a program may still choose among the host-made instances it was handed. Hosts and deployments own tool lifecycle, credentials, isolation, retention, and other operational guarantees. Flow may run inside or beside those systems; it does not replace them.

The requirements

Visible outside influence

Every outside value that can affect Flow execution enters through a declared input or a Tool call, and every other fact that can steer the run enters only as a recorded non-derivable choice. There is no second, unrecorded observation path, and no program reads its own history, position, mode, or binding identity as ambient state. Time, entropy, configuration, and human input obey the same rule rather than becoming ambient exceptions.

Typed, composable crossings

A Tool call is ordinary typed program structure. Tools can flow through values and control flow as function values, while each call remains identifiable as an outside request, and every function that can make one is marked as able to. Protocol conformance governs the request and reply shapes and nothing more: admission certifies that Flow could interpret a value, not that it is true, authorized, or came from any particular party.

Deterministic reconstruction

For the same versioned program, inputs, and admitted history, conforming implementations produce the same Flow-observable behavior. Ordinary branches and calculations are reconstructed from their inputs. Any runtime outcome that can steer the run, including a scheduling or admission decision, is either derived from language semantics or retained in semantic history. It is never reconstructed from host threads, transport topology, or an implementation's private queue.

Semantic execution history

History contains enough Flow-observed meaning to explain the path taken and to check replay: the exact program and root input, the boundary calls, the admitted outcome of each call and where it entered the run, non-derivable scheduling and arbitration, and the execution outcome as far as the validated record reaches. It is shaped around program, call, request, and outcome; which implementation a host bound is the host's record. It is not a complete application trace, provider log, data-lineage proof, or account of the outside world.

Recorded before its consequence

A live Tool request is accepted into semantic history before it is dispatched, and an admitted outside transition is accepted before its consequence is exposed to Flow computation. This ordering is the foundation; which durability mechanism provides it, and how strong that guarantee is, belong to the runtime specifications.

Replay without dispatch

Replay re-executes the program and validates it against an admissible history. It installs no tool implementation and dispatches nothing. A missing, reordered, contradictory, or unconsumed observation makes the replay incomplete or divergent rather than silently turning it into a fresh run.

Crash-resumable execution

Semantic history alone is enough to resume a run after process death: re-execute from the latest checkpoint, serve every recorded observation, and continue live where the record ends. A checkpoint is recorded only where the run's whole state is something the record can hold — data, host tokens already recorded, and tasks parked on their only Tool call — so it means the same to every implementation. Tool implementations, sockets, credentials and application state remain outside the record and are reinstalled by the host. Intentional rewind creates a new run that records its parent rather than changing the old one.

Honest uncertainty

Once a recorded call may have been dispatched, absence of an admitted outcome never authorizes automatic re-dispatch; Flow infers no mutating or repeatable class of operation to decide otherwise. When interruption or unresolved delivery leaves no admitted outcome, that state stays explicit rather than becoming success or failure. Flow makes no exactly-once guarantee for effects in systems it does not control. An admitted success or failure is still the tool's claim about its protocol outcome, not independent proof of the world's state.

Honest withholding

A history may be stored with values withheld or redacted, but the reporting must say so. A missing required observation is a hole regardless of why, and a history with a hole is replay-incomplete rather than merely quieter. A digest standing in for a value witnesses integrity; it is not the value and cannot drive re-execution. Substituting a masked value while still calling the record complete is worse than a hole, because the record then lies.

Bounded trust and disclosure

The compiler and runtime are trusted to implement the language and record it honestly. Tool implementations, their operators, and their replies are not made trustworthy by crossing a type boundary. Histories may disclose their recorded values; access control, encryption, integrity, retention, and any redaction guarantee belong to the systems that actually enforce them. Anchoring detects alteration only against an anchor outside the holder's control, and no anchor authenticates the record's writer.

Stable meaning

Once released, published programs and histories never acquire a different meaning silently. Exact contracts are versioned, and an incompatible change takes a new language version, or a new data version for the value encoding, the Tool protocol and the history format. Flow is pre-release and makes no compatibility promise yet (runtime architecture).

A general core, bounded in scope

A language mechanism belongs only when a required orchestration cannot be expressed clearly by composing existing deterministic forms, typed tools, and semantic history. A mechanism specialized to one provider, transport, policy, deployment, or product stays in the application, host, runtime, library, or guide that can own it honestly.

What these foundations do not require

Flow does not universally require or claim:

  • authorization, approval placement, budgets, revocation, or operator control;
  • filesystem, network, process, or provider-specific policy in the language;
  • sandboxing or confinement of arbitrary tool implementations;
  • complete observability of tool internals or the surrounding application;
  • one runtime topology, process model, transport, or container lifecycle.

Applications, hosts, libraries, and deployments may provide these properties. Their guarantees come from their own enforcement and evidence, not from Tool declarations or semantic history alone. Each claim is stated by its owner: Flow explains the orchestration it evaluated and observed; the host explains binding, enforcement, and storage; the application explains people, sessions, policy, and product actions.

Everything below this layer is a mechanism, exact contract, implementation, or guide. Where a lower layer disagrees, the disagreement is a defect to repair; the lower layer does not silently redefine these foundations.