docs: unify CLAUDE.md and AGENTS.md into single source of truth (#1272)
Merge content from both files into AGENTS.md, making it the single source of truth for all AI coding assistants. CLAUDE.md now references AGENTS.md via `Read @AGENTS.md` directive. Kept existing architecture/technical descriptions as-is to avoid a separate review cycle. Added sections: linting/formatting commands, i18n, code style, commit guidelines, CLI parameters, debug mode, platform notes, troubleshooting reference, and explicit links to CONTRIBUTING.md, CONTRIBUTING_TRANSLATIONS.md, and PR template.
This commit is contained in:
parent
11311bee0e
commit
564fbc84df
2 changed files with 128 additions and 186 deletions
154
AGENTS.md
154
AGENTS.md
|
|
@ -1,6 +1,6 @@
|
||||||
# AGENTS.md
|
# AGENTS.md
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
This file provides guidance to AI coding assistants working with code in this repository.
|
||||||
|
|
||||||
## Development Commands
|
## Development Commands
|
||||||
|
|
||||||
|
|
@ -29,51 +29,74 @@ bun run build # Build frontend (TypeScript + Vite)
|
||||||
bun run preview # Preview built frontend
|
bun run preview # Preview built frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Linting and Formatting (run before committing):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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 changes
|
||||||
|
bun run format:frontend # Prettier only
|
||||||
|
bun run format:backend # cargo fmt only
|
||||||
|
```
|
||||||
|
|
||||||
**Model Setup (Required for Development):**
|
**Model Setup (Required for Development):**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create models directory
|
|
||||||
mkdir -p src-tauri/resources/models
|
mkdir -p src-tauri/resources/models
|
||||||
|
|
||||||
# Download required VAD model
|
|
||||||
curl -o src-tauri/resources/models/silero_vad_v4.onnx https://blob.handy.computer/silero_vad_v4.onnx
|
curl -o src-tauri/resources/models/silero_vad_v4.onnx https://blob.handy.computer/silero_vad_v4.onnx
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For detailed platform-specific build setup, see [BUILD.md](BUILD.md).
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
Handy is a cross-platform desktop speech-to-text application built with Tauri (Rust backend + React/TypeScript frontend).
|
Handy is a cross-platform desktop speech-to-text application built with Tauri 2.x (Rust backend + React/TypeScript frontend).
|
||||||
|
|
||||||
### Core Components
|
### Backend Structure (src-tauri/src/)
|
||||||
|
|
||||||
**Backend (Rust - src-tauri/src/):**
|
- `lib.rs` - Main entry point, Tauri setup, manager initialization
|
||||||
|
- `managers/` - Core business logic:
|
||||||
- `lib.rs` - Main application entry point with Tauri setup, tray menu, and managers
|
|
||||||
- `managers/` - Core business logic managers:
|
|
||||||
- `audio.rs` - Audio recording and device management
|
- `audio.rs` - Audio recording and device management
|
||||||
- `model.rs` - Whisper model downloading and management
|
- `model.rs` - Model downloading and management
|
||||||
- `transcription.rs` - Speech-to-text processing pipeline
|
- `transcription.rs` - Speech-to-text processing pipeline
|
||||||
|
- `history.rs` - Transcription history storage
|
||||||
- `audio_toolkit/` - Low-level audio processing:
|
- `audio_toolkit/` - Low-level audio processing:
|
||||||
- `audio/` - Device enumeration, recording, resampling
|
- `audio/` - Device enumeration, recording, resampling
|
||||||
- `vad/` - Voice Activity Detection using Silero VAD
|
- `vad/` - Voice Activity Detection (Silero VAD)
|
||||||
- `commands/` - Tauri command handlers for frontend communication
|
- `commands/` - Tauri command handlers for frontend communication
|
||||||
|
- `cli.rs` - CLI argument definitions (clap derive)
|
||||||
- `shortcut.rs` - Global keyboard shortcut handling
|
- `shortcut.rs` - Global keyboard shortcut handling
|
||||||
- `settings.rs` - Application settings management
|
- `settings.rs` - Application settings management
|
||||||
|
- `overlay.rs` - Recording overlay window (platform-specific)
|
||||||
|
- `signal_handle.rs` - `send_transcription_input()` reusable function
|
||||||
|
- `utils.rs` - Platform detection helpers
|
||||||
|
|
||||||
**Frontend (React/TypeScript - src/):**
|
### Frontend Structure (src/)
|
||||||
|
|
||||||
- `App.tsx` - Main application component with onboarding flow
|
- `App.tsx` - Main component with onboarding flow
|
||||||
- `components/settings/` - Settings UI components
|
- `components/` - React UI components:
|
||||||
- `components/model-selector/` - Model management interface
|
- `settings/` - Settings UI
|
||||||
- `hooks/` - React hooks for settings and model management
|
- `model-selector/` - Model management interface
|
||||||
|
- `onboarding/` - First-run experience
|
||||||
|
- `overlay/` - Recording overlay UI
|
||||||
|
- `update-checker/` - App update notifications
|
||||||
|
- `shared/`, `ui/`, `icons/`, `footer/` - Shared components
|
||||||
|
- `hooks/useSettings.ts` - Settings state management hook
|
||||||
|
- `stores/settingsStore.ts` - Zustand store for settings
|
||||||
|
- `bindings.ts` - Auto-generated Tauri type bindings (via tauri-specta)
|
||||||
|
- `overlay/` - Recording overlay window entry point
|
||||||
- `lib/types.ts` - Shared TypeScript type definitions
|
- `lib/types.ts` - Shared TypeScript type definitions
|
||||||
|
|
||||||
### Key Architecture Patterns
|
### Key Architecture Patterns
|
||||||
|
|
||||||
**Manager Pattern:** Core functionality is organized into managers (Audio, Model, Transcription) that are initialized at startup and managed by Tauri's state system.
|
**Manager Pattern:** Core functionality organized into managers (Audio, Model, Transcription) initialized at startup and managed via Tauri state.
|
||||||
|
|
||||||
**Command-Event Architecture:** Frontend communicates with backend via Tauri commands, backend sends updates via events.
|
**Command-Event Architecture:** Frontend → Backend via Tauri commands; Backend → Frontend via events.
|
||||||
|
|
||||||
**Pipeline Processing:** Audio → VAD → Whisper → Text output with configurable components at each stage.
|
**Pipeline Processing:** Audio → VAD → Whisper/Parakeet → Text output → Clipboard/Paste
|
||||||
|
|
||||||
|
**State Flow:** Zustand → Tauri Command → Rust State → Persistence (tauri-plugin-store)
|
||||||
|
|
||||||
### Technology Stack
|
### Technology Stack
|
||||||
|
|
||||||
|
|
@ -86,12 +109,6 @@ Handy is a cross-platform desktop speech-to-text application built with Tauri (R
|
||||||
- `rubato` - Audio resampling
|
- `rubato` - Audio resampling
|
||||||
- `rodio` - Audio playback for feedback sounds
|
- `rodio` - Audio playback for feedback sounds
|
||||||
|
|
||||||
**Platform-Specific Features:**
|
|
||||||
|
|
||||||
- macOS: Metal acceleration for Whisper, accessibility permissions
|
|
||||||
- Windows: Vulkan acceleration, code signing
|
|
||||||
- Linux: OpenBLAS + Vulkan acceleration
|
|
||||||
|
|
||||||
### Application Flow
|
### Application Flow
|
||||||
|
|
||||||
1. **Initialization:** App starts minimized to tray, loads settings, initializes managers
|
1. **Initialization:** App starts minimized to tray, loads settings, initializes managers
|
||||||
|
|
@ -111,4 +128,87 @@ Settings are stored using Tauri's store plugin with reactive updates:
|
||||||
|
|
||||||
### Single Instance Architecture
|
### Single Instance Architecture
|
||||||
|
|
||||||
The app enforces single instance behavior - launching when already running brings the settings window to front rather than creating a new process.
|
The app enforces single instance behavior — launching when already running brings the settings window to front rather than creating a new process. Remote control flags (`--toggle-transcription`, etc.) work by launching a second instance that sends args to the running instance via `tauri_plugin_single_instance`, then exits.
|
||||||
|
|
||||||
|
## Internationalization (i18n)
|
||||||
|
|
||||||
|
All user-facing strings must use i18next translations. ESLint enforces this (no hardcoded strings in JSX).
|
||||||
|
|
||||||
|
**Adding new text:**
|
||||||
|
|
||||||
|
1. Add key to `src/i18n/locales/en/translation.json`
|
||||||
|
2. 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)
|
||||||
|
├── de/, es/, fr/, ja/, ru/, zh/, ...
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
For translation contribution guidelines, see [CONTRIBUTING_TRANSLATIONS.md](CONTRIBUTING_TRANSLATIONS.md).
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
**Rust:**
|
||||||
|
|
||||||
|
- Run `cargo fmt` and `cargo clippy` before committing
|
||||||
|
- Handle errors explicitly (avoid unwrap in production)
|
||||||
|
- Use descriptive names, add doc comments for public APIs
|
||||||
|
|
||||||
|
**TypeScript/React:**
|
||||||
|
|
||||||
|
- Strict TypeScript, avoid `any` types
|
||||||
|
- Functional components with hooks
|
||||||
|
- Tailwind CSS for styling
|
||||||
|
- Path aliases: `@/` → `./src/`
|
||||||
|
|
||||||
|
## Commit Guidelines
|
||||||
|
|
||||||
|
Use conventional commits: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
||||||
|
|
||||||
|
## CLI Parameters
|
||||||
|
|
||||||
|
Handy supports command-line parameters on all platforms for integration with scripts, window managers, and autostart configurations.
|
||||||
|
|
||||||
|
**Implementation:** `cli.rs` (definitions), `main.rs` (parsing), `lib.rs` (applying), `signal_handle.rs` (shared logic)
|
||||||
|
|
||||||
|
| Flag | Description |
|
||||||
|
| ------------------------ | -------------------------------------------------------------- |
|
||||||
|
| `--toggle-transcription` | Toggle recording on/off on a running instance |
|
||||||
|
| `--toggle-post-process` | Toggle recording with post-processing on/off |
|
||||||
|
| `--cancel` | Cancel the current operation on a running instance |
|
||||||
|
| `--start-hidden` | Launch without showing the main window (tray icon visible) |
|
||||||
|
| `--no-tray` | Launch without system tray (closing window quits the app) |
|
||||||
|
| `--debug` | Enable debug mode with verbose (Trace) logging |
|
||||||
|
|
||||||
|
**Key design decisions:**
|
||||||
|
|
||||||
|
- CLI flags are runtime-only overrides — they do NOT modify persisted settings
|
||||||
|
- Remote control flags work via `tauri_plugin_single_instance`: second instance sends args, then exits
|
||||||
|
- `send_transcription_input()` in `signal_handle.rs` is shared between signal handlers and CLI
|
||||||
|
|
||||||
|
## Debug Mode
|
||||||
|
|
||||||
|
Access debug features: `Cmd+Shift+D` (macOS) or `Ctrl+Shift+D` (Windows/Linux)
|
||||||
|
|
||||||
|
## Platform Notes
|
||||||
|
|
||||||
|
- **macOS**: Metal acceleration, accessibility permissions required for keyboard shortcuts
|
||||||
|
- **Windows**: Vulkan acceleration, code signing
|
||||||
|
- **Linux**: OpenBLAS + Vulkan, limited Wayland support, overlay uses GTK layer shell (disable with `HANDY_NO_GTK_LAYER_SHELL=1`)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
See the [Troubleshooting](README.md#troubleshooting) section in README.md.
|
||||||
|
|
||||||
|
## Contributing & PR Guidelines
|
||||||
|
|
||||||
|
Follow [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow and [PR template](.github/PULL_REQUEST_TEMPLATE.md) when submitting pull requests. For translations, see [CONTRIBUTING_TRANSLATIONS.md](CONTRIBUTING_TRANSLATIONS.md).
|
||||||
|
|
||||||
|
**Note:** Feature freeze is active — bug fixes are top priority. New features require community support via [Discussions](https://github.com/cjpais/Handy/discussions).
|
||||||
|
|
|
||||||
160
CLAUDE.md
160
CLAUDE.md
|
|
@ -1,159 +1 @@
|
||||||
# CLAUDE.md
|
Read @AGENTS.md
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
||||||
|
|
||||||
## Development Commands
|
|
||||||
|
|
||||||
**Prerequisites:** [Rust](https://rustup.rs/) (latest stable), [Bun](https://bun.sh/)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 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 changes
|
|
||||||
```
|
|
||||||
|
|
||||||
**Model Setup (Required for Development):**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p src-tauri/resources/models
|
|
||||||
curl -o src-tauri/resources/models/silero_vad_v4.onnx https://blob.handy.computer/silero_vad_v4.onnx
|
|
||||||
```
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
Handy is a cross-platform desktop speech-to-text app built with Tauri 2.x (Rust backend + React/TypeScript frontend).
|
|
||||||
|
|
||||||
### Backend Structure (src-tauri/src/)
|
|
||||||
|
|
||||||
- `lib.rs` - Main entry point, Tauri setup, manager initialization
|
|
||||||
- `managers/` - Core business logic:
|
|
||||||
- `audio.rs` - Audio recording and device management
|
|
||||||
- `model.rs` - Model downloading and management
|
|
||||||
- `transcription.rs` - Speech-to-text processing pipeline
|
|
||||||
- `history.rs` - Transcription history storage
|
|
||||||
- `audio_toolkit/` - Low-level audio processing:
|
|
||||||
- `audio/` - Device enumeration, recording, resampling
|
|
||||||
- `vad/` - Voice Activity Detection (Silero VAD)
|
|
||||||
- `commands/` - Tauri command handlers for frontend communication
|
|
||||||
- `shortcut.rs` - Global keyboard shortcut handling
|
|
||||||
- `settings.rs` - Application settings management
|
|
||||||
|
|
||||||
### Frontend Structure (src/)
|
|
||||||
|
|
||||||
- `App.tsx` - Main component with onboarding flow
|
|
||||||
- `components/settings/` - Settings UI (35+ files)
|
|
||||||
- `components/model-selector/` - Model management interface
|
|
||||||
- `components/onboarding/` - First-run experience
|
|
||||||
- `hooks/useSettings.ts`, `useModels.ts` - State management hooks
|
|
||||||
- `stores/settingsStore.ts` - Zustand store for settings
|
|
||||||
- `bindings.ts` - Auto-generated Tauri type bindings (via tauri-specta)
|
|
||||||
- `overlay/` - Recording overlay window code
|
|
||||||
|
|
||||||
### Key Patterns
|
|
||||||
|
|
||||||
**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)
|
|
||||||
|
|
||||||
## Internationalization (i18n)
|
|
||||||
|
|
||||||
All user-facing strings must use i18next translations. ESLint enforces this (no hardcoded strings in JSX).
|
|
||||||
|
|
||||||
**Adding new text:**
|
|
||||||
|
|
||||||
1. Add key to `src/i18n/locales/en/translation.json`
|
|
||||||
2. 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
**Rust:**
|
|
||||||
|
|
||||||
- Run `cargo fmt` and `cargo clippy` before committing
|
|
||||||
- Handle errors explicitly (avoid unwrap in production)
|
|
||||||
- Use descriptive names, add doc comments for public APIs
|
|
||||||
|
|
||||||
**TypeScript/React:**
|
|
||||||
|
|
||||||
- Strict TypeScript, avoid `any` types
|
|
||||||
- Functional components with hooks
|
|
||||||
- Tailwind CSS for styling
|
|
||||||
- Path aliases: `@/` → `./src/`
|
|
||||||
|
|
||||||
## Commit Guidelines
|
|
||||||
|
|
||||||
Use conventional commits:
|
|
||||||
|
|
||||||
- `feat:` new features
|
|
||||||
- `fix:` bug fixes
|
|
||||||
- `docs:` documentation
|
|
||||||
- `refactor:` code refactoring
|
|
||||||
- `chore:` maintenance
|
|
||||||
|
|
||||||
## CLI Parameters
|
|
||||||
|
|
||||||
Handy supports command-line parameters on all platforms for integration with scripts, window managers, and autostart configurations.
|
|
||||||
|
|
||||||
**Implementation files:**
|
|
||||||
|
|
||||||
- `src-tauri/src/cli.rs` - CLI argument definitions (clap derive)
|
|
||||||
- `src-tauri/src/main.rs` - Argument parsing before Tauri launch
|
|
||||||
- `src-tauri/src/lib.rs` - Applying CLI overrides (setup closure + single-instance callback)
|
|
||||||
- `src-tauri/src/signal_handle.rs` - `send_transcription_input()` reusable function
|
|
||||||
|
|
||||||
**Available flags:**
|
|
||||||
|
|
||||||
| Flag | Description |
|
|
||||||
| ------------------------ | ---------------------------------------------------------------------------------- |
|
|
||||||
| `--toggle-transcription` | Toggle recording on/off on a running instance (via `tauri_plugin_single_instance`) |
|
|
||||||
| `--toggle-post-process` | Toggle recording with post-processing on/off on a running instance |
|
|
||||||
| `--cancel` | Cancel the current operation on a running instance |
|
|
||||||
| `--start-hidden` | Launch without showing the main window (tray icon still visible) |
|
|
||||||
| `--no-tray` | Launch without the system tray icon (closing window quits the app) |
|
|
||||||
| `--debug` | Enable debug mode with verbose (Trace) logging |
|
|
||||||
|
|
||||||
**Key design decisions:**
|
|
||||||
|
|
||||||
- CLI flags are runtime-only overrides — they do NOT modify persisted settings
|
|
||||||
- Remote control flags (`--toggle-transcription`, `--toggle-post-process`, `--cancel`) work by launching a second instance that sends its args to the running instance via `tauri_plugin_single_instance`, then exits
|
|
||||||
- `send_transcription_input()` in `signal_handle.rs` is shared between signal handlers and CLI to avoid code duplication
|
|
||||||
- `CliArgs` is stored in Tauri managed state (`.manage()`) so it's accessible in `on_window_event` and other handlers
|
|
||||||
|
|
||||||
## Debug Mode
|
|
||||||
|
|
||||||
Access debug features: `Cmd+Shift+D` (macOS) or `Ctrl+Shift+D` (Windows/Linux)
|
|
||||||
|
|
||||||
## Platform Notes
|
|
||||||
|
|
||||||
- **macOS**: Metal acceleration, accessibility permissions required
|
|
||||||
- **Windows**: Vulkan acceleration, code signing
|
|
||||||
- **Linux**: OpenBLAS + Vulkan, limited Wayland support, overlay disabled by default
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue