stack.menu

Rust CLI + TUI

Portable command-line tools with explicit memory and resource control.

Clap · Ratatui when needed · Cargo

Complete guide (Markdown) · Structured record (JSON)

Original source review: 2026-10-10. Core guidance rechecked: 2026-10-13. Check scope. Dependency combinations and setup need project-specific qualification.

Use cases

Choose it when

Consider another path when

Working practices

Tools by job

Command parsing: clap

Typed commands plus a mature terminal widget/rendering ecosystem.

Keep domain code separate from rendering and support non-TTY output; restore terminal on errors and interruption.

Terminal UI: Ratatui only for interactive screens

Typed commands plus a mature terminal widget/rendering ecosystem.

Keep domain code separate from rendering and support non-TTY output; restore terminal on errors and interruption.

HTTP client: reqwest

Reusable typed HTTP client APIs.

Choose blocking or async deliberately; configure timeouts, TLS and response bounds. Never call blocking client inside an async runtime indiscriminately.

Persistence and migrations: None for stateless tools

Start without a database; add schema ownership only for persistent products.

SQLite feature/driver and migration setup require target testing; durable local state is not shared distributed workflow state.

Configuration: Serde-backed settings + config

Typed settings plus structured events/spans.

Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets.

Application logging: tracing + configured subscriber

Typed settings plus structured events/spans.

Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets.

Tests and static checks: cargo test; rustfmt; Clippy; cargo audit

Compiler, style, behavior and known-advisory checks complement each other.

Audit coverage is advisory-driven; compile success does not establish behavior or security. Test supported feature combinations rather than blindly enabling incompatible features.

Executable behavior tests: assert_cmd

Tests real exit codes, stdout/stderr and command contracts.

Snapshot changes need review; also test actual error and side-effect behavior.

Durable work: Delegate to a durable service; retain resumable job identity

CLI lifetime does not own remote work lifetime.

Checkpoint schema, atomic persistence and external idempotency must be designed; async execution alone adds no durability.

Distribution: dist (formerly cargo-dist) + Cargo release builds

Generates multi-platform release pipelines and installers.

Review generated CI before tags can publish; test installers and target-native dependencies. Signing and notarization are separate platform work.

Machine-readable output: serde_json

Stable JSON output lets scripts consume commands without parsing terminal text

Add an explicit --json/output mode and document schema/exit codes; reserve stdout for results, stderr for diagnostics, and disable interactive/color output for pipelines.

Cancellation and shutdown: Tokio signal handling for async commands

User interrupts should cancel outbound work and leave terminal/files usable

Propagate cancellation through work; bound cleanup time and test interrupts during writes. Avoid adding an async runtime to a synchronous Rust CLI solely for signals.

Build with the stack’s strengths

Architecture and developer workflow.

Recommendation: clap derives/parses a stable command interface, domain operations return Result, and the entry point converts errors to streams/status after cleanup. Serde owns a versioned machine format; Ratatui is an optional terminal client. Cargo/dist prepare artifacts for explicitly supported targets and update channels.

Version scope: Reviewed clap 4.6.7 and Rust std 1.99.0 documentation; Serde, Ratatui and current axodotdev cargo-dist book. Pin rust-toolchain.toml/Cargo.lock and dist version/config. The older opensource.axo.dev book path failed; no target install or release workflow was executed. · Reviewed 2026-10-11

Architecture boundaries

Tools and feedback

Translations to avoid

For an existing application

Keep the contracts while you change the stack.

These are documented options and proposed checks. Inspect the actual source application before adopting a transition.

CLI and pipe contracts

Inspect the source

Record current commands, option defaults, exit codes, stdout/stderr, JSON field names and shell completions consumed by callers.

During coexistence

Recommendation: keep an old command adapter and explicit schema version while migrating parsing to clap. Preserve old names/aliases and map new domain errors into the established protocol.

Target design

Recommendation: clap plus typed result/error JSON and main ExitCode mapping. clap usage failures use status 2 while help/version uses success; application failures need their own documented policy.

Rollback

Recommendation: return consumers to the previous binary/schema while retaining old option adapters. Keep version selection explicit so a rollback does not silently alter JSON meaning.

Benefits and prerequisites

Typed parsing and a stable output envelope make command automation explicit.
Requires: Contract fixtures cover old callers; result schemas and error/status mapping are versioned; help/completion behavior is checked.
Tradeoffs: Parser defaults can change compatibility; numeric status meanings are not universal across platforms; Rust error types do not define the public protocol.

Checks before transfer

  • Verify help/version succeed and invalid arguments use the intended stream/code without effects.
  • Execute legacy scripts and compare stdout/stderr/status exactly where promised.
  • Validate empty, partial and failed JSON results against the advertised schema.
