Thanks for your interest! This guide covers everything you need to contribute.
# Fork on GitHub, then clone
git clone https://github.com/hate/keyless.git
cd keyless
# Build and test
cargo build
cargo test --workspace
# Run CI checks locally (format, clippy, build, tests, docs, doctests)
./check-ci.shgit checkout -b feat/your-feature
# or fix/your-bugfixBefore committing:
./check-ci.sh # macOS/Linux (includes docs + doctests)
# or
.\check-ci.ps1 # Windows (PowerShell; includes docs + doctests)Use Conventional Commits:
feat(whisper): add temperature fallback
fix(audio): prevent VAD flicker
docs(readme): update installation steps
chore(ci): add Windows to matrix
Format: <type>(<scope>): <description>
Commit Types:
-
feat- New user-facing functionality or features- Example:
feat(whisper): add temperature fallback,feat(tui): add config screen - Use when: Adding new capabilities users can interact with
- Example:
-
fix- Bug fixes that resolve incorrect behavior- Example:
fix(audio): prevent VAD flicker,fix(runtime): handle PTT release edge case - Use when: Correcting bugs or broken functionality
- Example:
-
docs- Documentation-only changes (README, comments, rustdoc)- Example:
docs(readme): update installation steps,docs(api): add safety notes - Use when: Only changing documentation, no code changes
- Example:
-
style- Code style/formatting changes that don't affect logic- Example:
style: run cargo fmt,style(tui): fix indentation - Use when: Whitespace, formatting, or style-only changes
- Example:
-
refactor- Code restructuring that improves structure without changing behavior- Example:
refactor(runtime): extract pipeline setup,refactor(audio): simplify VAD logic - Use when: Improving code organization without fixing bugs or adding features
- Example:
-
perf- Performance improvements- Example:
perf(eq): cache FFT planner,perf(whisper): reduce allocations - Use when: Optimizing speed, memory usage, or efficiency
- Example:
-
test- Adding or modifying tests- Example:
test(audio): add VAD threshold tests,test(models): cover download cancellation - Use when: Test code changes only
- Example:
-
chore- Maintenance tasks (dependencies, CI, build, tooling)- Example:
chore(deps): update tokio,chore(ci): add Windows to matrix,chore: initial commit - Use when: Infrastructure, tooling, or housekeeping that doesn't change functionality
- Example:
Scopes (optional but recommended):
- Crate names:
whisper,audio,tui,runtime,models,output,core,logging - Areas:
ci,docs,build,deps,git - Leave out scope if change spans multiple areas:
chore: initial commit
git push origin feature/your-featureThen open PR on GitHub.
- ✅ Run
cargo fmt --allbefore committing - ✅ No
clippywarnings - ✅ No
unwrap()orexpect()in production code - ✅ Use
KeylessErrorfor errors - ✅ Use
tracingfor logging - ✅ Add tests for new features
- ✅ Document public APIs (rustdoc/JSDoc)
- ✅ Add inline comments for complex logic (Rust and TypeScript)
We enforce comprehensive documentation across the codebase:
Rust (rustdoc):
- Crate/module headers use
//!with purpose and relationships - All items (public and internal) use
///with a first-line summary - Include sections where applicable:
- Examples, Errors, Panics, Safety (Send/Sync/FFI), Threading/Blocking, Performance, Invariants
- Prefer small compilable examples (doctests)
Rust (inline comments):
- Add inline comments (
//) for complex logic, algorithms, and non-obvious code paths - Document thread-safety considerations, state management, and async boundaries
- Explain business logic, state transitions, and error handling strategies
TypeScript/React (JSDoc + inline):
- File-level JSDoc headers (
/** */) explaining component/hook purpose and usage - Inline comments (
//) for complex logic, state management, and event handling - Document React hooks, state variables, effects, and event listeners
- Explain business logic, async operations, and error handling
Template:
/// One-line summary.
///
/// Longer context if needed.
///
/// # Examples
/// ```no_run
/// // minimal, compilable usage
/// ```
///
/// # Errors
/// // when and why errors occur
///
/// # Panics
/// // when and why panics occur (ideally never)
///
/// # Safety
/// // safety constraints or Send/Sync invariants
///
/// # Performance
/// // allocations, blocking, complexity, hot paths
// ✅ Production code
pub fn do_work() -> KeylessResult<()> {
something()?; // Uses KeylessError
Ok(())
}
// ✅ Tests (Box<dyn Error> is OK)
#[test]
fn test_something() -> Result<(), Box<dyn std::error::Error>> {
do_work()?;
Ok(())
}use tracing::{info, debug, error};
info!(model = %path, "model loaded");
error!(error = %e, "failed to start");Run this:
./check-ci.sh # macOS/Linux
.\check-ci.ps1 # WindowsMust show: All checks pass
# All tests
cargo test --workspace
# Specific crate
cargo test -p keyless-whisper
# Watch for failures
cargo test --workspace --no-fail-fastTests with I/O should return Result<(), Box<dyn Error>>:
#[test]
fn test_file_write() -> Result<(), Box<dyn std::error::Error>> {
fs::write("test.txt", "data")?;
Ok(())
}Releases are automated via GitHub Actions workflows that trigger on git tags.
- TUI releases: Tag format
tui-v*(e.g.,tui-v0.3.0) - Desktop releases: Tag format
desktop-v*(e.g.,desktop-v0.3.0)
-
Update versions in all relevant files:
Cargo.toml(workspace version)keyless-desktop/src-tauri/Cargo.toml(desktop package version)keyless-desktop/src-tauri/tauri.conf.json(desktop app version)
-
Update CHANGELOG.md with the new version and changes
-
Commit version changes:
git add Cargo.toml keyless-desktop/src-tauri/Cargo.toml keyless-desktop/src-tauri/tauri.conf.json CHANGELOG.md git commit -m "chore: bump version to X.Y.Z" -
Create and push the tag:
# For TUI release git tag tui-v0.3.0 git push origin tui-v0.3.0 # For Desktop release git tag desktop-v0.3.0 git push origin desktop-v0.3.0 # Or both git tag tui-v0.3.0 desktop-v0.3.0 git push origin tui-v0.3.0 desktop-v0.3.0
-
GitHub Actions will automatically:
- Build binaries/installers for all platforms
- Create a GitHub Release with artifacts attached
- Use the tag name as the release name
We follow Semantic Versioning:
- MAJOR (X.0.0): Breaking changes
- MINOR (0.X.0): New features, backwards compatible
- PATCH (0.0.X): Bug fixes, backwards compatible
By contributing, you agree that your contributions will be licensed under the MIT License.