Skip to content
This repository was archived by the owner on Mar 10, 2026. It is now read-only.

Commit d80a73e

Browse files
committed
docs(cli): Add comprehensive developer documentation for scream-cli crate
1 parent 854cd0a commit d80a73e

1 file changed

Lines changed: 203 additions & 0 deletions

File tree

docs/dev/cli/README.md

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# `scream-cli` Developer Documentation
2+
3+
This document provides a comprehensive technical breakdown of the `scream-cli` crate. It details the flow of execution, configuration handling, data management, and the user interface system. It is intended for developers contributing to or extending the CLI's functionality.
4+
5+
For user-facing instructions on how to _use_ the CLI, see the [User Manual (`/docs/cli/USAGE.md`)](/docs/cli/USAGE.md).
6+
7+
**Table of Contents**
8+
9+
- [`scream-cli` Developer Documentation](#scream-cli-developer-documentation)
10+
- [1. Component Overview](#1-component-overview)
11+
- [2. Execution Flow of a `scream place` Command](#2-execution-flow-of-a-scream-place-command)
12+
- [3. The Layered Configuration System](#3-the-layered-configuration-system)
13+
- [3.1. The Three Layers of Configuration](#31-the-three-layers-of-configuration)
14+
- [3.2. The Build Process in `config::builder`](#32-the-build-process-in-configbuilder)
15+
- [4. Data Management with `DataManager`](#4-data-management-with-datamanager)
16+
- [4.1. Data Path Resolution](#41-data-path-resolution)
17+
- [4.2. Logical Name Resolution](#42-logical-name-resolution)
18+
- [4.3. Data Downloading](#43-data-downloading)
19+
- [5. User Interface (UI) and Logging](#5-user-interface-ui-and-logging)
20+
- [5.1. Decoupled Architecture with `tokio::mpsc`](#51-decoupled-architecture-with-tokiompsc)
21+
- [5.2. Progress Reporting](#52-progress-reporting)
22+
- [5.3. Logging Integration](#53-logging-integration)
23+
24+
---
25+
26+
## 1. Component Overview
27+
28+
The `scream-cli` crate is structured into several modules, each with a distinct responsibility, to create a maintainable and extensible command-line application.
29+
30+
- **`main.rs`**: The application entry point. It is responsible for setting up the `tokio` asynchronous runtime, initializing global error handling (`color-eyre`), parsing command-line arguments, and spawning the main UI manager task.
31+
32+
- **`cli.rs`**: Defines the entire command-line interface structure using `clap`'s derive macros. This file is the single source of truth for all commands (`place`, `data`), subcommands, arguments, and help messages.
33+
34+
- **`commands/`**: Contains the primary business logic for each subcommand.
35+
36+
- `place.rs`: Orchestrates the entire side-chain placement process, from configuration building to calling `scream-core` and processing the results.
37+
- `data.rs`: Implements the logic for the `scream data` subcommands (`download`, `path`, etc.).
38+
39+
- **`config/`**: The configuration engine.
40+
41+
- `file.rs`: Defines the Rust structs that map directly to the `config.toml` file format using `serde`.
42+
- `defaults.rs`: Provides hardcoded, sensible fallback values for all configurable parameters.
43+
- `builder.rs`: Implements the core logic for merging the three configuration layers (defaults, file, and CLI arguments) into a final, validated `PlacementConfig` struct for `scream-core`.
44+
45+
- **`data.rs`**: Implements the `DataManager`, a crucial abstraction that handles the physical location, resolution of logical names, and downloading of external data files (forcefields, rotamer libraries).
46+
47+
- **`ui.rs`**: Manages all terminal output. It uses the `indicatif` crate for progress bars and runs in a separate `tokio` task. It receives events to display from both the core library and the logging system via a shared channel.
48+
49+
- **`logging.rs`**: Configures the `tracing` subscriber framework. Its key feature is a custom `tracing::Layer` (`ChannelLayer`) that intercepts log messages and forwards them to the `UiManager` for display, ensuring that logging does not interfere with progress bar rendering.
50+
51+
- **`error.rs`**: Defines the CLI-specific error enum (`CliError`), which centralizes error handling for the application.
52+
53+
## 2. Execution Flow of a `scream place` Command
54+
55+
A typical `scream place` command follows a well-defined sequence of operations, translating user input into a scientific result.
56+
57+
**Figure 1: `scream place` Execution Flow**
58+
59+
```mermaid
60+
sequenceDiagram
61+
participant User
62+
participant CLI (main.rs)
63+
participant ConfigBuilder as Config Builder (config::builder)
64+
participant DataManager (data.rs)
65+
participant Core Library (scream-core)
66+
participant UI Manager (ui.rs)
67+
68+
User->>+CLI: executes `scream place ...`
69+
CLI->>CLI: `clap::parse()` command-line args
70+
CLI->>+UI Manager: Spawn UiManager task
71+
CLI->>+Config Builder: `build_config(args)`
72+
Config Builder->>+DataManager: Resolve logical names (e.g., 'charmm@rmsd-1.0')
73+
DataManager-->>-Config Builder: Return concrete file paths
74+
Config Builder-->>-CLI: Return final `PlacementConfig`
75+
CLI->>+Core Library: `workflows::place::run(system, config, reporter)`
76+
Note right of Core Library: Emits `Progress` events to <br/>UI Manager via reporter callback
77+
Core Library-->>-CLI: Return `PlacementResult`
78+
CLI->>CLI: Process results & write output file(s)
79+
CLI->>-UI Manager: Send shutdown signal
80+
```
81+
82+
1. **Parsing**: `main.rs` uses `clap` to parse all command-line arguments into the `Cli` struct.
83+
2. **UI Initialization**: The `UiManager` is spawned as a separate asynchronous `tokio` task to handle all terminal rendering independently of the main computation.
84+
3. **Configuration Building**: `commands::place::run` calls `config::builder::build_config`, passing the parsed arguments.
85+
4. **Path Resolution**: The `Config Builder` uses the `DataManager` to resolve any "logical names" for data files (like `'charmm@rmsd-1.0'`) into absolute file paths.
86+
5. **Core Invocation**: A final, validated `PlacementConfig` is constructed and passed to the `scream_core::workflows::place::run` function. The computationally intensive work happens here, executed within a `tokio::task::spawn_blocking` call to avoid blocking the async runtime.
87+
6. **Progress Reporting**: During execution, the core library sends `Progress` events back to the `UiManager` via a callback, which updates the progress bars in the terminal.
88+
7. **Result Handling**: Once `place::run` returns a `PlacementResult`, the `commands::place` module formats the summary, prints it to the console, and writes the resulting molecular structure(s) to the output file(s) specified by the user.
89+
90+
## 3. The Layered Configuration System
91+
92+
The CLI's configuration system is designed to be flexible and predictable, merging settings from three distinct sources with a clear order of precedence.
93+
94+
### 3.1. The Three Layers of Configuration
95+
96+
Settings are determined by the first layer in which they are found, following this hierarchy:
97+
98+
**Figure 2: Configuration Priority**
99+
100+
```mermaid
101+
graph TD
102+
subgraph Priority
103+
direction LR
104+
A["<strong>Layer 1:</strong><br/>CLI Arguments<br/>(Highest Priority)"] --> B["<strong>Layer 2:</strong><br/>`config.toml` File"];
105+
B --> C["<strong>Layer 3:</strong><br/>Built-in Defaults<br/>(Lowest Priority)"];
106+
end
107+
```
108+
109+
1. **Layer 1: Command-Line Arguments**: Any argument provided directly on the command line (e.g., `--s-factor 1.2`, `-n 5`) always overrides settings from other layers. This is ideal for quick experiments and scripting.
110+
2. **Layer 2: TOML Configuration File**: The `config.toml` file is the primary method for specifying complex or persistent settings, such as the `[residues-to-optimize]` table.
111+
3. **Layer 3: Built-in Defaults (`config::defaults`)**: These are hardcoded fallback values that ensure the program can run with minimal user input.
112+
113+
### 3.2. The Build Process in `config::builder`
114+
115+
The `config::builder::build_config` function is the orchestrator of this merging logic. Its process is as follows:
116+
117+
1. It starts with the `DefaultsConfig` struct.
118+
2. It loads the `FileConfig` struct by parsing the TOML file specified via `--config`. If no file is given, an empty `FileConfig` is used.
119+
3. It applies any `--set KEY=VALUE` arguments, directly modifying the in-memory `FileConfig` struct.
120+
4. It iterates through every parameter required by `scream-core`'s `PlacementConfig`. For each parameter, it checks for a value in this order: command-line argument, `FileConfig` struct, and finally the `DefaultsConfig`.
121+
5. During this process, it uses the `DataManager` to translate any string-based "logical names" into verified `PathBuf`s.
122+
6. Finally, it constructs and returns the fully validated `PlacementConfig` object.
123+
124+
## 4. Data Management with `DataManager`
125+
126+
The `DataManager` (`data.rs`) is a critical abstraction that decouples the application logic from the physical storage of data files like forcefields and rotamer libraries.
127+
128+
### 4.1. Data Path Resolution
129+
130+
The `DataManager` determines the root directory for all data files using a two-step process:
131+
132+
1. It first looks for a configuration file in an OS-specific config location (e.g., `~/.config/screampp/path.conf` on Linux). This file can be created and modified by the user via `scream data set-path` and `reset-path`.
133+
2. If this file does not exist, it falls back to an OS-specific default data directory (e.g., `~/.local/share/screampp` on Linux). This logic is handled by the `directories-rs` crate.
134+
135+
This ensures a predictable and platform-idiomatic location for data while still allowing user customization.
136+
137+
### 4.2. Logical Name Resolution
138+
139+
To provide a user-friendly experience, the CLI uses "logical names" instead of requiring full file paths for common data files.
140+
141+
- **The Problem**: A user should not have to type `--rotamer-library /path/to/data/rotamers/charmm/rmsd-1.0.toml`.
142+
- **The Solution**:
143+
1. The `utils::parser` module contains functions that parse user-friendly strings like `'charmm@rmsd-1.0'` into a structured representation (e.g., `RotamerLibraryName { scheme: "charmm", diversity: "rmsd-1.0" }`).
144+
2. The `DataManager::resolve_logical_name` method takes this structured data and constructs the full, platform-correct file path within the resolved data directory. It also performs an existence check on the final path.
145+
146+
### 4.3. Data Downloading
147+
148+
The `scream data download` command automates the acquisition of required data.
149+
150+
- **Process**: It uses the `reqwest` library to fetch a version-matched `.tar.zst` archive from the official SCREAM++ GitHub Releases page. The downloaded data is streamed into memory, decompressed on-the-fly using the `zstd` crate, and unpacked into the data directory using the `tar` crate. This entire process is visualized with an `indicatif` progress bar.
151+
152+
## 5. User Interface (UI) and Logging
153+
154+
The CLI's user interface is designed to be responsive and non-blocking, providing clear feedback without slowing down the core computation.
155+
156+
### 5.1. Decoupled Architecture with `tokio::mpsc`
157+
158+
The UI is architected around an asynchronous, event-driven model.
159+
160+
**Figure 3: UI and Logging Event Flow**
161+
162+
```mermaid
163+
graph TD
164+
subgraph "Core Computation (Blocking Thread)"
165+
A["scream-core Reporter"];
166+
end
167+
168+
subgraph "CLI Main Thread"
169+
B["tracing::Layer"];
170+
end
171+
172+
subgraph "UI Task (Async)"
173+
E["UiManager"];
174+
F["indicatif MultiProgress"];
175+
E --> F;
176+
end
177+
178+
C["tokio::mpsc::channel"];
179+
180+
A -- "Progress Event" --> C;
181+
B -- "Log Event" --> C;
182+
C -- "UiEvent" --> E;
183+
F --> G[Terminal Output];
184+
```
185+
186+
- **Decoupling**: The main computational logic (in `scream-core`) runs in a blocking thread pool managed by `tokio::task::spawn_blocking`. The `UiManager` runs in a separate, non-blocking asynchronous task.
187+
- **Communication**: They communicate via a `tokio::mpsc` (multi-producer, single-consumer) channel. This allows the computationally-heavy core library and the logging system to send `UiEvent` messages to the `UiManager` without waiting for the terminal to render.
188+
189+
### 5.2. Progress Reporting
190+
191+
- A `CliProgressHandler` is created in the CLI. It holds a sender handle to the mpsc channel.
192+
- It generates a `ProgressCallback` closure (a `Box<dyn Fn(...)>`), which captures the channel sender.
193+
- This callback is passed down into `scream-core` as part of the `ProgressReporter`.
194+
- When the core library needs to report progress (e.g., `Progress::TaskIncrement`), it calls the callback. The callback's only job is to send the `Progress` event into the channel asynchronously.
195+
- The `UiManager`'s main loop receives the event and updates the `indicatif` progress bars accordingly.
196+
197+
### 5.3. Logging Integration
198+
199+
To prevent log messages from interfering with the dynamically rendered progress bars, the logging system is integrated into the same UI event loop.
200+
201+
- **`logging::ChannelLayer`**: A custom `tracing::Layer` is implemented.
202+
- **Mechanism**: Instead of writing formatted log messages directly to `stdout` or `stderr`, this layer intercepts each log event from the `tracing` framework. It formats the message and sends it as a `UiEvent::Log` over the _same_ mpsc channel used for progress events.
203+
- **Benefit**: The `UiManager` receives both log messages and progress updates through a single stream. It can then use `indicatif`'s `MultiProgress::println` method to print the log message _above_ the active progress bars, ensuring a clean, non-flickering, and readable terminal output.

0 commit comments

Comments
 (0)