Skip to content

Build from source

Everything in Tealhand builds from the repository with a stable Rust toolchain. There are no prebuilt packages yet.

  • Rust 1.99.1, pinned in rust-toolchain.toml with the clippy and rustfmt components. rustup installs it on first use in the repository. The workspace uses edition 2024 and rust-version = "1.99".
  • Git, and a C toolchain for your platform (Visual Studio C++ build tools on Windows).
Terminal window
git clone https://github.com/tealvpn/tealhand
cd tealhand
rustup toolchain install # reads rust-toolchain.toml
Terminal window
cargo build --release -p tealhand-host # target/release/tealhand-host
cargo build --release -p tealhand-relay # target/release/tealhand-relay
cargo build --release -p tealhand-planner # target/release/tealhand-planner
cargo build --workspace # everything, debug

CI runs these on every pull request and on every push to main, on Ubuntu and Windows, and weekly. Run scripts/ci-local.sh before you push: it runs all of them (and the Android and Flutter checks when those tools are installed) and stops at the first failure. The steps by hand:

Terminal window
cargo fmt --check
cargo clippy --locked --workspace --all-targets -- -D warnings
cargo test --locked --workspace
cargo deny --locked check # licences, bans, sources, advisories
cargo audit --file Cargo.lock # known vulnerabilities
bash scripts/geiger-check.sh # no unsafe outside the isolated crates

CI pins cargo-deny 0.20.2, cargo-audit 0.22.2 and cargo-geiger 0.14.0:

Terminal window
cargo install --locked cargo-deny@0.20.2
cargo install --locked cargo-audit@0.22.2
cargo install --locked cargo-geiger@0.14.0

scripts/geiger-check.sh works in Git Bash on Windows and on Linux. It fails when a crate outside the isolated list mentions unsafe or unsafe_code, uses include! or #[path], or does not inherit the workspace lints; it then prints a cargo geiger total per crate as a report.

The full list of checks, including the ones for the Android bridge and the Flutter app, with a guide to adding a feature, is in How a feature is made.

Use WSL with Ubuntu for anything Linux-specific (the Linux side of Tealhand Host, fuzzing). Work on the Linux file system, not under /mnt/c, where builds are slow.

Every parser that reads bytes from another device has a fuzz target in fuzz/, its own Cargo workspace. It needs the nightly compiler and runs on Linux only (WSL on Windows). CI does not run it yet.

Terminal window
rustup toolchain install nightly
cargo install --locked cargo-fuzz
cd fuzz
cargo +nightly fuzz list
cargo +nightly fuzz run proto_frame -- -max_total_time=60 -max_len=70000
Target What it feeds
proto_frame read_frame and every message body decoder
roster_decode SignedRoster::decode and verify
signed_command_decode SignedCommand::decode and Verifier::verify
pair_messages The pair/1 messages into both connection state machines
qr_uri PairQr::from_uri

Set -max_len a little above the parser’s own cap (64 KiB for frames) so the cap check is exercised. A crash you fix becomes a unit test in the crate.

apps/mobile is the phone app: Flutter screens over the Rust core through the bridge. To build and install it, see Install the phone app.

  • After changing crates/tealhand-ffi/src/api.rs, regenerate the bridge in apps/mobile with flutter_rust_bridge_codegen generate. The codegen, the flutter_rust_bridge crate and the Dart package are all pinned to 2.13.0. It writes lib/src/rust/ and crates/tealhand-ffi/src/frb_generated.rs; run cargo fmt after it and commit both.
  • Android libraries: tool/android_libs.sh [--release] builds the three Android ABIs with cargo-ndk into android/app/src/main/jniLibs/ (not committed).
  • Checks: flutter analyze, and flutter test after cargo build -p tealhand-ffi (the test loads the host’s target/debug/tealhand_ffi library).

The documentation site lives in docs-site/ (Astro with Starlight). See docs-site/README.md for how to preview and build it.