Architecture
rx is a single Rust binary (MSRV 1.85.0) organized into focused modules. This page describes the high-level design.
Module layout
rx
├── cli/ CLI definition (clap derive), lazy config loading, profiles
├── config/ rx.toml parsing, global/project merge, profile resolution, validation
├── build/ cargo build orchestration, fast linker, cross-compilation
├── cache/ Opt-in content-addressed artifact store (xxHash, atomic writes, reflink)
├── cargo_output/ Cargo JSON output parser with error hints
├── workspace/ Dependency graph via cargo metadata, topological sort (Kahn's)
├── affected/ Git-diff-based affected package detection
├── ci/ + ci_gen/ Local CI pipeline and CI workflow generation
├── task/ task graph + runner: [tasks], depends-on, wave concurrency
├── completions/ Shell completions with context-aware dynamic values
├── output/ Colored output, timing, verbosity
├── stats/ Build time tracking and statistics
├── hints/ Error code hints surfaced next to cargo output
├── migrate/ Auto-detection of existing project settings
├── doctor/ Development environment checks
└── install.sh Self-installer script
How a command runs
- CLI parsing –
clapparses arguments and flags. The--profileflag is captured as a global option. - Config loading (lazy) – if the command needs configuration, rx loads
~/.rx/config.tomland./rx.toml, merges them (project overrides global), and applies the active profile. - Environment setup – environment variables from
[env]are set. The cached env at~/.rx/env.lockprovides linker paths and toolchain info. - Command execution – pipelines (
rx run,rx ci) resolve a task graph and execute it wave by wave; each task is a shell command or a built-in module (fmt/lint/test/build/check) that calls cargo as a subprocess. Output is parsed from cargo’s JSON stream for error hints and progress display. - Cache update – if the opt-in artifact cache is enabled, the fingerprint and artifacts are stored in
~/.rx/cache.
Config resolution
Configuration is resolved in layers:
defaults < ~/.rx/config.toml < ./rx.toml < [profile.<name>] < CLI flags
Each layer overrides the previous. Unknown keys produce warnings.
Cache design
The global cache at ~/.rx/cache is content-addressed:
~/.rx/cache/
├── index.json # fingerprint -> artifact metadata
├── mtime-snapshot.json # per-file modification times
├── lock # file lock for concurrent access
└── artifacts/
└── <fingerprint>/ # one directory per unique build
├── deps/
├── build/
└── ...
Correctness guarantees:
- Atomic writes – the index and mtime snapshots are written to a temp file and atomically renamed
- File locking – a lock file prevents concurrent rx processes from corrupting the index
- Staging directory – new artifacts are written to a staging directory, then renamed into place
- Parallel I/O – rayon is used for parallel file copies during store/restore
Workspace execution model
rx reads the workspace graph from cargo metadata. Cargo commands run as a single invocation (--workspace, or repeated -p selections for --affected) — Cargo schedules independent crates in parallel itself. rx’s own wave concurrency applies at the task level ([tasks] with depends-on), not inside Cargo’s compilation graph. ws exec uses a topological sort (Kahn’s algorithm) to visit member directories in dependency order.
For --affected, changed files are mapped to members, expanded to transitive dependents, and resolved once into a -p selection.
Error handling
rx wraps all errors with context using anyhow. Every user-facing error includes:
- A clear description of what went wrong
- The underlying cause (if available)
- A hint on how to fix it (common error codes get one-line practical hints next to cargo output)