r2x 0.1.11

A framework plugin manager for the r2x power systems modeling ecosystem.
docs.rs failed to build r2x-0.1.11
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: r2x-0.1.10

CI Release Documentation License


The r2x CLI is the orchestrator for the r2x ecosystem. It discovers installed Python plugins, chains them into pipelines, and manages Python environments, all from a single Rust binary.

Plugins handle every step of a power systems translation workflow: parsing source models, applying transforms, translating between formats, and exporting to targets like PLEXOS or Sienna. The CLI finds them via static analysis (no Python import side effects), resolves their dependencies, and pipes each step's output into the next.

Installation

Download the latest binary from the releases page, or use the one-liner installers below.

macOS / Linux

curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/NatLabRockies/r2x-cli/releases/latest/download/r2x-installer.sh | sh

Windows

powershell -ExecutionPolicy Bypass -c "irm https://github.com/NatLabRockies/r2x-cli/releases/latest/download/r2x-installer.ps1 | iex"

Verify it works:

r2x --version

[!NOTE] On first run, R2X uses UV to provision its managed CPython runtime and creates the R2X virtual environment. It does not require python3.12 in PATH or ~/.local/bin. UV owns the CPython installation; R2X owns only the plugin virtual environment, which references that interpreter. Use uv python list to inspect UV's available interpreters. Source builds select a supported version with PYO3_PYTHON from uv python find --managed-python and R2X_PYTHON_VERSION.

Upgrading

If you installed via the shell/powershell installer, a standalone updater is included:

r2x-update

Alternatively, re-run the installer to get the latest version:

# macOS / Linux
curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/NatLabRockies/r2x-cli/releases/latest/download/r2x-installer.sh | sh

Quick Start

# 1. Scaffold a pipeline config
r2x init

# 2. Install a plugin from PyPI
r2x install r2x-reeds

# 3. See what got installed
r2x list

# 4. Run a pipeline
r2x run pipeline.yaml reeds-test

r2x init creates a pipeline.yaml with example variables, pipeline definitions, and per-plugin configuration. Edit it to match your data and you are running translations in under a minute.

Plugin Management

Command What it does
r2x install <package> Install from PyPI
r2x install gh:NatLabRockies/r2x-reeds Install from a GitHub repo
r2x install gh:NatLabRockies/r2x-reeds --branch dev Install a specific branch (--tag, --commit)
r2x install -e /path/to/plugin Install in editable mode for local dev
r2x remove <package> Uninstall a plugin
r2x list List all installed plugins
r2x list r2x-reeds Filter by package name
r2x list r2x-reeds break-gens Filter by package and module
r2x sync Re-run plugin discovery and refresh manifest metadata
r2x sync --upgrade Upgrade compatible installed plugins, then sync and show version/commit changes
r2x clean -y Wipe the plugin manifest and clean cache

[!TIP] Plugin discovery uses static analysis (ast-grep) instead of importing Python modules. This makes r2x sync and r2x install fast and safe, with no side effects from plugin code.

Running Pipelines

Pipelines chain plugins together in a named sequence defined in a YAML file. See Pipeline File Format for the full spec. For ready-to-use translation examples across ReEDS, Sienna, and PLEXOS, see:

# List available pipelines
r2x run pipeline.yaml --list

# Dry run (preview without executing)
r2x run pipeline.yaml my-pipeline --dry-run

# Execute
r2x run pipeline.yaml my-pipeline

# Execute and save output
r2x run pipeline.yaml my-pipeline -o output.json

# Save a System and its time-series sidecars as an infrasys ZIP archive
r2x run pipeline.yaml my-pipeline --output output.zip --zip

Running Plugins Directly

Skip the pipeline and run a single plugin with inline arguments. The short form is r2x run <plugin-ref>; r2x run plugin <plugin-ref> remains supported.

# Run a plugin directly with idiomatic flags
r2x run r2x-reeds.reeds-parser \
  --path /path/to/reeds/run \
  --solve-year 2030 \
  --weather-year 2012

# Existing key=value arguments also work
r2x run r2x-reeds.reeds-parser \
  path=/path/to/reeds/run \
  solve_year=2030 \
  weather_year=2012

# Pipe a System through compatible plugins in one shell job
set -o pipefail
r2x run r2x-reeds.reeds-parser \
  --path /path/to/reeds/run \
  --solve-year 2030 \
  --weather-year 2012 |
r2x run r2x-reeds.add-pcm-defaults \
  --pcm-defaults-fpath config/pcm_defaults.json

# Write a durable System JSON entrypoint and its adjacent sidecar directory
r2x run r2x-reeds.reeds-parser \
  --path /path/to/reeds/run \
  --solve-year 2030 \
  --weather-year 2012 \
  -o artifacts/system.json

# Read the durable System by path; relative sidecars resolve beside the JSON file
r2x run r2x-reeds.add-pcm-defaults \
  -i artifacts/system.json \
  --pcm-defaults-fpath config/pcm_defaults.json

