feature/sdk-npm
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
| 1 | --- |
| 2 | name: smbcloud-deploy-rsync |
| 3 | description: Use when implementing or debugging smbCloud's generic rsync-based deployment path in `smbcloud-cli`, especially `rsync_deploy.rs`, workspace dependency wiring, SSH identity handling, remote path normalization, and parity with shell rsync commands like `rsync -a source/ host:path/`. |
| 4 | --- |
| 5 | |
| 6 | # smbCloud Deploy Rsync |
| 7 | |
| 8 | Use this skill when work is about smbCloud's generic rsync deploy path in the Rust CLI, not the specialized Next.js SSR flow. |
| 9 | |
| 10 | Applies to: |
| 11 | |
| 12 | - `crates/cli/src/deploy/rsync_deploy.rs` |
| 13 | - workspace dependency wiring in `Cargo.toml` |
| 14 | - embedding the Rust rsync crate instead of shelling out to system `rsync` |
| 15 | - reproducing command semantics like `rsync -a source/ host:path/` |
| 16 | - SSH key and remote destination handling for smbCloud runners |
| 17 | |
| 18 | ## Scope boundary |
| 19 | |
| 20 | This skill is for the generic rsync deploy implementation in `smbcloud-cli`. |
| 21 | |
| 22 | Do not use it for: |
| 23 | |
| 24 | - `kind = "nextjs-ssr"` local-build deploys |
| 25 | - PM2 restart logic for standalone Next.js bundles |
| 26 | - Nginx config for SSR apps |
| 27 | |
| 28 | Those belong to the Next.js deploy skill. |
| 29 | |
| 30 | ## Target behavior |
| 31 | |
| 32 | The baseline command to replicate is: |
| 33 | |
| 34 | ```sh |
| 35 | rsync -a 5mb-dot-app/ rsync-deploy-id-11:apps/web/5mb.app/ |
| 36 | ``` |
| 37 | |
| 38 | Important semantics: |
| 39 | |
| 40 | - trailing slash on the source means copy the contents of the directory |
| 41 | - trailing slash on the destination means sync into that directory |
| 42 | - archive mode preserves the usual rsync metadata behavior |
| 43 | - the remote target is `host:path`, not a local filesystem path |
| 44 | |
| 45 | When implementing in Rust, preserve these semantics explicitly. Do not assume path handling will match shell rsync unless you normalize it yourself. |
| 46 | |
| 47 | ## Current smbCloud conventions |
| 48 | |
| 49 | Generic rsync deploy uses smbCloud config and runner metadata. |
| 50 | |
| 51 | Expect these responsibilities: |
| 52 | |
| 53 | - get the logged-in smbCloud user |
| 54 | - resolve the SSH identity path from `Config::ssh_key_path(user.id)` |
| 55 | - determine the runner host, usually through `runner.rsync_host()` |
| 56 | - build the remote destination from configured project `path` |
| 57 | - deploy the current source tree or configured source directory |
| 58 | |
| 59 | The user-visible output may still mention the SSH key path. Preserve useful diagnostics, but avoid misleading claims about git deploy. |
| 60 | |
| 61 | ## Dependency wiring |
| 62 | |
| 63 | When the task is to replace shell `rsync` with the Rust embedding crate: |
| 64 | |
| 65 | 1. add the upstream rsync embedding crate at the workspace root `Cargo.toml` |
| 66 | 2. add it as a workspace dependency in the consuming crate |
| 67 | 3. wire only the minimal surface needed by `rsync_deploy.rs` |
| 68 | |
| 69 | Prefer the embedding crate over copying CLI subprocess behavior when the goal is portability or tighter control. |
| 70 | |
| 71 | Before coding, inspect: |
| 72 | |
| 73 | - the embedding crate API surface |
| 74 | - whether it supports client mode directly |
| 75 | - how stdout/stderr and exit status are reported |
| 76 | - how remote-shell transport is configured, if at all |
| 77 | |
| 78 | If the crate cannot actually express `host:path` SSH transport parity, say so explicitly instead of forcing a partial migration. |
| 79 | |
| 80 | ## Implementation guidance |
| 81 | |
| 82 | ### Path normalization |
| 83 | |
| 84 | Be precise with trailing slashes. |
| 85 | |
| 86 | Preferred rule: |
| 87 | |
| 88 | - normalize local source to end with `/` |
| 89 | - normalize remote destination to end with `/` |
| 90 | |
| 91 | That matches the intended `rsync -a source/ host:path/` behavior. |
| 92 | |
| 93 | ### SSH identity |
| 94 | |
| 95 | The CLI currently resolves the private key path from the smbCloud user id. |
| 96 | |
| 97 | If the embedded rsync client still needs an ssh transport command, keep the identity handling equivalent to the current shell behavior. |
| 98 | |
| 99 | Typical concerns: |
| 100 | |
| 101 | - identity file path |
| 102 | - strict host key checking |
| 103 | - known hosts file or pinned host key strategy |
| 104 | - batch mode / no password prompts |
| 105 | |
| 106 | ### Failure reporting |
| 107 | |
| 108 | Preserve actionable errors. |
| 109 | |
| 110 | Good failures include: |
| 111 | |
| 112 | - local source path missing |
| 113 | - remote project path missing in config |
| 114 | - SSH key missing |
| 115 | - embedded client non-zero exit status |
| 116 | - stderr emitted by the transfer implementation |
| 117 | |
| 118 | Do not flatten all deploy failures into a generic message. |
| 119 | |
| 120 | ### Behavior parity |
| 121 | |
| 122 | If replacing subprocess `rsync`, confirm parity for: |
| 123 | |
| 124 | - source contents vs source directory copying |
| 125 | - remote path handling |
| 126 | - recursive transfer |
| 127 | - deletion behavior, if smbCloud depends on it |
| 128 | - stdout/stderr capture |
| 129 | - non-zero status mapping |
| 130 | |
| 131 | ## Validation |
| 132 | |
| 133 | Use small checks first. |
| 134 | |
| 135 | ### Rust |
| 136 | |
| 137 | - `cargo check -p smbcloud-cli` |
| 138 | - targeted tests if added around path normalization or command construction |
| 139 | |
| 140 | ### Behavioral |
| 141 | |
| 142 | Verify the resulting implementation matches the shell command shape conceptually: |
| 143 | |
| 144 | - source `dir/` |
| 145 | - destination `host:path/` |
| 146 | - ssh identity derived from smbCloud config |
| 147 | |
| 148 | If the code still shells out to `rsync`, validate the exact arguments. |
| 149 | If it migrates to the embedding crate, validate equivalent output and error handling. |
| 150 | |
| 151 | ## Common mistakes |
| 152 | |
| 153 | - mixing this generic rsync deploy path with the specialized `nextjs-ssr` flow |
| 154 | - losing trailing slash semantics and copying the wrong directory level |
| 155 | - adding the dependency in one `Cargo.toml` but not wiring the workspace dependency correctly |
| 156 | - assuming the embedding crate automatically supports ssh remote syntax without checking |
| 157 | - hiding transport stderr that the user needs to debug deploy failures |
| 158 | - hardcoding local paths instead of using smbCloud config and user-derived SSH identity |