Contributing to SwarmDrop
August 7, 2026 · View on GitHub
Issues and pull requests are welcome. This document covers the things that are not obvious from reading the code — the rest you can figure out as you go.
Getting set up
Requires Node 20+, pnpm 9+ and Rust 1.85+. There are no git submodules; a plain clone is enough.
git clone git@github.com:swarm-apps/SwarmDrop.git
cd SwarmDrop
pnpm install
pnpm tauri dev # desktop app (Vite on :1420 + Rust backend)
pnpm dev # frontend only
pnpm only. npm and yarn will produce a lockfile the CI does not understand.
The repo has four separate pnpm workspaces
This trips up almost everyone. The root workspace does not include these — you have
to pnpm install inside each one:
| Directory | What it is |
|---|---|
docs/ | Documentation site (Next.js + Fumadocs), and it also hosts the browser build |
mobile/ | iOS / Android app (React Native + Expo + uniffi) |
e2e/desktop/ | Desktop end-to-end tests (WebdriverIO) |
video/ | Remotion project for demo footage |
So pnpm test at the root will not run the docs tests — the root vitest config
explicitly excludes docs/**. Run those from inside docs/.
The Cargo workspace is separate again: it covers crates/*, src-tauri, and the mobile
Rust bridge, all from the repo root.
Before you commit
Frontend checks have no CI workflow behind them — this list is their only enforcement:
pnpm exec tsc --noEmit
pnpm test
pnpm check:zustand-access # selector rules, scans src/ and docs/app/app
pnpm check:shared-view # shared package must stay platform-free
pnpm check:clipboard # no direct navigator.clipboard
pnpm check:landing # pairing landing page size budget
# Rust — run from the repo root, covers the whole workspace
cargo fmt --all
cargo check --workspace --all-targets
cargo test --workspace
cargo clippy --workspace
If you touched crates/net, net-base, host, transfer, invite, core or web,
the wasm gate also has to pass — CI will block you otherwise:
./scripts/check-wasm.sh
./scripts/check-wasm.sh --clippy
./scripts/test-wasm.sh # only if you touched crates/web; compiling ≠ passing
Things that will bite you
- Never hand-edit
src/lib/bindings.ts. It is generated by tauri-specta. Change the Rust command or type, runpnpm tauri dev, and it regenerates. Commands and events are registered insrc-tauri/src/setup.rs. - Zustand selectors must not derive new arrays or objects — that causes infinite
re-renders. Wrap in
useShallowif you need to.pnpm check:zustand-accessenforces it. - Don't touch the libp2p pin.
libp2pand friends are pinned to a specific rev of a fork; the reasons and the exit conditions are documented inCargo.toml. Bumping it requires its own PR with a full test run. - Don't add application-layer encryption. Confidentiality is the transport layer's
job, and an extra layer cannot coexist with bao-tree per-chunk verification. See
SECURITY.md. - Version numbers live in more than one place. Desktop:
src-tauri/tauri.conf.jsonis the source of truth, withpackage.jsonandsrc-tauri/Cargo.tomlfollowing. Mobile:mobile/app.jsonleads,mobile/package.jsonfollows. CI verifies this. - New UI strings go through Lingui (
pnpm i18n:extract, source localezh). Native strings — tray, system notifications — use rust-i18n instead.
Architecture boundaries
These are enforced by the wasm build, not by taste. Break one and check-wasm.sh goes red:
crates/corehas nosea-orm.crates/transferdoes not depend oncrates/core(it does depend on the network layer).crates/invitedoes not depend oncrates/core.- libp2p types are wrapped into newtypes in
crates/net-baseand do not leak upward.
src-tauri/src/commands/ is a thin shell: parse arguments, take state, call a manager.
Business logic belongs in crates/*.
Pull requests
- Branch off
develop, notmain.mainis the release branch. - Use Conventional Commits —
feat:,fix:,docs:,chore:and so on. - Keep unrelated changes in separate commits. It makes review and reverts much easier.
- Explain why in the commit body when the change isn't self-evident. The repo's history is used as documentation.
Larger or cross-cutting changes are usually worth an issue first, so we can agree on the shape before you write it.
Documentation
Architecture lives in CLAUDE.md — it is the single source of truth for how the repo is
laid out, and it should be updated alongside structural changes. Deeper notes on specific
subsystems are in dev-notes/knowledge/.
Code of conduct
Participation is governed by CODE_OF_CONDUCT.md.