This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Prerequisites: Rust (latest stable), Bun
# Install dependencies
bun install
# Run in development mode
bun run tauri dev
# If cmake error on macOS:
CMAKE_POLICY_VERSION_MINIMUM=3.5 bun run tauri dev
# Build for production
bun run tauri build
# Linting and formatting (run before committing)
bun run lint # ESLint for frontend
bun run lint:fix # ESLint with auto-fix
bun run format # Prettier + cargo fmt
bun run format:check # Check formatting without changesModel Setup (Required for Development):
mkdir -p src-tauri/resources/models
curl -o src-tauri/resources/models/silero_vad_v4.onnx https://blob.handy.computer/silero_vad_v4.onnxHandy is a cross-platform desktop speech-to-text app built with Tauri 2.x (Rust backend + React/TypeScript frontend).
lib.rs- Main entry point, Tauri setup, manager initializationmanagers/- Core business logic:audio.rs- Audio recording and device managementmodel.rs- Model downloading and managementtranscription.rs- Speech-to-text processing pipelinehistory.rs- Transcription history storage
audio_toolkit/- Low-level audio processing:audio/- Device enumeration, recording, resamplingvad/- Voice Activity Detection (Silero VAD)
commands/- Tauri command handlers for frontend communicationshortcut.rs- Global keyboard shortcut handlingsettings.rs- Application settings management
App.tsx- Main component with onboarding flowcomponents/settings/- Settings UI (35+ files)components/model-selector/- Model management interfacecomponents/onboarding/- First-run experiencehooks/useSettings.ts,useModels.ts- State management hooksstores/settingsStore.ts- Zustand store for settingsbindings.ts- Auto-generated Tauri type bindings (via tauri-specta)overlay/- Recording overlay window code
Manager Pattern: Core functionality organized into managers (Audio, Model, Transcription) initialized at startup and managed via Tauri state.
Command-Event Architecture: Frontend → Backend via Tauri commands; Backend → Frontend via events.
Pipeline Processing: Audio → VAD → Whisper/Parakeet → Text output → Clipboard/Paste
State Flow: Zustand → Tauri Command → Rust State → Persistence (tauri-plugin-store)
All user-facing strings must use i18next translations. ESLint enforces this (no hardcoded strings in JSX).
Adding new text:
- Add key to
src/i18n/locales/en/translation.json - Use in component:
const { t } = useTranslation(); t('key.path')
File structure:
src/i18n/
├── index.ts # i18n setup
├── languages.ts # Language metadata
└── locales/
├── en/translation.json # English (source)
├── es/translation.json # Spanish
├── fr/translation.json # French
└── vi/translation.json # Vietnamese
Rust:
- Run
cargo fmtandcargo clippybefore committing - Handle errors explicitly (avoid unwrap in production)
- Use descriptive names, add doc comments for public APIs
TypeScript/React:
- Strict TypeScript, avoid
anytypes - Functional components with hooks
- Tailwind CSS for styling
- Path aliases:
@/→./src/
Use conventional commits:
feat:new featuresfix:bug fixesdocs:documentationrefactor:code refactoringchore:maintenance
Access debug features: Cmd+Shift+D (macOS) or Ctrl+Shift+D (Windows/Linux)
- macOS: Metal acceleration, accessibility permissions required
- Windows: Vulkan acceleration, code signing
- Linux: OpenBLAS + Vulkan, limited Wayland support, overlay disabled by default