Rust CLI tool for launching vLLM/SGLang containers across a DGX Spark cluster. SSH-based provisioning over russh.
Cargo.toml # Binary crate, Edition 2024
config.toml # User config (gitignored)
locales/ # Fluent i18n files (en, ru, es, it, fr, de)
recipes/ # Recipe directories (<name>/recipe.toml)
src/
├── main.rs # CLI entrypoint, command dispatch, i18n init
├── cli.rs # clap derive CLI definitions
├── config.rs # Config deserialization, cluster resolution;
│ # config/types.rs (Node/Cluster/Config),
│ # config/recipe.rs (Recipe + [env] EnvValue refs)
├── ssh.rs # SSH client, key loading, host key verification
├── docker/
│ ├── mod.rs # Docker command builder: serve, stop, health, logs
│ └── tests.rs # Command builder tests
├── tmux/
│ ├── mod.rs # Tmux module root
│ ├── serve.rs # Tmux serve (window/panel layout)
│ └── ops.rs # Tmux stop/status/logs/attach
├── power.rs # Power on/off/switch flows
├── home_assistant.rs # HA REST API client
├── host_keys.rs # init-host-keys command
├── exec.rs # Exec subcommand + alias resolution
├── doctor.rs # Doctor mode + --repair
├── pre_serve.rs # PreServeCommand types
├── before_serve.rs # Pre-serve hook execution
└── health.rs # Tmux health-check helpers
make check # All gates: fmt → clippy → test → line-count
make fmt # cargo fmt
make check-fmt # cargo fmt --check
make check-clippy # cargo clippy --all-targets -- -D warnings
make check-test # cargo test
make check-lines # File-size ≤500 lines per src/**/*.rs
serve reads the recipe TOMLdocker run command via build_docker_command(), runs via SSHbuild_docker_command() in src/docker/mod.rs is engine-aware:
| Aspect | vLLM | SGLang |
|---|---|---|
| Host IP env var | VLLM_HOST_IP |
SGLANG_WORKER_IP |
| Model argument | bare name | --model-path |
| TP flag | --tensor-parallel-size |
--tp |
| PP flag | --pipeline-parallel-size |
— |
| Backend flag | --distributed-executor-backend (ray only) |
— |
| Init addr | --master-addr + --master-port |
--dist-init-addr |
| Workers | --headless |
— |
Auto-generated flags: --host 0.0.0.0, --port <recipe.port>, --nnodes, --node-rank.
--cluster 4nodes-switch--cluster 4 → resolves to 4nodes-switch (unique prefix, fails on ambiguous)--cluster auto (or omitted) → picks the smallest cluster with NCCL config matching required_nodes[nccl]): NCCL_IB_DISABLE, NCCL_IB_HCA, NCCL_SOCKET_IFNAME, etc.nccl.socket_ifname): MN_IF_NAME, UCX_NET_DEVICES, OMPI_MCA_btl_tcp_if_includeOMP_NUM_THREADS=4, NCCL_IGNORE_CPU_AFFINITY=1, NCCL_NET=IB, NCCL_DEBUG=WARNVLLM_HOST_IP / SGLANG_WORKER_IPVLLM_LOGGING_COLOR=1, TERM=xterm-256color, -p <port>:<port>RAY_ADDRESS, RAY_PORT, RAY_NODE_IP_ADDRESS, RAY_OVERRIDE_NODE_IP_ADDRESS[env]: appended last, overrides everything abovepower off: SSH sudo shutdown now → wait shutdown_delay_seconds → HA turn_off per-node entities + cluster extraspower on: HA turn_on per-node entities + cluster extras (no SSH)power switch: disable nodes/extras unique to from → enable all in toMozilla Fluent via fluent-i18n crate. Locale auto-detected from system. FTL files in locales/{lang}/main.ftl.
Every src/**/*.rs file must stay ≤500 lines. Enforced by make check-lines.
# Build
cargo build
# Run locally with dry-run (no SSH execution)
cargo run -- -d serve --recipe deepseek-v4-flash
# Run tests
cargo test
# All gates (must pass before commit)
make check
# Add a new recipe
mkdir -p recipes/my-model/
# create recipes/my-model/recipe.toml
cargo run -- -d serve --recipe my-model --cluster <name>
# Add a new locale
cp locales/en/main.ftl locales/xx/main.ftl
# translate strings, commit
| Crate | Version | Purpose |
|---|---|---|
clap |
4.6 | CLI parsing (derive) |
russh |
0.61 | SSH client |
russh-keys |
0.50-beta | SSH key loading |
tokio |
1 (full) | Async runtime |
toml |
1 | Config deserialization |
serde |
1 | Serialization |
tracing |
0.1 | Logging |
anyhow |
1.0 | Error handling |
futures |
0.3 | Concurrent SSH |
sha2 |
0.11 | Host key fingerprints |
base64 |
0.22 | Base64 encoding |
reqwest |
0.13 | HTTP client (HA) |
serde_json |
1 | JSON (HA) |
dirs |
6 | OS config dir |
fluent-i18n |
— | Mozilla Fluent i18n |