# Contributing to Hollow Thanks for wanting to help. Hollow is meant to give people private, distributed communication they can trust and check for themselves. ## Before you start - **Open an issue first.** If you want to add a feature or make a bigger change, open an issue to talk it through before you write code, so you don't spend time on something that doesn't fit where the project is going. - **Bug fixes and small improvements** can go straight to a pull request. - **Read the [Whitepaper](WHITEPAPER.md)** if you're touching cryptography, networking, or sync logic. It explains the protocol design and why it is the way it is. ## Setting up the project [BUILDING.md](BUILDING.md) covers what each platform needs (Windows, macOS, Linux, Android and iOS) and how to build it. ### Running Rust tests ```bash cd rust/hollow_core cargo test --lib cargo clippy ``` On Windows the test binary loads OpenSSL's DLLs at startup, so put `C:\Program Files\OpenSSL-Win64\bin` on `PATH` first, or it exits with `STATUS_DLL_NOT_FOUND`. ### Regenerating FFI bindings After any changes to files in `rust/hollow_core/src/api/`, regenerate bindings from the **project root** (not from inside `rust/hollow_core/`): ```bash flutter_rust_bridge_codegen generate --rust-input "crate::api" --rust-root "rust/hollow_core" --dart-output "lib/src/rust" ``` ## Project structure | Directory | Language | What it does | |-----------|----------|--------------| | `lib/` | Dart | Flutter UI, state management (Riverpod), app logic | | `rust/hollow_core/` | Rust | Networking, cryptography, CRDTs, storage engine | | `relay-uws/` | C++ | Production relay server (uWebSockets, MIT licensed) | Rust handles everything security-critical. Dart handles the user interface. They communicate through FFI bindings generated by `flutter_rust_bridge`. ## Writing code ### Rust - Follow `cargo clippy` recommendations. - Add `#[serde(default)]` to any new field on a persisted struct (e.g., `ServerState`). Without it, old data missing the new field silently fails to deserialize. - New `MessageEnvelope` variants go in the appropriate `handle_envelope_*()` handler module, not in `swarm.rs` directly. - Unit tests go in `#[cfg(test)]` modules within the same file (standard Rust convention). ### Dart/Flutter - Follow `flutter_lints` / `analysis_options.yaml`. - Use `ConsumerWidget` or `ConsumerStatefulWidget` to access Riverpod state. Never pass `WidgetRef` as a constructor parameter. - Use the Hollow design system components (`HollowButton`, `HollowTextField`, `HollowDialog`, etc.) instead of raw Material widgets. - Use `AnimatedOpacity` for opacity animations, never the `Opacity` widget. - Text people see in the app uses sentence case for settings labels and never contains an em dash. The full design rules are in [HOLLOW_DESIGN_LANGUAGE.md](reports/reference/HOLLOW_DESIGN_LANGUAGE.md). ### General - Don't add comments explaining what code does. Only comment when the *why* is non-obvious. - Don't introduce abstractions beyond what the task requires. - Never commit secrets, keys, or credentials. ## Submitting a pull request 1. Fork the repository and create a branch from `main`. 2. Make your changes. Keep the diff focused, one concern per PR. 3. Run `cargo test --lib` and `cargo clippy` for Rust changes. 4. Run `flutter analyze` for Dart changes. 5. Write a clear PR description: what changed, why, and how you tested it. 6. Submit the pull request against `main`. ## Reporting security vulnerabilities If you find a security issue, **do not open a public issue**. See [SECURITY.md](SECURITY.md) for how to report vulnerabilities privately. ## License By contributing, you agree that your contributions will be licensed under the [AGPL-3.0 License](LICENSE) (client and core) or [MIT License](relay-uws/LICENSE) (relay), matching the component you're contributing to.