1 ---
2 name: rust-cross-platform
3 description: Use when building or debugging Rust code that targets multiple platforms or language surfaces, especially Tauri, wasm/npm, UniFFI, Swift/Kotlin bindings, shared SDK crates, deployment-target issues, and environment parity across desktop, mobile, CLI, and web.
4 ---
5
6 # Rust Cross Platform
7
8 Use this skill when a change spans Rust plus any of:
9
10 - Tauri desktop or mobile
11 - wasm or npm packaging
12 - UniFFI-generated Swift/Kotlin bindings
13 - shared SDK crates used by web, native, and CLI clients
14 - Apple platform linker or deployment-target issues
15 - environment-specific credentials or runtime configuration
16
17 ## Default approach
18
19 Treat the Rust crate as the source of truth and keep platform adapters thin.
20
21 Preferred layering:
22
23 1. Shared Rust domain crate
24 2. Platform wrapper crate or binding layer
25 3. App-specific UI or shell code
26
27 Do not duplicate API contracts in TypeScript, Swift, Kotlin, and Rust if the Rust crate can own the contract.
28
29 ## Environment parity
30
31 Always make environment selection explicit.
32
33 Use:
34
35 - an enum in Rust for `development` vs `production`
36 - one place for app ids, hosts, and secrets
37 - thin adapters in Tauri, wasm, or UniFFI to pass the enum through
38
39 Do not let frontend-only checks become the source of truth for runtime mode if Rust owns the actual behavior.
40
41 ## Tauri conventions
42
43 For auth or networking features:
44
45 - keep logic in `src-tauri/src/...`
46 - expose narrow Tauri commands
47 - store session state in plugin-store, not only React state
48 - use Rust for build-mode checks such as `cfg!(debug_assertions)`
49
50 ### macOS
51
52 `tauri.conf.json` `minimumSystemVersion` does not fix `tauri dev`.
53
54 If Swift-linked plugins are present, add `src-tauri/.cargo/config.toml` with:
55
56 - `MACOSX_DEPLOYMENT_TARGET`
57 - `-mmacosx-version-min=...` for `aarch64-apple-darwin`
58 - `-mmacosx-version-min=...` for `x86_64-apple-darwin`
59 - host `CC` and `CXX` if native deps might pick the wrong toolchain
60
61 If runtime fails on `libswift_Concurrency.dylib`, fix Cargo/macOS config before touching app code.
62
63 ## wasm and npm conventions
64
65 For browser-facing Rust SDKs:
66
67 - keep the core logic in a normal Rust crate
68 - expose wasm bindings in a dedicated wrapper crate
69 - make wasm functions explicit and app-oriented
70 - prefer passing primitive strings and enums over complex borrowed structs
71
72 Typical exported operations:
73
74 - `signup_with_client`
75 - `login_with_client`
76 - `me_with_client`
77 - `remove_with_client`
78
79 ### Packaging
80
81 Use `wasm-pack` for npm distribution unless there is a strong reason not to.
82
83 Recommended pattern:
84
85 - Rust crate under `crates/...-wasm`
86 - `wasm-bindgen` exports only the browser surface
87 - README contains exact browser import example
88
89 Do not make the HTML or JS app reimplement request signing or endpoint construction if the Rust crate already owns it.
90
91 ## UniFFI conventions
92
93 Use UniFFI when Swift/Kotlin consumers need a stable SDK surface from Rust.
94
95 Guidelines:
96
97 - keep FFI-safe types small and explicit
98 - avoid leaking internal crate structure into the public interface
99 - prefer stringly transport only at the boundary, not internally
100 - map platform-facing errors into a deliberate error enum
101 - keep async boundaries clear; document whether the caller must dispatch off the main thread
102
103 When designing UniFFI APIs:
104
105 - expose nouns and use cases, not transport details
106 - keep constructors simple
107 - prefer one shared config object if several methods need the same environment or credentials
108
109 ## Shared auth and SDK work
110
111 For auth-backed SDKs:
112
113 - keep account flows in the shared crate
114 - keep app credentials and environment resolution in one place
115 - make desktop, mobile, and web call the same Rust path where possible
116
117 If a web client must use wasm, bind the existing Rust account crate instead of rebuilding the flow in JavaScript.
118
119 ## Validation
120
121 Use the smallest relevant checks.
122
123 ### Rust
124
125 - `cargo check -p <crate>`
126 - `cargo test -p <crate>` when tests exist and are relevant
127
128 ### Tauri
129
130 - `cargo check` in `src-tauri`
131 - frontend build, usually `pnpm build`
132
133 ### wasm
134
135 - `cargo check -p <wasm-crate>`
136 - `wasm-pack build --target web` when packaging behavior changed
137
138 ### UniFFI
139
140 - regenerate bindings if applicable
141 - build at least one native target that consumes the bindings
142
143 ## Common mistakes
144
145 - duplicating business logic in each platform adapter
146 - hiding environment selection in UI-only code
147 - using app secrets in public web clients without noting the security tradeoff
148 - assuming `tauri.conf.json` fixes macOS dev runtime issues
149 - exposing unstable internal Rust types directly through wasm or UniFFI
150 - changing backend error shapes without updating parser code in wrappers