Skip to content

Latest commit

 

History

History
218 lines (163 loc) · 11 KB

File metadata and controls

218 lines (163 loc) · 11 KB

Contributing to Claudette

Thank you for your interest in contributing to Claudette! This guide will help you get started.

Code of Conduct

This project adheres to the Contributor Covenant 3.0 Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to seancallan@gmail.com.

How to Contribute

Reporting Bugs

Before filing a bug report, please check existing issues to avoid duplicates.

When filing a bug report, include:

  • A clear, descriptive title
  • Steps to reproduce the issue
  • Expected behavior vs. actual behavior
  • Your OS and version (macOS, Linux, or Windows)
  • Relevant logs or screenshots

Suggesting Features

Feature suggestions are welcome! Please open an issue describing:

  • The problem your feature would solve
  • Your proposed solution
  • Any alternatives you've considered

Submitting Changes

  1. Fork the repository and create a feature branch from main.
  2. Set up the development environment — see the README for prerequisites.
  3. Make your changes following the guidelines below.
  4. Test your changes — run the full test and lint suite before submitting:
    cargo test --all-features
    cargo clippy --workspace --all-targets
    cargo fmt --all --check
    cd src/ui && bunx tsc --noEmit
  5. Commit your changes using conventional commit format.
  6. Open a pull request against main with a clear description of your changes.

Development Setup

# Clone your fork
git clone https://github.com/<your-username>/claudette.git
cd claudette

# Install frontend dependencies
cd src/ui && bun install && cd ../..

# Run in development mode (macOS / Linux)
./scripts/dev.sh
# Windows equivalent — same flags, PowerShell launcher
.\scripts\dev.ps1
.\scripts\dev.ps1 --help

macOS — voice input dev mode: if you're working on or testing the voice-input feature, run ./scripts/dev.sh instead of cargo tauri dev. The script wraps the dev binary in a signed .app bundle with the usage strings + entitlements that macOS TCC requires before granting Microphone or Speech Recognition permission. Plain cargo tauri dev works for everything else.

Linux — ALSA development headers: Debian/Ubuntu users need libasound2-dev installed (Fedora: alsa-lib-devel, Arch: alsa-lib). The cpal audio crate fails to build without it. The full apt install line is in the README prerequisites. Nix users get this automatically via flake.nix.

Headless or sandboxed Linux environments without ALSA can omit voice support entirely:

cargo tauri build --no-default-features --features tauri/custom-protocol,server

Windows — use scripts\dev.ps1 (not cargo tauri dev). The PowerShell launcher refreshes PATH from the registry (so a fresh shell sees clang/cargo without restarting), forces Vite onto 127.0.0.1 (Windows resolves localhost to ::1 first; WebView2 doesn't follow), drops voice from the default feature set (gemm-f16 requires the fullfp16 ARMv8.2 target feature that stock aarch64-pc-windows-msvc doesn't enable), skips tauri/custom-protocol (it would suppress import.meta.env.DEV and break /claudette-debug), and stages the claudette-cli sidecar that the bundled tauri.conf.json would otherwise look for. --new, --clone, --clean, and --help work the same as on the .sh version.

Heads up if you have muscle memory for --clean: the flag was repurposed. It used to mean "run as a fresh user with a per-PID sandbox" — that's now --new. The new --clean is a standalone action that wipes everything under $TMPDIR/claudette-dev/ and exits without launching the app. Use --new for fresh-user dev sessions and --clean only when you want to reset the discovery directory after SIGKILL'd runs.

First-time prerequisites on Windows: VS C++ Build Tools (Desktop development with C++ workload) and Clang/LLVM on PATH (e.g. scoop install llvm). The PowerShell profile snippet for a bare dev command is in the README — Run in development mode.

Verifying Linux behavior from macOS / Windows: Claudette ships an Arch Linux + XFCE + noVNC test container at packaging/aur/test/Dockerfile. One command builds the image, installs claudette-bin from the in-repo PKGBUILD, plants a Desktop launcher, clones the public repo into ~/Projects/ Claudette, and serves the desktop on http://localhost:6080/ for any browser:

scripts/aur/test-in-docker.sh claudette-bin    # or: nix develop -c aur-test claudette-bin

Use it to verify Tauri/GTK behavior, packaging assumptions, or any reported "works on macOS, breaks on Linux" issue without needing to maintain a Linux VM. The user inside the container is builder / builder (sudo is passwordless). Full reference in packaging/aur/README.md.

Commit Conventions

This project uses conventional commits. Every commit message and PR title must follow this format:

<type>: <description>

Common types: feat, fix, docs, refactor, test, ci, chore

  • Keep the header under 100 characters
  • Use the imperative mood ("add feature" not "added feature")
  • PR titles are validated by CI

