commit 744c2f31a8eafb965ce3d5783a5a44554c44dd04 Author: Brummel Date: Wed Jun 3 01:31:14 2026 +0200 chore: scaffold aura workspace and wire the skills dev-cycle Cargo workspace aura-core -> aura-engine -> aura-cli (bin `aura`) plus nodes/ for hot-reloadable cdylib node crates. Crate bodies are intentionally API-free; types arrive from the first spec. Adds the skills profile (.claude/dev-cycle-profile.yml), the project CLAUDE.md with the eight domain invariants, and the design-ledger skeleton. Co-Authored-By: Claude Opus 4.8 (1M context) diff --git a/.claude/dev-cycle-profile.yml b/.claude/dev-cycle-profile.yml new file mode 100644 index 0000000..865d6c7 --- /dev/null +++ b/.claude/dev-cycle-profile.yml @@ -0,0 +1,52 @@ +# Project profile for the skills plugin (~/dev/skills). +# Schema: ~/dev/skills/docs/profile-schema.md + +paths: + spec_dir: docs/specs + plan_dir: docs/plans + design_ledger: docs/design/INDEX.md + code_roots: [crates, nodes] + +naming: + counter_dirs: [] + policy: flat + slug_separator: "-" + +commands: + build: "cargo build --workspace" + test: "cargo test --workspace" + lint: "cargo clippy --workspace --all-targets -- -D warnings" + doc_build: "cargo doc --workspace --no-deps 2>&1" + regression: [] + architect_sweeps: [] + +vocabulary: + cycle: cycle + subcycle: iteration + milestone: milestone + ledger_entry: contract + +standing_reading: + always: + - CLAUDE.md + - "git log -10 --format=full" + by_role: {} + +git: + main_sacrosanct: true + only_orchestrator_commits: true + protected_branches: [main] + issue_tracker: + kind: gitea + close_marker: "closes #N" + url: "http://192.168.178.103:3000/Brummel/aura/issues" + list_cmd: "tea issues ls --repo Brummel/aura --state open" + +notifications: {} + +pipeline: + brainstorm: { gates: [planner] } + planner: { gates: [implement] } + implement: {} + audit: { mandatory_at: cycle_close } + debug: { trigger: bug, red_first: true } diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f384ab6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/target +**/*.rs.bk +Cargo.lock.orig + +# Hot-reload build artifacts for node cdylibs live under target/; nothing else +# generated is checked in. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..736a749 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,82 @@ +# aura — project rules + +aura is a "game engine for traders": a Rust framework **and** a playground to +author trading nodes, backtest them deterministically and massively in parallel, +compose them fractally, validate them (sweep / Monte-Carlo / walk-forward), and +freeze a validated strategy into a standalone bot with a broker connection. + +This file is the project sittenkodex. It imports the universal discipline from +`~/dev/skills/templates/CLAUDE.md.fragment` and adds aura's domain invariants. +The full architecture lives in the design ledger (`docs/design/`) and the specs +(`docs/specs/`), not here. + +## Roles + +I am the **orchestrator**, not the implementer. The skills-plugin agents are my +workers: I plan, design, decide, and integrate; they implement, refactor, test, +and diagnose. Trivial mechanical edits I may do directly; anything needing broad +reading or judgement goes to an agent. Agent reports describe intent, not +outcome — I verify the diff and the test output myself before committing. + +## Commit discipline and main-branch sanctity + +- **Only the orchestrator commits.** No skill agent runs `git commit`; agents + leave their output as unstaged working-tree changes for me to inspect and shape + into commits. +- **main HEAD is sacrosanct.** No `git reset`/`git revert` on main. main moves + forward only via my commits. Wrong agent output is discarded with + `git checkout -- `/`git stash`; a bad landing is fixed forward, never + rewound. +- When a commit closes a Gitea issue, reference it in the body: `closes #N` + (or `refs #N` for non-final work). + +## Design rationale ≠ implementation effort + +Design choices are justified by substance — semantics, structural fit, what the +design permits vs forbids, compositional clarity, future-proofing. Implementation +effort ("approach A touches 250 sites, B touches 1") is an observation about the +current code, not a rationale. Effort is at most a named tiebreaker after +substantive reasons tie. + +## Bug fixes — TDD, always + +Bug fixes are RED-first and autonomous: the failing test exists in the working +tree before any fix. The `debug` skill is mandatory for any observable +misbehaviour (failing test, panic, wrong output). + +## Domain invariants (load-bearing — never silently violate) + +These are the contracts the whole design rests on. A change that breaks one is a +design decision, not a refactor, and belongs in the ledger. + +1. **Determinism.** A backtest is a deterministic, synchronous, non-concurrent + event loop that reaches a unique state after each input tick. Same input → + same run, reproducibly. Two backtests are fully disjoint → concurrently + executable without locking. Parallelism is *across* sims, never within one. +2. **Causality / no look-ahead.** A node sees only the past. Look-ahead is made + structurally impossible (read-only input windows that end at the cursor; + resamplers emit a bar only once it is complete), not merely discouraged. +3. **One merge, at ingestion only.** Heterogeneous timestamped sources are + k-way-merged into a single chronological cycle stream at the ingestion + boundary. There is no merge / as-of join inside the graph. +4. **The four scalar base types, streamed as SoA.** Only `i64`, `f64`, `bool`, + `timestamp` are streamed, as columnar Structure-of-Arrays. Composite streams + (e.g. OHLCV) are bundles of base columns. Non-scalars (String, Records, + tables, calendars) exist as metadata beside the hot path, never in it. +5. **Acyclic dataflow.** The graph is a DAG; the only feedback path is an + explicit delay/state node (the RTL "register"). The "cycle" of the research + workflow is not a dataflow cycle. +6. **Record-then-replay determinism boundary.** Anything non-deterministic, + external, or slow (LLM news agents, web sources) is materialized into a + recorded, timestamped stream *before* it enters the engine. The sim never + makes a live external call mid-replay. (See `~/.claude/CLAUDE.md` for the + IONOS consent rule: external LLM calls happen at the recording/live-source + edge, with explicit per-session consent, never inside a backtest.) +7. **The broker is part of the strategy.** The broker node is fixed in a + strategy and identical in sim and live (one accounting path → one equity + curve shape). "Same strategy, different broker" = swap the broker *profile* + it is parameterized with. Live order-routing/reconciliation is an external + adapter outside the strategy graph. +8. **Deploy artifacts are frozen.** Hot-reload (cdylib) is an authoring-loop + tool only. The live bot is a statically-linked, versioned, frozen artifact — + never hot-swapped (audit trail: this bot = this commit). diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1144ffd --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,21 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aura-cli" +version = "0.1.0" +dependencies = [ + "aura-engine", +] + +[[package]] +name = "aura-core" +version = "0.1.0" + +[[package]] +name = "aura-engine" +version = "0.1.0" +dependencies = [ + "aura-core", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a9a4806 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +# aura — a "game engine for traders": a Rust framework + playground to author +# trading nodes, backtest them deterministically and in parallel, compose them +# fractally, and freeze a validated strategy into a standalone bot. +# +# Workspace split is driven by the cdylib hot-reload boundary: `aura-core` is the +# shared contract that BOTH the engine and every hot-reloadable signal/node +# cdylib link against. Add crates only when a boundary proves real. + +[workspace] +resolver = "3" +members = [ + "crates/aura-core", + "crates/aura-engine", + "crates/aura-cli", +] + +[workspace.package] +edition = "2024" +version = "0.1.0" +license = "proprietary" +publish = false diff --git a/crates/aura-cli/Cargo.toml b/crates/aura-cli/Cargo.toml new file mode 100644 index 0000000..344574b --- /dev/null +++ b/crates/aura-cli/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "aura-cli" +edition.workspace = true +version.workspace = true +license.workspace = true +publish.workspace = true + +[[bin]] +name = "aura" +path = "src/main.rs" + +[dependencies] +aura-engine = { path = "../aura-engine" } diff --git a/crates/aura-cli/src/main.rs b/crates/aura-cli/src/main.rs new file mode 100644 index 0000000..f834da7 --- /dev/null +++ b/crates/aura-cli/src/main.rs @@ -0,0 +1,8 @@ +//! `aura` — the programmatic / CLI face of the engine (the surface the LLM and +//! automation drive: author a node, run a sim/sweep, emit structured metrics). +//! +//! Skeleton only: real subcommands arrive with the walking-skeleton milestone. + +fn main() { + println!("aura: walking-skeleton scaffold — no subcommands yet."); +} diff --git a/crates/aura-core/Cargo.toml b/crates/aura-core/Cargo.toml new file mode 100644 index 0000000..268bb91 --- /dev/null +++ b/crates/aura-core/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "aura-core" +edition.workspace = true +version.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] diff --git a/crates/aura-core/src/lib.rs b/crates/aura-core/src/lib.rs new file mode 100644 index 0000000..21de293 --- /dev/null +++ b/crates/aura-core/src/lib.rs @@ -0,0 +1,17 @@ +//! `aura-core` — the shared contract every aura component links against. +//! +//! This crate is the boundary forced by the cdylib hot-reload model: both the +//! engine and every hot-reloadable node cdylib depend on it, so it must stay +//! small and stable. It is the home of (to be specified): +//! +//! - the scalar base types streamed as SoA: `i64`, `f64`, `bool`, `timestamp`; +//! - the `Node` trait — the contract an authored node implements (`schema` + +//! `eval`), with engine-provided read-only input windows and node-internal +//! series; +//! - the evaluation context `Ctx` (zero-copy indexed access into input columns, +//! fresh-mask, current-cycle timestamp); +//! - the firing-policy declarations (A: fire-on-any-fresh + hold; B: all-fresh +//! barrier), declarable per input group. +//! +//! Types are intentionally absent until the first spec lands under +//! `docs/specs/`. This crate documents intent; it does not yet define API. diff --git a/crates/aura-engine/Cargo.toml b/crates/aura-engine/Cargo.toml new file mode 100644 index 0000000..d000bfc --- /dev/null +++ b/crates/aura-engine/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "aura-engine" +edition.workspace = true +version.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] +aura-core = { path = "../aura-core" } +# data-server (the first data source) enters when the ingestion task starts; +# kept out of the bare skeleton so the workspace compiles without the network. diff --git a/crates/aura-engine/src/lib.rs b/crates/aura-engine/src/lib.rs new file mode 100644 index 0000000..a6da1c0 --- /dev/null +++ b/crates/aura-engine/src/lib.rs @@ -0,0 +1,10 @@ +//! `aura-engine` — the headless, UI-agnostic reactive SoA engine. +//! +//! Home of (to be specified): the ingestion boundary (k-way merge of timestamped +//! sources into one chronological cycle stream), the deterministic synchronous +//! single-threaded sim loop (one unique state per input tick), freshness-gated +//! recompute, the broker/portfolio node mechanics, and the atomic sim unit +//! `(topology + params + data-window + seed) -> metrics` that the sweep / +//! optimize / walk-forward / Monte-Carlo axes orchestrate. +//! +//! Visualization is never here: it is a downstream consumer node on the streams. diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md new file mode 100644 index 0000000..3f1237e --- /dev/null +++ b/docs/design/INDEX.md @@ -0,0 +1,21 @@ +# aura design ledger — INDEX + +The ledger records the load-bearing design contracts and their rationale. Each +entry is one contract: what it guarantees, what it forbids, and why. + +This is the place where the architecture settled during the initial rough-sketch +interview will be written up as discrete contracts. Until those entries land, the +authoritative summary of the invariants is the **Domain invariants** section of +`CLAUDE.md`, and the cross-session rationale notes live in the project memory. + +## Contracts + +_(none yet — to be authored from the first spec onward)_ + +## Open architectural threads not yet resolved + +- Visual playground form (leaning egui-native; deferred — the headless core + makes deferring it free). +- Smarter parameter-space search strategies (Bayesian/genetic) as pluggable + policies atop the atomic sim unit. +- Top-level `strategies/` split from reusable building blocks in `nodes/`. diff --git a/docs/plans/.gitkeep b/docs/plans/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/specs/.gitkeep b/docs/specs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/nodes/README.md b/nodes/README.md new file mode 100644 index 0000000..dba8bad --- /dev/null +++ b/nodes/README.md @@ -0,0 +1,15 @@ +# `nodes/` + +Hot-reloadable, LLM-authored node crates (`cdylib`). Everything that plugs into +the engine is fractally a `Node`: indicators, signals, sources (e.g. news-agent +nodes that emit a recorded/live bias stream), decision nodes, broker profiles, +session nodes, resamplers, and sinks/visualizers. A composite — and ultimately a +whole strategy — is also just a `Node` that wires a sub-graph and exposes one +output. + +Each crate here links only against `aura-core` (the shared contract) and is +built with the same toolchain as the engine (Rust-ABI hot-reload). For the +deploy bot, the wired graph is frozen and statically linked — never hot-swapped. + +A later split may separate top-level `strategies/` from reusable building blocks; +for now this is the single bucket.