Data and schema

Inspect the source

Inventory configuration file locations, schema versions, defaults, permissions and old binaries' ability to read newer files.

During coexistence

Recommendation: read old config into a versioned internal model and migrate only through an explicit command with backup. Keep concurrent writer ownership explicit; read-only startup must not silently rewrite files.

Target design

Recommendation: Serde-tagged/versioned configuration and documented unknown-field handling. Validate a temporary representation before replacing the live file; platform atomicity, permissions and crash behavior require implementation checks.

Rollback

Recommendation: restore the preserved old config and binary as a pair. Reconcile new-only fields before using an old reader; avoid destructive in-place downgrade guesses.

Benefits and prerequisites

Explicit config migration decouples executable upgrades from accidental data loss.
Requires: Old/new fixtures and semantic transforms exist; backup/restore works; unsupported versions fail before write.
Tradeoffs: Strict Serde unknown-field rejection can prevent mixed-version use; deny_unknown_fields does not compose with flatten; replacing a file is not a complete durability protocol.

Checks before transfer

  • Load old config and compare effective settings after migration.
  • Verify unsupported versions and malformed values leave the source unchanged.
  • Downgrade the binary with its preserved config and confirm paths/permissions on each target OS.
Jobs and schedules

Inspect the source

Preserve ordering, per-item effects, timeout and interrupt semantics for batch/network subcommands.

During coexistence

Recommendation: retain sequential mode while qualifying bounded parallel work using dry-run/fixtures. Store item operation IDs and completion receipts before enabling resume against live systems.

Target design

Recommendation: a bounded executor selected for CPU or async I/O with cooperative stop, tracked joins and cleanup. Started blocking work needs its own stop protocol or process boundary; do not label a task timeout as effect cancellation.

Rollback

Recommendation: use sequential mode with the same receipt format and reconcile unknown outcomes. A previous executable must be able to read checkpoint versions or an explicit converter is required.

Benefits and prerequisites

Bounded parallel execution can overlap independent work without unlimited task creation.
Requires: Independent item semantics; capacity/budget limits; stable effect IDs; tested cancellation and resume contract.
Tradeoffs: Speed is unmeasured; running blocking tasks may continue; a cancelled remote write can have an ambiguous outcome.

Checks before transfer

  • Interrupt a batch and verify no new items start, joins are bounded and terminal state restores.
  • Simulate a remote success with a lost acknowledgement; resume reconciles rather than duplicating the effect.
  • Verify CPU tasks cannot starve I/O and the executor respects the declared capacity.
Delivery and recovery

Inspect the source

Capture existing target triples, libc/native dependencies, install path, package metadata and update/downgrade contracts.

During coexistence

Recommendation: prepare dist artifacts beside the previous release; review generated CI and installers, and use a prerelease or test channel for target qualification. Do not promise all platforms merely because dist generates a matrix.

Target design

Recommendation: pinned dist configuration and Cargo.lock with release artifacts/installers for exercised targets. Keep signing/attestation, system dependency baselines and update channel ownership explicit.

Rollback

Recommendation: restore the previous verified package/update channel and retain older installers/checksums. Review data/config compatibility before allowing downgrade; never change a public channel based only on a plan.

Benefits and prerequisites

Generated release plans coordinate binary artifacts and installers across targets.
Requires: dist version is pinned; generated workflow is reviewed; native dependencies and every advertised target are exercised.
Tradeoffs: dist init may replace generated workflows; OS signing and Linux libc compatibility remain separate obligations; a plan is not build/publication evidence.

Checks before transfer

  • Inspect dist plan --output-format=json for expected target triples and artifact names.
  • Install downloaded artifacts on clean target hosts, including the oldest promised Linux baseline.
  • Exercise upgrade/downgrade, PATH behavior, checksum verification and preserved versioned config.

Read the migration workflow →

Setup

  1. Create source in a local development workspace with cargo new tool; enter tool; run cargo add clap --features derive.
  2. Resolve Ratatui and its supported terminal backend only if interactive rendering is required; add reqwest only if network access is needed.
  3. Implement typed commands, injected/configured settings, stable output/exit codes and domain logic independent of terminal rendering.
  4. Add tests with cargo add --dev assert_cmd; cover missing files, invalid input, stdin, cancellation, stdout/stderr and terminal cleanup.
  5. Install a selected dist release and run dist init; review target list and generated CI. Lock dependencies/toolchain; no release tags or publication were executed.

Verification

Run these in the configured application; they are instructions, not recorded passes.

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo test --workspace --locked
cargo audit
cargo build --release --locked

Open questions

Sources