Code Style

Rust

  • Edition 2024 — use modern idioms
  • Run cargo fmt before committing (CI enforces formatting)
  • Run cargo clippy with zero warnings (CI sets RUSTFLAGS="-Dwarnings")

TypeScript

  • Strict mode enabled — no any types
  • Use bun as the package manager (not npm)

Architecture Overview

Claudette is a Tauri 2 desktop app with a Rust backend and React/TypeScript frontend. See CLAUDE.md for the full architecture guide.

Key principles:

  • Data types go in src/model/ — keep them free of UI and IO dependencies
  • Service modules (db.rs, git.rs, agent.rs) live at the src/ level
  • Tauri commands go in src-tauri/src/commands/ as thin wrappers
  • React components are organized by feature area in src/ui/src/components/
  • State management uses Zustand with domain slices

Translating Claudette

Claudette is internationalized using i18next on the frontend and a small bespoke loader on the Rust side. Today the app ships with five complete translations: English (en, the baseline), Spanish (es), Brazilian Portuguese (pt-BR), Japanese (ja), and Simplified Chinese (zh-CN). Each ships the full UI plus the system tray menu, notifications, and the quit-confirm dialog. Missing keys fall back to English at runtime, so partial translations are safe to ship — they just leave a few English strings showing through.

Adding a language is mostly a JSON-translation task. You don't need Rust or TypeScript experience to translate the strings; the small registration step at the end is just a handful of lines.

Where translation files live

  • Frontendsrc/ui/src/locales/<lang>/ contains five namespace files: common.json, chat.json, modals.json, settings.json, and sidebar.json.
  • Backendsrc/locales/<lang>/tray.json contains the tray, notification, and quit-dialog strings.

Both sides use the same {{var}} placeholder syntax for interpolation, so a translator only learns one convention.

Adding a new language

  1. Pick a locale code. Use the 2-letter ISO 639-1 code (e.g. fr, de, pt). If you need a regional variant, use BCP-47 style (e.g. pt-BR, zh-TW).
  2. Copy the English files. Duplicate src/ui/src/locales/en/ and src/locales/en/ to your new locale directory. Translate the values; leave the keys byte-for-byte identical to English.
  3. Register the language on the frontend. In src/ui/src/i18n.ts, add imports for each of the five namespace files, append your locale code to SUPPORTED_LANGUAGES, and add a matching entry to the resources map.
  4. Update the TypeScript declaration in src/ui/src/types/i18next.d.ts only if you've introduced a new namespace (most translation contributions don't need this).
  5. Register the language on the backend. In src/i18n/mod.rs, add a variant to the Locale enum, add an include_str! line for your tray.json, add a matching *_store() function alongside the existing per-locale stores (each wraps a OnceLock over the parsed JSON), and update Locale::from_db_value and Locale::store to recognize the new code. Also extend the locales_have_identical_key_sets test in the same file to include your new store, so the parity check covers your locale.
  6. Add the language to the selector in Settings → General, following the existing pattern (general_language_<code> translation key plus an <option> entry).

Updating an existing translation

If you'd like to fix a mistranslation or polish wording in an existing language, just edit the relevant file under src/ui/src/locales/<lang>/ or src/locales/<lang>/tray.json and open a PR — no registration steps required.

Conventions

  • Keep {{placeholder}} interpolation tokens verbatim. They're substituted at runtime; translating them will break the rendered string.
  • Honor _one / _other plural keys. If a key has both forms in English (i18next's plural convention), provide both forms in your language even if your language uses fewer plural categories — i18next will pick the right one.
  • Match casing and punctuation choices to the language's UI conventions, but be aware that some strings (e.g. button labels) have tight space budgets in the UI.

What CI checks

  • cargo test --all-features runs locales_have_identical_key_sets in src/i18n/mod.rs, which fails if the backend locales it includes (currently es, pt-BR, ja, and zh-CN, each compared against en) disagree on which keys exist. The check only covers the locales explicitly compared in the test, so when adding a new backend locale make sure to extend the test to include it (see the registration step above). Run the suite locally before opening a PR.
  • cd src/ui && bunx tsc -b enforces frontend type safety, which transitively catches mistyped translation keys consumed via useTranslation().
  • cargo clippy --workspace --all-targets and cargo fmt --all --check round out the standard checks.

If you're not sure where to start, open an issue to claim a language so two contributors don't unknowingly translate in parallel.

Pull Request Guidelines

  • Keep PRs focused — one feature or fix per PR
  • Include tests for new functionality where applicable
  • Update documentation if your change affects public behavior
  • Ensure CI passes before requesting review
  • Link related issues in the PR description

License

By contributing to Claudette, you agree that your contributions will be licensed under the MIT License.