Thank you for your interest in contributing. This document covers development setup, code conventions, and the pull request process.
Be respectful and constructive. Follow existing code style, write clear commit messages, and test your changes before submitting.
- Node.js 20+
- npm 10+
- Rust stable toolchain (
rustup toolchain install stable) - Linux desktop with WebKitGTK and GTK3 dev libraries
Ubuntu / Debian:
sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev \
libayatana-appindicator3-dev librsvg2-dev patchelf build-essentialArch Linux:
sudo pacman -S --needed webkit2gtk-4.1 gtk3 libayatana-appindicator librsvg base-develgit clone https://github.com/YOUR_USERNAME/lintd.git
cd lintd
npm install
npm run tauri dev| Type | Pattern |
|---|---|
| Feature | feature/short-description |
| Bug fix | fix/short-description |
| Docs | docs/what-you-changed |
| Refactor | refactor/component-name |
- Strict TypeScript — no
any - Functional components and hooks only
- TanStack Query for all async data fetching
- Tailwind classes for styling — no inline styles except where dynamic values are required
- Export only what is needed; keep internals unexported
- Run
cargo fmtbefore committing - Run
cargo clippyand address all warnings - Use
Result<T, E>for error handling — nounwrap()in production paths - Add doc comments (
///) on all public functions and types
- Create
src-tauri/src/pmal/your_manager.rs - Implement the
PackageManagertrait:
use super::*;
use async_trait::async_trait;
pub struct YourManager;
#[async_trait]
impl PackageManager for YourManager {
fn name(&self) -> &str { "your_manager" }
fn source(&self) -> PackageSource { PackageSource::YourManager }
fn detect(&self) -> bool {
std::path::Path::new("/usr/bin/your-manager").exists()
}
async fn list_user_installed(&self) -> Result<Vec<Package>, PmalError> { todo!() }
async fn list_orphans(&self) -> Result<Vec<Package>, PmalError> { Ok(vec![]) }
async fn get_files(&self, name: &str) -> Result<Vec<String>, PmalError> { todo!() }
async fn get_reverse_deps(&self, name: &str) -> Result<Vec<String>, PmalError> { todo!() }
async fn remove(&self, name: &str, dry_run: bool) -> Result<RemovalResult, PmalError> { todo!() }
}- Add
YourManagerto thePackageSourceenum inpmal/mod.rs - Register detection in
distro_detect.rs - Add
'your_manager'to thePackageSourceunion type insrc/types/lintd.ts - Add entries to
sourceBadgeClassMapandsourceLabelMapinsrc/lib/presentation.ts - Test package listing, orphan detection, removal preview, and actual removal
- Add an SVG to
public/distro-logos/ - Add the distro ID mapping in
src/components/DistroLogo.tsx - Add an
id_likefamily fallback if needed - Run
npm run buildto verify
Short one-liner, present tense, lowercase after the type prefix:
feat: add zypper package manager backend
fix: correct orphan detection for flatpak runtimes
style: unify source badge colors
chore: update dependencies
docs: update contributing guide
- Ensure
npx tsc --noEmitandcargo buildboth pass - Keep PRs focused — one feature or fix per PR
- Update documentation if you're changing behavior
- Write a clear description: what, why, and how it was tested
- Link related issues with
Fixes #123orRelates to #456 - Be responsive to review feedback
Include:
- Distro and version
- Installed package managers (
which pacman apt dnf flatpak snap) - Steps to reproduce
- Expected vs actual behavior
- Error messages or terminal output
- Never modify the system-critical package block list without thorough review
- Always test removal flows with non-critical packages first
- Document any privilege escalation requirements
- Consider error cases and partial failure scenarios
Open a GitHub issue with the question label, or review existing code for patterns and examples.