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:
@@ -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 }
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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" }
|
||||
@@ -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.");
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "aura-core"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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/`.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user