Skip to content
Back to skills

Cli Distribution

CSecurity

Distribution and packaging patterns including shell completions, man pages, cross-compilation, and release automation. Use when preparing CLI tools for distribution.

  • 666 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added February 8, 2026
toolsrustgorubyshellbashexpressdockergitbackendci/cd

Works with

  • cli

Security analysis

C68/100
  • highPerforms destructive filesystem operations
  • criticalModifies startup scripts or system services for persistence
  • criticalModifies startup scripts or system services for persistence

Pro shows the line behind each finding and how to fix it

Scanned February 10, 2026

npx -y skills add majiayu000/claude-skill-registry --skill cli-distribution --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cli Distribution?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cli Distribution
[![Security: C — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-cli-distribution/badge)](https://www.skillsdirectory.com/skills/majiayu000-cli-distribution)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cli-distribution
description: Distribution and packaging patterns including shell completions, man pages, cross-compilation, and release automation. Use when preparing CLI tools for distribution.
---

# CLI Distribution Skill

Patterns and best practices for distributing Rust CLI applications to users.

## Shell Completion Generation

### Using clap_complete

```rust
use clap::{CommandFactory, Parser};
use clap_complete::{generate, Generator, Shell};
use std::io;

#[derive(Parser)]
struct Cli {
    /// Generate shell completions
    #[arg(long = "generate", value_enum)]
    generator: Option<Shell>,

    // ... other fields
}

fn print_completions<G: Generator>(gen: G, cmd: &mut clap::Command) {
    generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
}

fn main() {
    let cli = Cli::parse();

    if let Some(generator) = cli.generator {
        let mut cmd = Cli::command();
        print_completions(generator, &mut cmd);
        return;
    }

    // ... rest of application
}
```

### Installation Instructions by Shell

**Bash:**
```bash
# Generate and save
myapp --generate bash > /etc/bash_completion.d/myapp

# Or add to ~/.bashrc
eval "$(myapp --generate bash)"
```

**Zsh:**
```bash
# Generate and save
myapp --generate zsh > ~/.zfunc/_myapp

# Add to ~/.zshrc
fpath=(~/.zfunc $fpath)
autoload -Uz compinit && compinit
```

**Fish:**
```bash
# Generate and save
myapp --generate fish > ~/.config/fish/completions/myapp.fish

# Or load directly
myapp --generate fish | source
```

**PowerShell:**
```powershell
# Add to $PROFILE
Invoke-Expression (& myapp --generate powershell)
```

### Dynamic Completions

For commands with dynamic values (like listing resources):

```rust
use clap::CommandFactory;
use clap_complete::{generate, Generator};

pub fn generate_with_values<G: Generator>(
    gen: G,
    resources: &[String],
) -> String {
    let mut cmd = Cli::command();

    // Add dynamic values to completion
    if let Some(subcommand) = cmd.find_subcommand_mut("get") {
        for resource in resources {
            subcommand = subcommand.arg(
                clap::Arg::new("resource")
                    .value_parser(clap::builder::PossibleValuesParser::new(resource))
            );
        }
    }

    let mut buf = Vec::new();
    generate(gen, &mut cmd, "myapp", &mut buf);
    String::from_utf8(buf).unwrap()
}
```

## Man Page Generation

### Using clap_mangen

```toml
[dependencies]
clap_mangen = "0.2"
```

```rust
use clap::CommandFactory;
use clap_mangen::Man;
use std::io;

fn generate_man_page() {
    let cmd = Cli::command();
    let man = Man::new(cmd);
    man.render(&mut io::stdout()).unwrap();
}
```

### Build Script for Man Pages

```rust
// build.rs
use clap::CommandFactory;
use clap_mangen::Man;
use std::fs;
use std::path::PathBuf;

include!("src/cli.rs");

fn main() {
    let out_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("target/man");
    fs::create_dir_all(&out_dir).unwrap();

    let cmd = Cli::command();
    let man = Man::new(cmd);
    let mut buffer = Vec::new();
    man.render(&mut buffer).unwrap();

    fs::write(out_dir.join("myapp.1"), buffer).unwrap();
}
```

### Install Man Page

```bash
# System-wide
sudo cp target/man/myapp.1 /usr/local/share/man/man1/

# User-local
mkdir -p ~/.local/share/man/man1
cp target/man/myapp.1 ~/.local/share/man/man1/
```

## Cross-Compilation

### Target Triples

Common targets for CLI distribution:

```bash
# Linux
x86_64-unknown-linux-gnu      # GNU Linux
x86_64-unknown-linux-musl     # MUSL Linux (static)
aarch64-unknown-linux-gnu     # ARM64 Linux

# macOS
x86_64-apple-darwin           # Intel Mac
aarch64-apple-darwin          # Apple Silicon

# Windows
x86_64-pc-windows-msvc        # Windows MSVC
x86_64-pc-windows-gnu         # Windows GNU
```

### Cross-Compilation with cross

```bash
# Install cross
cargo install cross

# Build for Linux from any platform
cross build --release --target x86_64-unknown-linux-gnu

# Build static binary with MUSL
cross build --release --target x86_64-unknown-linux-musl
```

### GitHub Actions for Cross-Compilation

```yaml
# .github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    strategy:
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            artifact_name: myapp
            asset_name: myapp-linux-amd64

          - os: ubuntu-latest
            target: x86_64-unknown-linux-musl
            artifact_name: myapp
            asset_name: myapp-linux-musl-amd64

          - os: macos-latest
            target: x86_64-apple-darwin
            artifact_name: myapp
            asset_name: myapp-macos-amd64

          - os: macos-latest
            target: aarch64-apple-darwin
            artifact_name: myapp
            asset_name: myapp-macos-arm64

          - os: windows-latest
            target: x86_64-pc-windows-msvc
            artifact_name: myapp.exe
            asset_name: myapp-windows-amd64.exe

    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@v3

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Build
        run: cargo build --release --target ${{ matrix.target }}

      - name: Upload binaries
        uses: actions/upload-artifact@v3
        with:
          name: ${{ matrix.asset_name }}
          path: target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
```

## Binary Size Optimization

### Cargo.toml optimizations

```toml
[profile.release]
opt-level = "z"     # Optimize for size
lto = true          # Link-time optimization
codegen-units = 1   # Better optimization
strip = true        # Strip symbols
panic = "abort"     # Smaller panic handler
```

### Additional size reduction

```bash
# Install upx
brew install upx  # macOS
apt install upx   # Linux

# Compress binary
upx --best --lzma target/release/myapp
```

**Before/After example:**
```
Original:  2.5 MB
Optimized: 1.2 MB (strip = true)
UPX:       400 KB (upx --best --lzma)
```

## Package Distribution

### Homebrew (macOS/Linux)

Create a formula:

```ruby
# Formula/myapp.rb
class Myapp < Formula
  desc "Description of your CLI tool"
  homepage "https://github.com/username/myapp"
  url "https://github.com/username/myapp/archive/v1.0.0.tar.gz"
  sha256 "abc123..."
  license "MIT"

  depends_on "rust" => :build

  def install
    system "cargo", "install", "--locked", "--root", prefix, "--path", "."

    # Install shell completions
    generate_completions_from_executable(bin/"myapp", "--generate")

    # Install man page
    man1.install "target/man/myapp.1"
  end

  test do
    assert_match "myapp 1.0.0", shell_output("#{bin}/myapp --version")
  end
end
```

### Debian Package (.deb)

Using `cargo-deb`:

```bash
cargo install cargo-deb

# Create debian package
cargo deb

# Package will be in target/debian/myapp_1.0.0_amd64.deb
```

**Cargo.toml metadata:**

```toml
[package.metadata.deb]
maintainer = "Your Name <you@example.com>"
copyright = "2024, Your Name"
license-file = ["LICENSE", "4"]
extended-description = """
A longer description of your CLI tool
that spans multiple lines."""
depends = "$auto"
section = "utility"
priority = "optional"
assets = [
    ["target/release/myapp", "usr/bin/", "755"],
    ["README.md", "usr/share/doc/myapp/", "644"],
    ["target/completions/myapp.bash", "usr/share/bash-completion/completions/", "644"],
    ["target/man/myapp.1", "usr/share/man/man1/", "644"],
]
```

### Docker Distribution

```dockerfile
# Dockerfile
FROM rust:1.75 as builder
WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/myapp /usr/local/bin/myapp
ENTRYPOINT ["myapp"]
```

**Multi-stage with MUSL (smaller image):**

```dockerfile
FROM rust:1.75-alpine as builder
RUN apk add --no-cache musl-dev
WORKDIR /app
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl

FROM scratch
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/myapp /myapp
ENTRYPOINT ["/myapp"]
```

### Cargo-binstall Support

Add metadata for faster installation:

```toml
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ target }{ binary-ext }"
bin-dir = "{ bin }{ binary-ext }"
pkg-fmt = "bin"
```

Users can then install with:
```bash
cargo binstall myapp
```

## Auto-Update

### Using self_update crate

```toml
[dependencies]
self_update = "0.39"
```

```rust
use self_update::cargo_crate_version;

fn update() -> Result<()> {
    let status = self_update::backends::github::Update::configure()
        .repo_owner("username")
        .repo_name("myapp")
        .bin_name("myapp")
        .show_download_progress(true)
        .current_version(cargo_crate_version!())
        .build()?
        .update()?;

    println!("Update status: `{}`!", status.version());
    Ok(())
}
```

### Update Command

```rust
#[derive(Subcommand)]
enum Commands {
    /// Update to the latest version
    Update,
}

fn handle_update() -> Result<()> {
    println!("Checking for updates...");

    match update() {
        Ok(_) => {
            println!("Updated successfully! Please restart the application.");
            Ok(())
        }
        Err(e) => {
            eprintln!("Update failed: {}", e);
            eprintln!("Download manually: https://github.com/username/myapp/releases");
            Err(e)
        }
    }
}
```

## Release Automation

### Cargo-release

```bash
cargo install cargo-release

# Dry run
cargo release --dry-run

# Release patch version
cargo release patch --execute

# Release minor version
cargo release minor --execute
```

### GitHub Release Action

```yaml
# .github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: taiki-e/create-gh-release-action@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          changelog: CHANGELOG.md

  upload-assets:
    needs: release
    strategy:
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
          - target: x86_64-apple-darwin
          - target: x86_64-pc-windows-msvc

    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v3

      - uses: taiki-e/upload-rust-binary-action@v1
        with:
          bin: myapp
          target: ${{ matrix.target }}
          token: ${{ secrets.GITHUB_TOKEN }}
```

## Best Practices

1. **Provide multiple installation methods** - Cargo, Homebrew, apt, etc.
2. **Generate completions** - Essential for good UX
3. **Create man pages** - Professional documentation
4. **Test cross-platform** - Build for all major platforms
5. **Optimize binary size** - Users appreciate smaller downloads
6. **Automate releases** - Use CI/CD for consistent builds
7. **Version clearly** - Semantic versioning
8. **Sign binaries** - Build trust (especially on macOS)
9. **Provide checksums** - Verify download integrity
10. **Document installation** - Clear, platform-specific instructions

## Distribution Checklist

- [ ] Shell completions generated (bash, zsh, fish, powershell)
- [ ] Man pages created
- [ ] Cross-compiled for major platforms
- [ ] Binary size optimized
- [ ] Release artifacts uploaded to GitHub
- [ ] Installation instructions in README
- [ ] Homebrew formula (if applicable)
- [ ] Debian package (if applicable)
- [ ] Docker image (if applicable)
- [ ] Checksums provided
- [ ] Changelog maintained
- [ ] Version bumped properly

## References

- [clap_complete Documentation](https://docs.rs/clap_complete/)
- [clap_mangen Documentation](https://docs.rs/clap_mangen/)
- [cargo-deb](https://github.com/kornelski/cargo-deb)
- [cross](https://github.com/cross-rs/cross)
- [Rust Platform Support](https://doc.rust-lang.org/nightly/rustc/platform-support.html)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.