release/v0.7.4
claude/smbcloud-github-app-k9641p
development
feature/apps
feature/build-release
feature/ci-docs
feature/ci-ruby-gems
feature/cicd
feature/completion
feature/dist-nuget
feature/fix-ci-sdk-pypi-rubygem
feature/fix-clippy-on-stable-channel
feature/fix-deployment-script
feature/github-email
feature/gresiq-v1
feature/project-new-structure
feature/rsync-deploy
feature/ruby-runner
feature/sdk-npm
feature/sdk-workflows
feature/smbcloud-cli-release-npm
feature/smbcloud-deploy
feature/wasm
main
release/v0.7.4
GitHub Copilot Instructions — smbcloud-cli
Project Overview
smbcloud-cli is a Rust CLI tool that ships as the smb binary. It lets users authenticate, manage projects, and trigger deployments on the smbCloud platform. The workspace targets Rust 1.93 (edition 2021) and is built as a Cargo workspace with multiple focused crates.
Workspace Structure
| Crate | Role |
|---|---|
crates/cli |
Main binary (smb) — all commands, entrypoint |
crates/smbcloud-model |
Shared serde data models (source of truth for API shapes) |
crates/smbcloud-network |
Network config, environment resolution, connectivity check |
crates/smbcloud-networking |
Core HTTP client (SmbClient) |
crates/smbcloud-auth |
Auth SDK API calls — login, logout, me |
crates/smbcloud-networking-project |
Project API calls |
crates/smbcloud-utils |
Shared utility helpers |
crates/gresiq |
Internal tooling |
CLI Source Layout (crates/cli/src/)
main.rs — tokio entrypoint, logging setup, command dispatch
lib.rs — crate root, SmbClient accessor
cli/ — Cli struct, Commands enum, CommandResult
account/ — login, logout, me handlers
deploy/ — deploy command handler
project/ — project init, crud, process handlers
token/ — token storage/retrieval
ui/ — terminal output helpers (spinners, styles)
Dependency Graph
crates/cli
└── smbcloud-auth
└── smbcloud-networking-project
└── smbcloud-networking (SmbClient)
└── smbcloud-model (API types)
└── smbcloud-network (Environment, connectivity)
└── smbcloud-utils
All workspace-level dependencies are declared once in the root Cargo.toml under [workspace.dependencies]. Crate-level Cargo.toml files must inherit from workspace with { workspace = true }.
Coding Guidelines
Correctness & Clarity
- Prioritize correctness and clarity. Performance is a secondary concern unless explicitly stated.
- Comments explain why, never what. Do not write comments that summarize or re-describe the code.
- Implement new functionality in existing files when it fits logically. Avoid creating many small, single-purpose files.
Error Handling
- Use
?to propagate errors. Never call.unwrap()or.expect()outside of test code. - Never silently discard errors with
let _ =on fallible operations:- Propagate with
?when the caller should handle it - Use explicit
matchorif let Err(e) = ...when custom recovery logic is needed - Log and ignore only when truly intentional and visibility is preserved
- Propagate with
- All command handlers return
anyhow::Result<CommandResult>. Surface user-facing errors withanyhow!("descriptive message"). - Ensure async errors propagate to the top level so the user sees meaningful terminal output.
Naming & Style
- Use full words for all variable and parameter names — no single-letter names, no abbreviations (e.g.
environmentnotenv,clientnotc). - Use variable shadowing to scope
.clone()calls inside async closures, minimizing borrow lifetimes:rust cx.spawn({ let handle = handle.clone(); async move { handle.do_work().await; } });
Module Structure
- Never create
mod.rsfiles. Usesrc/some_module.rsinstead ofsrc/some_module/mod.rs. - When creating new crates, set
[lib] path = "src/<crate_name>.rs"inCargo.tomlinstead of relying on the defaultlib.rs.
Panics & Bounds
- Avoid any operation that can panic at runtime: no
.unwrap(), no unchecked indexing, no.expect()in production code. - When iterating or slicing, always validate bounds or use safe alternatives like
.get().
Architecture Patterns
Adding a New Command
- Add a variant to the
Commandsenum incrates/cli/src/cli/ - Create a handler function in
crates/cli/src/<domain>/ - Wire it in the
match cli.command { ... }block inmain.rs - Mark commands that require internet access in the
needs_internetmatch block
Adding a New API Call
- Add or update the request/response types in
crates/smbcloud-model/src/ - Implement the call in the relevant
crates/smbcloud-networking-*/src/crate usingSmbClient - Call the networking function from the CLI command handler
Environment & Auth
- The
Environmenttype (fromsmbcloud-network) is threaded through all command handlers — always accept it as the first parameter. - Auth tokens are managed through the
tokenmodule — never hardcode credentials. - The
CLI_CLIENT_SECRETcomes from the.envfile viadotenv_codegenat compile time.
Terminal Output
- Use the
uimodule helpers for consistent spinner, progress, and styled output. - Use
console::style(...)for coloured terminal text. - Errors are printed in red with a
✘prefix (handled inmain.rs).
Build & Test Commands
# Verify compilation across the whole workspace
cargo check --workspace
# Build release binary
cargo build --release
# Run all tests
cargo test --all-features
# Lint — treat warnings as errors
cargo clippy --workspace --tests -- -D warnings
# Format
cargo fmt --all
# Check formatting without modifying files
cargo fmt --all -- --check
# Publish all workspace crates (requires cargo-workspaces)
cargo workspaces publish --publish-as-is
Common Pitfalls
.envmust exist withCLI_CLIENT_SECRETbefore building. CI generates it from secrets; locally you must create it manually.- No
mod.rs— always use named files for submodules. - All new dependencies go in the root
Cargo.tomlunder[workspace.dependencies], then inherit them in each crate with{ workspace = true }. #[tokio::main]lives only inmain.rs— all other async entry points are plainasync fn.- The binary is named
smb, notsmbcloud-cli— it comes from[[bin]] name = "smb"incrates/cli/Cargo.toml. SmbClientis a zero-cost static reference — obtain it with theclient()helper inlib.rs, don't construct it ad-hoc.- Do not add crate-local dependencies without first checking the workspace root — duplicate version declarations break the workspace resolver.
Pull Request Conventions
- Use a clear, imperative PR title:
Fix crash when project name is empty, notfixed stuff. - No conventional-commit prefixes (
feat:,fix:, etc.) in the PR title. - Include a
Release Notes:section at the end of the PR body: ``` Release Notes:
- Fixed ...
``
Use- N/A` for non-user-facing changes.