Embed Arcana
Use the compiler and runtime in your own application: declare a host, replay data, step a live run and retain checkpoints.
An application embeds Arcana by declaring a host, compiling a program against it and supplying the observations that program reads. The Rust library is arcana-core; @arcana/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 @arcana/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 22.18 or newer, npm and Rust with the wasm32-unknown-unknown target installed, run this from arcana/npm. A copy of arcana/ alone is sufficient; the root application and Justfile are not required:
npm ci
npm test
npm packThese commands install development dependencies, build the JavaScript and WebAssembly, run the tests and pack the result. At the current package version, the output is arcana-core-0.1.0.tgz in that directory; the version in 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:
npm install /path/to/authorized-checkout/arcana/npm/arcana-core-0.1.0.tgzIn Node, await loadArcana() 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 loadArcana.
To use local files or pipe your own source adapter into a retained run without writing an embedding service, follow Run Arcana locally. The packaged CLI accepts the same host declaration as the API and returns evaluated outputs and unsent action intents.
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 does.
Store the program source, its host and library configuration, and its compiled language version together. A program can pin its version with arcana "0.1";; a host can record a version for source that omits that line. Restoring a checkpoint requires the same compiled program identity.
Use arcana.resolveLibraries(source, host) to obtain and persist the exact transitive dependency sources, including reached standard libraries. The extension guide 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:
import { loadArcana } from '@arcana/core';
const arcana = await loadArcana();
const host = {
sources: [
{ name: 'bars.close', type: 'number', keyed: true, intervals: ['1h'] },
],
capabilities: [],
};
const source = `arcana "0.1";
uses { bars: "^1" }
const close = bars.close("DEMO-USD", "1h");
metric("average", sma(close, 3));
`;
const compiled = arcana.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 = arcana.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 = arcana.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 {
arcana.drop(compiled.program);
}Persist a new checkpoint and the cursor naming its consumed inputs as one application-level commit. Arcana produces checkpoint text; it does not provide a database, subscription cursor or transaction around your storage.
For one bar at a time, arcana.run(program) creates a run. run.step(values, time) consumes one completed bar; run.snapshot() returns a result containing checkpoint text. Restore with arcana.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 arcana.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 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 for the complete host contract, runtime semantics and diagnostics. For ftw.trade's own host, modules, accounts and execution workflow, use its platform guide.