Add declarative planning, private same-crate helpers, AST transforms, atomic staging, locked Cargo checks, compilation fixtures, snapshots and Linux CI. Verify an isolated pinned horizon-core prototype and record build measurements.
horizon-mixins
A working stable-Rust CLI for deterministic, build-time source mixins for Horizon. The MVP implements declarative TOML mods, HEAD, BEFORE_CALL, OVERWRITE, JSON planning, atomic Linux staging, and compilation-tested fixtures. Native mods run with your user privileges.
Pristine Cargo workspace + independent mod bundles
→ index source → validate combined plan → transform AST
→ separate staged workspace → cargo test --locked --offline
The three workspace crates are horizon-mixins-core (manifests, indexing,
planning, diagnostics), horizon-mixins-transform (AST rewriting), and
horizon-mixins-cli (the horizon-mixins binary). Rust 1.95.0 and Cargo.lock
are pinned. Cargo metadata and builds use offline, locked dependency resolution.
Run cargo fetch --locked once to populate the tool's dependencies.
Build and run the complete two-mod fixture:
cargo build --locked -p horizon-mixins-cli
./target/debug/horizon-mixins plan \
--workspace fixtures/game --mods fixtures/mods --out target/plan.json
./target/debug/horizon-mixins apply \
--workspace fixtures/game --mods fixtures/mods --out target/modded-game
./target/debug/horizon-mixins check \
--workspace fixtures/game --mods fixtures/mods --out target/modded-game \
--trust-native-mods
plan writes the full validated plan to --out. apply and check rebuild
that plan from pristine source, then stage all input files. They never patch
the original checkout. check executes the staged workspace's tests; it
requires explicit native-code trust. Successful commands print JSON to stdout;
failures print a structured diagnostic to stderr and exit nonzero. JSON plans
are review artifacts; the CLI does not execute saved plans.
check --package NAME limits Cargo to a package; --target-dir PATH selects
a reusable, locked target directory. The default target directory is a stable
sibling of the stage. Outputs, mods and originals must be separate. Existing
output directories need the generated stage marker. Unchanged files keep their
bytes and mtimes, including across publication of changed stages.
A bundle contains horizon-mixin.toml and helper .rs files. For example:
[mod]
id = "movement"
version = "0.1.0"
priority = 100
[[injection]]
id = "head"
target = "fixture_game::entity::advance"
kind = "HEAD"
helper = "head.rs"
bindings = [{ name = "entity", ty = "&mut Entity", value = "&mut *entity" }]
// head.rs: compiled as a local function inside the target function.
fn head(entity: &mut Entity) {
entity.velocity += 3; // Private fields in the target module are accessible.
}
Helpers use explicit typed parameter bindings. They are compiled in the game crate and introduce no game→mod→game Cargo cycle. All selectors resolve on the original AST; same-site hooks run by priority descending, mod ID ascending, then injection ID ascending. An OVERWRITE conflicts with every other hook on its function.
BEFORE_CALL requires an exact syntax selector, explicit total require, and
zero-based ordinal. It supports a complete expression statement, plain let
initializer, or block/function tail. Calls nested in larger expressions are
rejected because wrapping them can change temporary drop timing. Macro sites,
unresolved cfg, async/closures/?, generic/unsafe/const targets, and ambiguous
source identities are rejected. Rust checks privacy, types and borrowing in
check; successful planning alone does not guarantee compilation.
Validate the implementation:
python3 tools/feasibility.py
cargo fmt --all --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo test --workspace --locked
python3 tools/benchmark.py # fresh target/benchmark; use --out for another run
The integration suite includes generated source/plan snapshots, positive and negative compilation, deterministic ordering, immutable originals, stale-source rejection, concurrent checks, and unchanged mtimes. Linux CI runs the same checks.
An isolated test against the complete horizon-core crate from commit
028f60881678a9a0e3e198f693a82858fa475c76 passed, including two independent
HEAD hooks in jmath::atan. Reproduce it using your local clone:
python3 tools/horizon_prototype.py --horizon /home/levzzz/Documents/horizon
It exports committed crate sources into a fresh target/horizon-prototype,
uses an isolated workspace manifest/lockfile, runs upstream tests and generated
probes, and records timings. It does not build the full game or launcher.
No upstream checkout is edited; no Minecraft assets or prepared resources are used.
Further documentation: API, transformations, architecture, staging and cache, security, roadmap, feasibility and measurements. Advanced injection kinds, launcher integration, semantic resolution, and a complete executable cache remain future work. License: MIT.