# Debug an uncaught plugin exception in an interactive post-mortem PDB session
# Use --input FILE for a durable input so stdin remains available to PDB
r2x run plugin <plugin-name> --pdb --input input.json

# Debug the failing step in a pipeline
r2x run pipeline.yaml my-pipeline --pdb

# Show a plugin's help
r2x run plugin r2x-reeds.reeds-parser --show-help

# Run repeated invocations and print timing summary
r2x run r2x-reeds.reeds-parser --repeat 10 --benchmark solve_year=2030

# Compare two benchmark outputs (baseline vs current)
uv run --no-config --no-project --managed-python --python 3.12 -- \
  python scripts/compare_benchmark_summary.py --baseline baseline.txt --current current.txt

# Emit machine-readable status line in stderr
uv run --no-config --no-project --managed-python --python 3.12 -- \
  python scripts/compare_benchmark_summary.py \
  --baseline baseline.txt \
  --current current.txt \
  --print-status-line

# Fail when regression exceeds 15%
uv run --no-config --no-project --managed-python --python 3.12 -- \
  python scripts/compare_benchmark_summary.py \
  --baseline baseline.txt \
  --current current.txt \
  --fail-on-regression-pct 15

# In CI, set optional regression gate
export R2X_BENCHMARK_REGRESSION_PCT=15

# List all runnable plugins
r2x run plugin

Use --pdb only from an interactive terminal. It opens Python's post-mortem pdb for uncaught plugin exceptions, including failures in a pipeline, and returns the original plugin error after continue or quit. Debugger prompts are written to stderr. Noninteractive or piped invocations fail immediately; when debugging interactively, prefer --input FILE so stdin remains available for PDB commands.

Without -o, System JSON on stdout embeds an absolute r2x sidecar location, so it is safe to pass to the next command in the same shell job. With -o, r2x creates parent directories, replaces the JSON entrypoint, and writes a portable sibling <stem>_time_series/ directory; read that artifact with -i, not shell redirection. Plugin diagnostics use stderr, and exporters write their configured files without emitting a JSON record.

For Torc parameterization, file dependencies, and the distinction between live pipes and durable -o / -i boundaries, see Use r2x plugin streams in Torc.

Pipeline File Format

Pipeline configs are YAML with three sections: variables for substitution values, pipelines for named plugin sequences, and config for per-plugin settings.

variables:
  output_dir: "output"
  reeds_run: /path/to/reeds/run
  solve_year: 2032

pipelines:
  reeds-test:
    - r2x-reeds.reeds-parser
    - r2x-reeds.break-gens

  reeds-to-plexos:
    - r2x-reeds.reeds-parser
    - r2x-reeds-to-plexos.reeds-to-plexos
    - r2x-plexos.plexos-exporter

config:
  r2x-reeds.reeds-parser:
    weather_year: 2012
    solve_year: ${solve_year}
    path: ${reeds_run}

  r2x-reeds.break-gens:
    drop_capacity_threshold: 5

  r2x-plexos.exporter:
    output: ${output_dir}

output_folder: ${output_dir}

Variables use ${var} syntax and are substituted at runtime across all config values and output_folder.

Interactive System Shell

Load a system JSON and drop into an IPython session for exploration:

r2x read system.json

# Load an infrasys ZIP archive
r2x read system.zip --zip

The session exposes sys (the loaded system), plugins (installed plugins), and lazy-loaded pd, np, plt for pandas, numpy, and matplotlib. Type %r2x_help for the full list of magic commands.

# From stdin
cat system.json | r2x read

# Run a script against the system
r2x read system.json --exec script.py

# Run a script then stay interactive
r2x read system.json --exec script.py -i

Configuration

# Show current config
r2x config show

# Set values
r2x config set cache-path /path/to/cache

# Reset everything
r2x config reset -y

R2X uses the Python major.minor ABI that its PyO3 runtime was built against. Use uv python list and uv python install to inspect or manage interpreter installations directly. A configured Python patch version must use that same major.minor ABI.

The r2x python command manages R2X's UV-backed plugin environment:

# Create or refresh the managed venv with UV
r2x python install

# Show the R2X venv's Python configuration
r2x python show

# Get the Python executable path
r2x python path

# Create or recreate the managed venv
r2x config venv create -y

# Install packages into the managed venv
uv pip install <package> --python $(r2x python path)

[!TIP] The r2x python commands are shortcuts for r2x config python <action>. Both work identically.

r2x config cache clean
# Show current logging settings
r2x log show

# Keep Python/plugin stdout out of the log file by default
r2x log set no-stdout true

# Cap log file size (bytes)
r2x log set max-size 26214400

# Show Python log messages on console by default
r2x log set log-python true

# Override log file location
r2x log path /tmp/r2x.log

# Print the resolved log file path
r2x log path

# Command help
r2x log --help
r2x log set --help

[!NOTE] Configuration is stored in ~/.config/r2x/config.toml on Unix-like systems or %APPDATA%\r2x\config.toml on Windows. Override with the R2X_CONFIG environment variable.

Verbosity

