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:

DirectoryWhat 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, run pnpm tauri dev, and it regenerates. Commands and events are registered in src-tauri/src/setup.rs.
  • Zustand selectors must not derive new arrays or objects — that causes infinite re-renders. Wrap in useShallow if you need to. pnpm check:zustand-access enforces it.
  • Don't touch the libp2p pin. libp2p and friends are pinned to a specific rev of a fork; the reasons and the exit conditions are documented in Cargo.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.json is the source of truth, with package.json and src-tauri/Cargo.toml following. Mobile: mobile/app.json leads, mobile/package.json follows. CI verifies this.
  • New UI strings go through Lingui (pnpm i18n:extract, source locale zh). 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/core has no sea-orm.
  • crates/transfer does not depend on crates/core (it does depend on the network layer).
  • crates/invite does not depend on crates/core.
  • libp2p types are wrapped into newtypes in crates/net-base and 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, not main. main is the release branch.
  • Use Conventional Commitsfeat:, 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.