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) <noreply@anthropic.com>
This commit is contained in:
2026-06-03 01:31:14 +02:00
commit 744c2f31a8
15 changed files with 285 additions and 0 deletions
+52
View File
@@ -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 }
+6
View File
@@ -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.
+82
View File
@@ -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 -- <paths>`/`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).
Generated
+21
View File
@@ -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",
]
+21
View File
@@ -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
+13
View File
@@ -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" }
+8
View File
@@ -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.");
}
+8
View File
@@ -0,0 +1,8 @@
[package]
name = "aura-core"
edition.workspace = true
version.workspace = true
license.workspace = true
publish.workspace = true
[dependencies]
+17
View File
@@ -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.
+11
View File
@@ -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.
+10
View File
@@ -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.
+21
View File
@@ -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/`.
View File
View File
+15
View File
@@ -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.