Skip to main content
This guide covers the development workflow, build commands, and distribution packaging for Handhold.

Development Workflow

Running in Development Mode

The development server provides hot reload for both frontend and backend:
bun tauri dev
This command:
  1. Starts Vite dev server on http://localhost:5173
  2. Compiles Rust backend in debug mode
  3. Launches the Tauri app window
  4. Watches for file changes
Frontend changes (TypeScript, React, CSS) apply instantly via Vite HMR. Backend changes (Rust files) trigger a full recompile, which takes 10-30 seconds depending on your machine.

Development Tips

Keep the terminal output visible. Rust compilation errors and Tauri runtime errors appear here.
The dev build is significantly slower than production. Use it for development only.

Opening DevTools

To inspect the frontend or debug JavaScript:
Press Cmd+Option+I or right-click and select “Inspect Element”

Rust Logging

Tauri logs Rust backend output to the terminal. Use standard Rust debugging:
println!("Debug: {:?}", value);
eprintln!("Error: {}", error);
For more structured logging, consider adding the log and env_logger crates.

Frontend-Only Development

If you’re only working on UI components that don’t require backend features, you can run Vite standalone:
bun run dev
This is faster than bun tauri dev but won’t have access to Tauri APIs.

Production Builds

Build Command

To create a production build:
bun tauri build
This:
  1. Runs bun run build to compile the frontend
  2. Compiles Rust in release mode with optimizations
  3. Bundles everything into a platform-native installer
  4. Outputs the installer to src-tauri/target/release/bundle/

Build Artifacts

  • .dmg disk image installer
  • .app bundle in target/release/bundle/macos/
The DMG is code-signed if you have a Developer ID certificate. Otherwise, it’s unsigned and will require users to bypass Gatekeeper.

Build Options

Debug Build (Faster, Larger)

cargo build --manifest-path src-tauri/Cargo.toml
This compiles Rust without optimizations. Useful for debugging crashes.

Release Build (Optimized)

cargo build --release --manifest-path src-tauri/Cargo.toml
Full optimizations enabled. This is what bun tauri build uses.

Configuration

Tauri Config

Location: src-tauri/tauri.conf.json Key settings:
{
  "productName": "Handhold",
  "version": "0.2.13",
  "identifier": "com.handhold.app",
  "build": {
    "beforeDevCommand": "bun run dev",
    "beforeBuildCommand": "bun run build",
    "devUrl": "http://localhost:5173",
    "frontendDist": "../dist"
  }
}
  • beforeDevCommand: Runs before dev mode (starts Vite)
  • beforeBuildCommand: Runs before production build (builds frontend)
  • devUrl: Dev server URL
  • frontendDist: Production build output directory

Version Bumping

Update the version in three places:
  1. package.json (frontend)
  2. src-tauri/Cargo.toml (backend)
  3. src-tauri/tauri.conf.json (Tauri config)
Then rebuild:
bun tauri build

Cross-Platform Builds

Building for Multiple Platforms

Tauri requires native builds on each platform. You cannot cross-compile from macOS to Windows, for example. To build for all platforms:
  1. Build on macOS for macOS (ARM + Intel via universal binary)
  2. Build on Linux for Linux
  3. Build on Windows for Windows
The official release workflow uses GitHub Actions to automate this.

Universal macOS Binaries

To build a universal binary (ARM + Intel):
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
bun tauri build --target universal-apple-darwin

Sidecar Binaries

Handhold bundles the Kokoro TTS binary as a sidecar. The binary must match the target platform:
  • macOS ARM: koko-aarch64-apple-darwin
  • macOS Intel: koko-x86_64-apple-darwin
  • Linux: koko-x86_64-unknown-linux-gnu
  • Windows: koko-x86_64-pc-windows-msvc.exe
Tauri automatically selects the correct binary based on the build target. Sidecar location: src-tauri/binaries/

Bundled Resources

The following resources are packaged into the installer:
  • src-tauri/resources/models/ - TTS voice models
  • src-tauri/resources/espeak-ng-data/ - Phoneme data
These are specified in tauri.conf.json:
{
  "bundle": {
    "resources": [
      "resources/models/",
      "resources/espeak-ng-data/"
    ]
  }
}

Testing Builds Locally

After building, test the installer:
Open the .dmg and drag the app to Applications. Then run it from Applications.If unsigned, macOS will block it. Right-click the app and select “Open” to bypass Gatekeeper.

Continuous Integration

The project includes a GitHub Actions workflow that:
  1. Runs on every push to main
  2. Builds on macOS, Linux, and Windows runners
  3. Runs tests (when available)
  4. Uploads build artifacts
Workflow file: .github/workflows/ci.yml

Release Process

To trigger a release build:
1

Bump version

Update version in package.json, Cargo.toml, and tauri.conf.json.
2

Commit and tag

git add .
git commit -m "chore: bump version to v0.3.0"
git tag v0.3.0
git push origin main --tags
3

Wait for CI

GitHub Actions automatically builds for all platforms and creates a draft release.
4

Publish release

Go to the GitHub Releases page, review the draft, and click “Publish”.
Release workflow: .github/workflows/release.yml The workflow builds:
  • .dmg for macOS (ARM + Intel universal)
  • .AppImage and .deb for Linux
  • .msi and .exe for Windows
All artifacts are uploaded to the GitHub Release.

Troubleshooting

Build fails with “Cargo.lock is out of date”

cd src-tauri
cargo update

Frontend build fails

Clear Vite cache:
rm -rf node_modules/.vite dist
bun run build

Sidecar binary not found

Ensure the TTS binary exists:
ls -l src-tauri/binaries/
Re-run the setup script:
bash scripts/install.sh

Rust compilation is slow

Enable faster linking (Linux/macOS):
brew install llvm  # macOS
sudo apt-get install lld  # Linux
Add to ~/.cargo/config.toml:
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=lld"]

[target.x86_64-apple-darwin]
rustflags = ["-C", "link-arg=-fuse-ld=lld"]

Next Steps

Contributing

Learn how to contribute to Handhold

Frontend

Explore the React frontend

Backend

Dive into the Rust backend

Architecture

Understand the system design

Build docs developers (and LLMs) love