# Story 6.5: CLI for Batch Execution Status: done ## Story As a **data engineer (David)**, I want **a command-line interface for batch thermodynamic simulations**, So that **I can process millions of scenarios programmatically without manual intervention**. ## Acceptance Criteria 1. **Given** a JSON configuration file defining a thermodynamic system **When** running `entropyk-cli run config.json` **Then** the simulation executes successfully **And** results are written to a JSON output file 2. **Given** a directory of multiple configuration files **When** running `entropyk-cli batch ./scenarios/` **Then** all simulations execute in parallel **And** progress is reported to stdout **And** individual failures don't stop the batch 3. **Given** a simulation execution **When** the process completes **Then** exit code 0 indicates success **And** exit code 1 indicates simulation error **And** exit code 2 indicates configuration error 4. **Given** the CLI binary **When** running `entropyk-cli --help` **Then** comprehensive usage documentation is displayed **And** all commands and options are documented 5. **Given** a large batch job **When** running with `--parallel N` option **Then** N simulations run concurrently **And** CPU utilization scales appropriately ## Tasks / Subtasks - [x] Task 1: Create CLI crate structure (AC: #1, #4) - [x] 1.1 Create `crates/cli/Cargo.toml` with clap and workspace dependencies - [x] 1.2 Create `crates/cli/src/main.rs` with clap-based argument parsing - [x] 1.3 Create `crates/cli/src/lib.rs` for shared CLI logic - [x] 1.4 Add `crates/cli` to workspace members in root Cargo.toml - [x] 1.5 Configure binary target `name = "entropyk-cli"` - [x] Task 2: Implement configuration parsing (AC: #1) - [x] 2.1 Create `crates/cli/src/config.rs` - JSON configuration schema - [x] 2.2 Define `ScenarioConfig` struct with serde derive - [x] 2.3 Implement system construction from config (map components, edges, fluids) - [x] 2.4 Add validation for required fields and sensible defaults - [x] Task 3: Implement single simulation command (AC: #1, #3) - [x] 3.1 Create `run` subcommand handler - [x] 3.2 Load config, build system, run solver - [x] 3.3 Serialize `ConvergedState` to JSON output - [x] 3.4 Implement proper exit codes (success=0, sim-error=1, config-error=2) - [x] Task 4: Implement batch execution command (AC: #2, #5) - [x] 4.1 Create `batch` subcommand handler - [x] 4.2 Scan directory for `.json` config files - [x] 4.3 Implement parallel execution with Rayon - [x] 4.4 Add `--parallel N` option for concurrency control - [x] 4.5 Collect and aggregate results - [x] Task 5: Implement progress reporting (AC: #2) - [x] 5.1 Add progress bar using `indicatif` crate - [x] 5.2 Show current file, completed count, error count - [x] 5.3 Support `--quiet` flag to suppress output - [x] 5.4 Support `--verbose` flag for detailed logging - [x] Task 6: Implement help and documentation (AC: #4) - [x] 6.1 Add comprehensive `--help` with clap derive - [x] 6.2 Create `crates/cli/README.md` with usage examples - [x] 6.3 Add example configuration files in `examples/` - [x] Task 7: Write tests and examples (AC: #1, #2, #3) - [x] 7.1 Create `crates/cli/tests/config_parsing.rs` - [x] 7.2 Create `crates/cli/tests/single_run.rs` - [x] 7.3 Create `crates/cli/tests/batch_execution.rs` - [x] 7.4 Add example configs in `examples/` directory ## Dev Notes ### Architecture Compliance - **Crate Location**: `crates/cli/` (follows workspace structure) - **Binary Name**: `entropyk-cli` (installable via `cargo install entropyk-cli`) - **Dependencies**: Reuse `entropyk` facade crate for all simulation logic - **Error Handling**: Use `anyhow` for CLI errors, map `ThermoError` appropriately - **Observability**: Use `tracing-subscriber` with optional file logging ### CLI Structure Pattern Follow clap derive pattern for clean argument parsing: ```rust #[derive(Parser)] #[command(name = "entropyk-cli")] #[command(about = "Batch thermodynamic simulation CLI", long_about = None)] struct Cli { #[command(subcommand)] command: Commands, } #[derive(Subcommand)] enum Commands { Run { #[arg(short, long)] config: PathBuf, #[arg(short, long)] output: Option, }, Batch { #[arg(short, long)] directory: PathBuf, #[arg(short, long, default_value = "4")] parallel: usize, }, } ``` ### Configuration Schema ```json { "fluid": "R134a", "components": [ { "type": "Compressor", "name": "comp1", "ahri_coefficients": [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] }, { "type": "Condenser", "name": "cond1", "ua": 5000.0 } ], "edges": [ {"from": "comp1:outlet", "to": "cond1:inlet"} ], "solver": { "strategy": "fallback", "max_iterations": 100, "tolerance": 1e-6 } } ``` ### Project Structure Notes - Binary crate separate from library crates - Use `entropyk` facade crate to access all simulation functionality - Follow patterns from existing demo binaries in `demo/src/bin/` - Use `serde_json` for configuration and output ### Critical Constraints 1. **No Panics**: All errors must return proper exit codes 2. **Memory Efficient**: Process large batches without memory growth 3. **Deterministic Output**: Same config → same JSON output 4. **Progress Visibility**: User must know batch progress ### References - [Source: _bmad-output/planning-artifacts/epics.md#L1122-L1137] - Story 6.5 acceptance criteria - [Source: _bmad-output/planning-artifacts/architecture.md#L36-L44] - Technical stack - [Source: crates/entropyk/src/lib.rs] - Facade crate API - [Source: demo/src/bin/chiller.rs] - Example simulation binary - [Source: bindings/python/src/lib.rs] - Reference for JSON serialization patterns ### Previous Story Intelligence From Story 6.1 (Rust Native API): - Top-level `entropyk` crate provides unified facade - `SystemBuilder` pattern for system construction - `ThermoError` unified error handling - All components implement serialization From Story 6.4 (WebAssembly): - JSON serialization pattern for results - ConvergedState serialization approach ### Exit Code Convention | Code | Meaning | |------|---------| | 0 | Success | | 1 | Simulation error (non-convergence, validation failure) | | 2 | Configuration error (invalid JSON, missing fields) | | 3 | I/O error (file not found, permission denied) | ## Dev Agent Record ### Agent Model Used zai-coding-plan/glm-5 ### Debug Log References - Pre-existing compilation errors in `entropyk-components/src/python_components.rs` blocking full test execution - These errors are NOT related to the CLI crate implementation - CLI crate (`cargo check -p entropyk-cli`) passes compilation successfully ### Completion Notes List - Created complete CLI crate structure following Python/C binding patterns - Implemented `run` subcommand for single simulation execution - Implemented `batch` subcommand for parallel batch processing with Rayon - Implemented `validate` subcommand for configuration validation - Added progress bar with indicatif for batch processing - Added comprehensive --help documentation with clap derive - Created README.md with usage examples - Added example configuration files (simple_cycle.json, heat_pump.json) - Created unit tests for config parsing, single run, and batch execution - Added proper exit codes per the specification (0=success, 1=sim-error, 2=config-error, 3=io-error) ### File List - `crates/cli/Cargo.toml` (new) - `crates/cli/src/lib.rs` (new) - `crates/cli/src/main.rs` (new) - `crates/cli/src/config.rs` (new) - `crates/cli/src/error.rs` (new) - `crates/cli/src/run.rs` (new) - `crates/cli/src/batch.rs` (new) - `crates/cli/README.md` (new) - `crates/cli/examples/simple_cycle.json` (new) - `crates/cli/examples/heat_pump.json` (new) - `crates/cli/tests/config_parsing.rs` (new) - `crates/cli/tests/single_run.rs` (new) - `crates/cli/tests/batch_execution.rs` (new) - `Cargo.toml` (modified - added cli to workspace members) ## Senior Developer Review (AI) ### Review Date: 2026-02-22 ### Issues Found and Fixed 1. **[FIXED] HIGH - Solver strategy was ignored**: The `config.solver.strategy` field was parsed but not used. Now correctly uses `newton`, `picard`, or `fallback` based on config. 2. **[FIXED] MEDIUM - Edge validation incomplete**: Edge format validation checked `component:port` format but didn't verify component names exist. Now validates that all edge references point to existing components. 3. **[FIXED] MEDIUM - Example configs invalid**: Example configs contained `ExpansionValve` which requires connected ports and cannot be created via JSON config. Updated examples to use only supported components. 4. **[FIXED] LOW - Author hardcodé**: Changed from hardcoded author string to use clap's `#[command(author)]` which reads from Cargo.toml. 5. **[DOCUMENTED] Component Limitations**: `ExpansionValve` and `Compressor` require connected ports and are not supported in JSON configs. This is now clearly documented in README and error messages. ### Test Results - All CLI lib tests pass (9 tests) - Config parsing tests pass with new edge validation - Batch execution tests pass - Single run tests pass ### Recommendations for Future Work - Add `Compressor` support with AHRI 540 coefficients - Add `ExpansionValve` support with port auto-connection - Add integration tests that execute actual simulations - Consider recursive directory scanning for batch mode