A project crate that path-depends on the engine and lives under the engine repo (common during authoring) is rejected by cargo unless its Cargo.toml carries an empty [workspace] table. Surfaced repeatedly by the cycle-0006 and cycle-0007 fieldtests as a non-obvious onboarding one-liner. Document it on the consumer-facing surface (project-layout, the "A project repo" section) so a nested-project author can predict and fix it. The aura new scaffolder will emit the line once it exists (folds into the CLI work); the docs capture closes the actionable half now. closes #9
7.5 KiB
How aura is used — engine, projects, and a day in the life
This document describes the outside of aura: how you sit in front of it and
what a research session looks like. The inside (the engine's contracts) is the
design ledger (docs/design/INDEX.md).
Engine vs. project (the game-engine split)
aura is a game engine for traders, and like any game engine it is separate from the things built with it:
- This repo (
aura) is the engine:aura-core(the shared contract),aura-std(universal standard nodes),aura-engine(the deterministic sim runtime),aura-cli(theaurabinary), and later the egui playground. It ships at mostexamples/fixture nodes for its own tests — never your real signals. - A research project is its own external repo (e.g.
~/dev/ger40-lab/), with its own git history, its own Gitea repo (its own forward-queue), and a cargo dependency on aura. It is itself a Rust crate (acdyliblibrary of node / strategy / experiment blueprints); theaurahost loads and runs it during research (hot-reload), and freezes a chosen strategy + broker into a standalone binary for deploy. This is where you and Claude author signals and experiments — all in Rust — and where the runs live. (Contracts C16, C20.)
The aura CLI is a tool you run inside a project directory — it finds the
project root by walking up to an Aura.toml, the way cargo finds Cargo.toml.
A project is always a Rust program built on the engine.
A project repo
ger40-lab/ # your research project — a separate Rust crate (cdylib)
├── Aura.toml # STATIC context only: data paths, instrument/pip
│ # metadata, default broker & window, runs dir (no logic)
├── Cargo.toml # cdylib; depends on aura-core/aura-std (+ shared node crates);
│ # carries an empty [workspace] table (see note below)
├── CLAUDE.md # the project's own skills wiring (authoring discipline)
├── .claude/dev-cycle-profile.yml
├── nodes/ # project-local node & strategy blueprints (Rust)
│ └── third-candle-long/
├── experiments/ # experiment/harness definitions (Rust): matrices, sweeps
├── runs/ # the run registry: manifest + metrics per run
└── (frozen bots, …)
The empty
[workspace]table. A project crate is its own cargo workspace, never a member of the engine's. This matters the moment a project lives under the engine repo (common while authoring, before it moves to its own repo): cargo otherwise walks up, finds the engine's root manifest, and refuses to build —error: current package believes it's in a workspace when it's not: ... to keep it out of the workspace, add an empty [workspace] table ...The fix is cargo's own hint: an empty
[workspace]table in the project'sCargo.toml. It pins the crate as a standalone workspace root and costs nothing when the project later sits in its own repo. The futureaura newscaffolder will emit this line; until then, add it by hand.
Where reusable nodes live (three tiers)
Everything that plugs into the engine is fractally a Node. Reuse is plain
cargo, layered by maturity (contract C16):
aura-std— universal blocks shipped with the engine (SMA/ATR/RSI, resamplers, theSessionNode, standard combinators, broker profiles).- Shared node crates — cross-project-reusable blocks in their own repos
(e.g.
Brummel/aura-nodes-fx), pulled in as cargo git dependencies. - Project-local
nodes/— experimental, project-specific blocks.
Promotion is the ordinary Rust gradient: a node proves itself project-local →
gets extracted into a shared crate → if it turns universal, into aura-std.
Shared nodes are rlib dependencies; the hot-reload unit stays the project-side
cdylib that composes them, so editing a shared node still rebuilds and reloads
the dependent.
Authoring happens in Claude Code (contract C17)
aura has no built-in coding-LLM. You author by talking to Claude Code, which
writes the Rust — nodes, strategies, and experiments — builds it, runs it, and
reports back. Declarative config (Aura.toml) holds only static context, never
logic. IONOS LLMs appear only as a runtime data source (e.g. a news-agent node
emitting a bias), recorded before it enters a backtest, and only with your
per-session consent.
A day in the life
- You (in Claude Code, inside
ger40-lab/): "I suspect the 3rd 15m candle after GER40 open is long-biased when the first two close bullish — build it as a signal." - Claude (via the skills pipeline) writes
nodes/third-candle-long/, implementsschema+evalagainstaura-core. - Backtest:
aura backtest nodes/third-candle-long --symbol GER40 --from 2020 --to 2024→ the strategy produces a broker-independent exposure stream (one bounded signed value per cycle = intent); the default sim-optimal broker integratesexposure·returninto a synthetic pip-equity — the signal's quality — yielding a metrics table (pip-P&L, max-DD, Sharpe) + a run record (manifest + metrics) underruns/. Brokers are consumer nodes: the sim-optimal one reads the exposure stream directly, while a realistic broker reads the derived position-event table — add--broker pepperstoneto get a realistic currency curve alongside the sim-optimal pip curve, two comparable equity curves. (Contract C10.) - Sweep / Monte-Carlo / matrix — a Rust experiment. Anything beyond a
single backtest is an experiment in
experiments/(Rust, builder API): a parameter sweep, Monte-Carlo over seeds, or a structural matrix like "these 10 strategies × these 3 instruments × {sim-optimal, pepperstone}". The matrix is plain Rust loops, not a config schema (C20).aura run experiments/comparebootstraps the matrix, fans the disjoint sims over all cores (C1), and writes the comparable runs toruns/. - Compose: "combine it with
momentum-filteras a weighted sum" → Claude writes a composite node (fractal, C9). - Walk-forward: another experiment kind (rolling in-sample optimize + out-of-sample test) → an out-of-sample verdict.
- Freeze:
aura freeze nodes/strategy-y --broker pepperstone --out bots/strategy-y→ a standalone, statically-linked bot (C13). - Explore —
aura play. The playground plays any harness and shows what your sinks recorded (C22): live equity/signal streams while a run executes, and recorded traces + meta-views afterwards — stitched walk-forward equity, sweep surfaces, multi-strategy comparison. It is a trace explorer, not a scene editor (the World is a program; only sink-recorded data is visible — no sink, nothing to see). Topology you grow in Rust (hot-reload); runtime params you tune with sliders (C12).
The real value is not step 3 (one backtest — every quant system does that) but the World: steps 4/6 dynamically construct and orchestrate families of harnesses, and the playground explores those families. The single-harness engine is the substrate; the World is the product (C20–C22).
CLI command names and Aura.toml are illustrative; the concrete surface is
designed with the relevant milestone (see the open threads in the design ledger).
The forward-queue — what to try next — lives in the project's Gitea tracker, not
in code (contract C18).