# Rho Single CLI TODO
Status: implemented on `madhava/cli-all`. Keep this file until the branch is
merged and the release artifacts are confirmed.
## Objective
Finish the migration from a dispatcher plus many `rho-*` binaries to one real
installed binary:
```text
rho <subcommand> ...
```
The crate name stays `rho-cli`; the installed executable should be `rho`.
## Current Evidence
- [x] `Cargo.toml` now defines one binary target:
- `rho`
- [x] `src/bin/rho.rs` dispatches to internal command modules directly.
- [x] Command implementations moved to `src/commands/*.rs`.
- [x] `.github/workflows/release.yml` now sets `RHO_BINS: rho`.
- [x] Release packaging builds with `cargo build --release --locked --target ... --bin rho`.
- [x] `install.sh` verifies only `rho`.
- [x] E2E tests invoke `cargo run --quiet --bin rho -- <subcommand> ...`.
## Target Shape
- One binary target remains in `Cargo.toml`:
- `rho`
- All user-facing commands are subcommands of `rho`.
- Command logic lives in normal Rust modules, not in sibling executables.
- Release archives contain only `rho`.
- `cargo install rho-cli --bin rho` installs the full CLI.
- `rho --version` and `rho version` continue to report the crate version.
## Command Map
| `rho-dataset ...` | `rho dataset ...` |
| `rho-publish ...` | `rho publish ...` |
| `rho-message ...` | `rho message ...` |
| `rho-request ...` | `rho request ...` |
| `rho-tools ...` | `rho tools ...` |
| `rho-run ...` | `rho run ...` |
| `rho-result ...` | `rho result ...` |
| `rho-id ...` | `rho id ...` |
| `rho-crypto ...` | `rho crypto ...` |
| `rho-repo ...` | `rho repo ...` |
| dispatcher alias `rho approve ...` | keep as `rho approve ...`, backed by request logic |
| dispatcher alias `rho status ...` | keep as `rho status ...`, backed by repo logic |
| dispatcher alias `rho add user ...` | keep as `rho add user ...`, backed by repo logic |
| current `rho gh ...` | keep in `rho` |
| current `rho commit ...` | keep in `rho` |
| current `rho env ...` | keep in `rho` |
| current `rho install-shell ...` | keep in `rho` |
## Non-Goals
- Do not redesign command behavior during this migration.
- Do not introduce long-term compatibility binaries.
- Do not add a CLI framework unless the migration proves the existing parsing is
too brittle to maintain.
- Do not block on live Pi/provider tests; keep those manual.
## Migration Plan
### 1. Create command modules
- [x] Add `src/commands/mod.rs`.
- [x] Move each implementation file into a module:
- [x] `src/bin/rho_dataset.rs` -> `src/commands/dataset.rs`
- [x] `src/bin/rho_publish.rs` -> `src/commands/publish.rs`
- [x] `src/bin/rho_message.rs` -> `src/commands/message.rs`
- [x] `src/bin/rho_request.rs` -> `src/commands/request.rs`
- [x] `src/bin/rho_tools.rs` -> `src/commands/tools.rs`
- [x] `src/bin/rho_run.rs` -> `src/commands/run.rs`
- [x] `src/bin/rho_result.rs` -> `src/commands/result.rs`
- [x] `src/bin/rho_id.rs` -> `src/commands/id.rs`
- [x] `src/bin/rho_crypto.rs` -> `src/commands/crypto.rs`
- [x] `src/bin/rho_repo.rs` -> `src/commands/repo.rs`
- [x] Export command modules through `src/commands/mod.rs` for `src/bin/rho.rs`.
### 2. Convert `main()` functions
- [x] Replace each moved `fn main()` with a callable entrypoint.
- [x] Use one consistent shape:
```rust
pub fn run(args: &[String]) -> i32
```
- [x] Preserve current usage functions and exit-code behavior.
- [x] Avoid panics for ordinary CLI errors.
- [x] Keep stdout/stderr contracts stable for tests and scripts.
If converting direct `std::process::exit(...)` calls is too large for one PR,
allow an intermediate helper that exits from inside the module, but only as a
temporary migration step.
### 3. Replace dispatcher process spawning
- [x] Update `src/bin/rho.rs` so subcommands call modules directly instead of
launching `rho-*` binaries.
- [x] Keep existing built-in commands in `rho.rs`:
- [x] `gh`
- [x] `commit`
- [x] `env`
- [x] `install-shell`
- [x] `version`
- [x] Preserve aliases:
- [x] `rho approve ...`
- [x] `rho status ...`
- [x] `rho add user ...`
### 4. Update tests and scripts
- [x] Replace `cargo run --quiet --bin rho-dataset -- ...` with
`cargo run --quiet --bin rho -- dataset ...`.
- [x] Replace `cargo run --quiet --bin rho-publish -- ...` with
`cargo run --quiet --bin rho -- publish ...`.
- [x] Replace `cargo run --quiet --bin rho-tools -- ...` with
`cargo run --quiet --bin rho -- tools ...`.
- [x] Replace `cargo run --quiet --bin rho-request -- ...` with
`cargo run --quiet --bin rho -- request ...`.
- [x] Replace `cargo run --quiet --bin rho-run -- ...` with
`cargo run --quiet --bin rho -- run ...`.
- [x] Search for any remaining `--bin rho-` and remove it.
- [x] Keep `./rho <subcommand>` tests as-is where they already exercise the
dispatcher path.
### 5. Remove extra binary targets
- [x] Delete all non-`rho` `[[bin]]` entries from `Cargo.toml`.
- [x] Delete or repurpose the old `src/bin/rho_*.rs` files after their logic is
moved.
- [x] Confirm `cargo metadata --no-deps --format-version 1` lists one binary
target named `rho`.
- [x] Confirm `cargo build --bins` still works and only builds `rho`.
### 6. Update release and install packaging
- [x] Change release `RHO_BINS` to `rho`.
- [x] Change release build from `--bins` to `--bin rho`.
- [x] Package only `rho` in Linux/macOS tarballs and Windows zip files.
- [x] Update release notes from "binaries" to "the rho binary".
- [x] Update `install.sh` to install and verify only `rho`.
- [x] Confirm `cargo publish --dry-run --locked` packages only the intended
installed executable.
### 7. Update docs
- [x] Update docs that describe `rho-*` as installed commands in touched e2e docs.
- [x] Keep architecture doc filenames like `rho-id.md` if they describe the
subsystem rather than a binary.
- [x] Add or update README install examples:
- `cargo install rho-cli --bin rho`
- `rho id ...`
- `rho crypto ...`
- `rho repo ...`
- `rho run ...`
## Compatibility Decision
Preferred: make the next minor release the clean single-binary release and
document the new subcommand invocations.
Fallback: if compatibility shims are needed for one release, keep tiny wrapper
binaries only. They must call the same internal modules as `rho` and must not
contain duplicate command logic. Remove them in the following release.
## Acceptance Gates
- [x] `cargo fmt --all -- --check`
- [x] `cargo clippy --all-targets --all-features --locked -- -D warnings`
- [x] `cargo test --all-targets --all-features --locked`
- [x] `./test.sh`
- [x] `cargo publish --dry-run --locked --allow-dirty`
- [x] `rg -- '--bin rho-' tests scripts docs .github install.sh Cargo.toml` returns no migration blockers.
- [x] `cargo metadata --no-deps --format-version 1` proves there is exactly one
binary target: `rho`.
- [x] Release workflow packages only `rho`.
- [x] `install.sh` verifies only `rho`.
- [x] Local smoke checks pass:
- [x] `cargo run --quiet --bin rho -- version`
- [x] `cargo run --quiet --bin rho -- id list`
- [x] `cargo run --quiet --bin rho -- tools list --shared-root sandbox/nonexistent-shared-root`
- [x] `printf '' | cargo run --quiet --bin rho -- crypto smudge`
## First PR Scope
Make the first implementation PR mechanical:
- Move command code into modules.
- Replace dispatcher process spawning with module calls.
- Update tests from `--bin rho-*` to `--bin rho -- <subcommand>`.
- Remove extra bin targets only after tests pass.
- Do not mix in README, Homebrew, completions, or command redesign.