Flag Effect
-q Suppress informational logs
-qq Suppress logs and plugin stdout
-v Debug logging
-vv Trace logging
--log-python Show Python logs on console
--no-stdout Do not capture plugin stdout in logs

Persisted logging defaults can be set with r2x log set ....

Plugin installation and r2x sync --upgrade print an immediate phase status to stderr and stream uv diagnostics there. uv's progress display is enabled only for an interactive terminal; pipes, CI, NO_COLOR, and TERM=dumb receive plain, line-oriented status instead. Use -q or -qq to suppress status and uv informational output, and -v or -vv to pass diagnostic verbosity through to uv. stdin is inherited, so private Git and SSH installs can still prompt for credentials.

Architecture

flowchart LR
    CLI[r2x CLI] --> Config[r2x-config]
    CLI --> Manifest[r2x-manifest]
    CLI --> AST[r2x-ast]
    CLI --> Python[r2x-python]
    CLI --> Logger[r2x-logger]
    AST -->|ast-grep| Discovery[Plugin Discovery]
    Python -->|PyO3| Runtime[Python Runtime]
    Manifest --> Plugins[(Plugin Registry)]

The workspace is split into six crates:

Crate Role
r2x-cli CLI entry point, command routing, pipeline execution
r2x-config Configuration management, paths, Python/venv settings
r2x-manifest Plugin manifest read/write, package metadata
r2x-ast AST-based plugin discovery via ast-grep
r2x-python PyO3 bridge for running Python plugins
r2x-logger Structured logging with tracing

Ecosystem

The r2x ecosystem is a set of independently published packages. The CLI orchestrates them; r2x-core provides the shared plugin framework; model packages supply parsers, exporters, and data models; and translation packages convert between formats.

Package Description
r2x-cli (this repo) Rust CLI that discovers, installs, and runs any r2x plugin. Chains plugins into pipelines and manages Python environments
r2x-core Shared plugin framework: PluginContext, Rule, System, @getter registry
R2X Translation plugins: ReEDS to PLEXOS, Sienna to PLEXOS, and more
r2x-reeds ReEDS parser, transform plugins, and component models
r2x-plexos PLEXOS parser/exporter and component models
r2x-sienna Sienna parser/exporter and PowerSystems.jl-compatible models
infrasys Foundational System container, time series management, and component storage
plexosdb Standalone PLEXOS XML database reader/writer

Building from Source

Prerequisites

  • Rust toolchain (rustup)
  • uv package manager
  • Python 3.11 or newer
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install 3.12

[!IMPORTANT] Restart your shell after installing rustup and uv so both are available in your PATH.

Build and install

git clone https://github.com/NatLabRockies/r2x-cli && cd r2x-cli
PYO3_PYTHON="$(uv python find --managed-python 3.12)" \
  R2X_PYTHON_VERSION=3.12 cargo install --path crates/r2x-cli --bins --force --locked

To build against another supported Python version:

uv python install 3.13
PYO3_PYTHON="$(uv python find --managed-python 3.13)" \
  R2X_PYTHON_VERSION=3.13 cargo install --path crates/r2x-cli --bins --force --locked

Set PYO3_PYTHON from uv python find --managed-python so PyO3 builds against the UV-managed interpreter. R2X passes the requested version directly to UV. Install that exact version first with uv python install <version>.

This places r2x and its adjacent r2x-runtime payload in ~/.cargo/bin/. Run r2x; keep both files together when moving the installation.

r2x --version
PYO3_PYTHON="$(uv python find --managed-python 3.12)" \
  R2X_PYTHON_VERSION=3.12 cargo build --release -p r2x --bins

The build produces target/release/r2x and target/release/r2x-runtime. Copy them to the same directory, then invoke r2x.

The justfile also honors R2X_PYTHON_VERSION, for example R2X_PYTHON_VERSION=3.13 just test.

R2X_PYTHON_VERSION selects the Python ABI for a source build. The installed CLI accepts only the same major.minor ABI for r2x config set python-version; a patch version such as 3.12.1 is allowed for a binary built against 3.12.

When R2X_PYTHON_VERSION is set for a just task, install that version first with uv python install <version>. This avoids accidentally building PyO3 against a different Python ABI than the one requested. If you also set PYO3_PYTHON manually, it must point to an interpreter with the same major.minor ABI as R2X_PYTHON_VERSION.

The project uses a justfile for common tasks:

just build     # fmt + clippy + build
just test      # cargo test --workspace --all-features
just lint      # fmt + clippy
just all       # fmt + clippy + test
  • If the build fails with a Python error, verify R2X_PYTHON_VERSION is set to a supported version (for example 3.12, 3.13, or 3.13.1) and uv python find --managed-python <version> returns a valid path. You may need uv python install <version> first.
  • If r2x is not found after install, check that ~/.cargo/bin is in your $PATH.
  • On HPC systems with older glibc, building from source is usually required since pre-built binaries target glibc 2.28+.

License

BSD-3-Clause. See LICENSE.txt for the full text.

Copyright (c) 2025, Alliance for Sustainable Energy LLC.