# Embed Flowscript

> Use the compiler and runtime in your own application: declare a host, replay data, step a live run and retain checkpoints.

[Canonical documentation](https://flowscript.ftw.trade/docs/embedding)

An application embeds Flowscript by declaring a host, compiling a program against it and supplying the observations that program reads. The Rust library is `flowscript-core`; `@flowscript/core` exposes the compiler and evaluator to JavaScript and TypeScript through WebAssembly. The JavaScript package has no runtime dependencies and does not depend on ftw.trade.

## Install and load

There is currently no public package release or public download of `@flowscript/core`, and it is not published to the npm registry. Embedding it locally requires authorized access to the source repository. These docs describe the library that exists in that checkout; they do not offer a public installation URL.

With Node.js, npm, Rust with the `wasm32-unknown-unknown` target, and `just` installed, run this from the checkout's root:

```sh
just flowscript-pack
```

The recipe installs the library's development dependencies, type-checks, builds the JavaScript and WebAssembly, runs the tests and packs the result. At the current package version, its output is `flowscript/npm/flowscript-core-0.1.0.tgz`; the version in `flowscript/npm/package.json` determines the filename. Packing does not publish the artifact.

Install the resulting tarball from your application directory. Replace the example checkout path with your actual source location:

```sh
npm install /path/to/authorized-checkout/flowscript/npm/flowscript-core-0.1.0.tgz
```

In Node, `await loadFlowscript()` loads the WebAssembly shipped beside that installed package. In a browser it fetches that file. A bundled application must serve the file itself and pass its bytes or a compiled `WebAssembly.Module` to `loadFlowscript`.

Compiler and evaluator calls are synchronous. Run them in a Web Worker when embedding in a browser so evaluation does not block the interface.

## Declare your host

The host determines what a program may read and call:

- **Sources** declare names, value types, key shapes and available intervals. The application supplies the actual samples.
- **Capabilities** are manifests declaring action names and arguments. Declaring an action does not implement or authorize an external transaction.
- **Libraries** supply named source imports. **Integrations** describe which implementations serve particular interfaces and markets.

An undeclared read or action is a compiler refusal. A host can declare sources without any capabilities, as the [quickstart](https://flowscript.ftw.trade/docs/quickstart) does.

Store the program source, its host and library configuration, and its compiled language version together. A program can pin its version with `flowscript "0.3";`; a host can record a version for source that omits that line. Restoring a checkpoint requires the same compiled program identity.

Use `flowscript.resolveLibraries(source, host)` to obtain and persist the exact
transitive dependency sources, including reached standard libraries. The
[extension guide](https://flowscript.ftw.trade/docs/extending) shows how to compose and test user libraries,
implement custom tool consumers and record external model predictions.

## Replay and checkpoint

`compile` returns a program or located problems. `replay` takes a program and a history with `len` rows, input columns by source name, and optional evaluation timestamps in seconds. It returns per-bar metrics and decisions, or an error. Inspect `unmodelled` too: a successful result can identify behavior the selected evaluation configuration did not model.

For batches, `{ save: true }` returns a checkpoint in `snapshot`. Pass that text as `{ resume: snapshot }` with only the observations after it. This complete example uses illustrated hourly inputs and no actions:

```js
import { loadFlowscript } from '@flowscript/core';

const flowscript = await loadFlowscript();
const host = {
  sources: [
    { name: 'bars.close', type: 'number', keyed: true, intervals: ['1h'] },
  ],
  capabilities: [],
};
const source = `flowscript "0.3";
uses { bars: "^1" }
const close = bars.close("DEMO-USD", "1h");
metric("average", sma(close, 3));
`;
const compiled = flowscript.compile(source, host);
if (!compiled.ok) throw new Error(JSON.stringify(compiled.problems));

try {
  const firstClose = Date.UTC(2026, 0, 1, 1) / 1000;
  const first = flowscript.replay(compiled.program, {
    len: 3,
    series: { 'bars.close': new Float64Array([100, 102, 104]) },
    time: new Float64Array([firstClose, firstClose + 3600, firstClose + 7200]),
  }, { save: true });
  if (!first.ok) throw new Error(first.error);
  if (first.unmodelled.length) throw new Error(first.unmodelled.join('; '));
  if (typeof first.snapshot !== 'string') throw new Error('No checkpoint returned');

  // Your application persists this text with its input cursor and configuration.
  const saved = first.snapshot;

  const next = flowscript.replay(compiled.program, {
    len: 2,
    series: { 'bars.close': new Float64Array([106, 108]) },
    time: new Float64Array([firstClose + 10800, firstClose + 14400]),
  }, { resume: saved, save: true });
  if (!next.ok) throw new Error(next.error);
  if (next.unmodelled.length) throw new Error(next.unmodelled.join('; '));
  if (typeof next.snapshot !== 'string') throw new Error('No checkpoint returned');

  console.log(Array.from(next.metrics.average)); // [104, 106]
} finally {
  flowscript.drop(compiled.program);
}
```

Persist a new checkpoint and the cursor naming its consumed inputs as one application-level commit. Flowscript produces checkpoint text; it does not provide a database, subscription cursor or transaction around your storage.

For one bar at a time, `flowscript.run(program)` creates a run. `run.step(values, time)` consumes one completed bar; `run.snapshot()` returns a result containing checkpoint text. Restore with `flowscript.run(program, { snapshot })`, check each result and call `run.drop()` when finished. Supply the same paper-broker configuration when restoring a run that used one. Call `flowscript.drop(program)` after its runs have been dropped.

Each successful step returns structured metrics, text and decisions for your application to consume. [Outputs and consumers](https://flowscript.ftw.trade/docs/outputs) shows a complete adapter that builds chart rows, unsent action records and application logs from those real results.

## Preserve the boundary

The application owns data collection, bar construction, units, ordering, freshness and durable input cursors. An omitted observation in `run.step` holds its prior value; `null` explicitly supplies an unknown observation. Choose that behavior deliberately for your feed.

An action decision records what the program requested. Sending it to a venue, protecting signing keys, enforcing trading permissions and reconciling the actual outcome are application responsibilities. The optional paper broker models explicitly configured orders; it is not a venue depth or partial-fill simulator.

Runtime refusals and `unmodelled` behavior must reach the caller. Do not replace them with fabricated values or silently restart evaluation. A WebAssembly trap invalidates existing program and run handles; compile explicitly and restore a validated checkpoint before continuing. Checkpoint identity mismatches are refused.

Read the [language reference](https://flowscript.ftw.trade/docs/reference) for the complete host contract, runtime semantics and diagnostics. For ftw.trade's own host, modules, accounts and execution workflow, use [its platform guide](https://docs.ftw.trade/strategies/overview).
