18 KiB
Contributing to TuxMate
Thank you for your interest in contributing! This guide ensures high-quality, error-free contributions.
⚠️ Before You Start
Your PR will be rejected if you:
- ❌ Submit unverified package names
- ❌ Use wrong package name casing (e.g.,
firefoxvsMozillaFirefox) - ❌ Put
pacmanpackages inarchwhen they're AUR-only - ❌ Use partial Flatpak IDs instead of full App IDs
- ❌ Forget
--classicfor Snap packages that require it - ❌ Include PPAs or unofficial repos for apt packages
- ❌ Incorrect Homebrew format (GUI apps require
'--cask name'with a space separator)
📦 Adding Applications
All applications are defined in src/lib/data.ts.
Mandatory Research Protocol
You MUST verify every package on these official sources before submitting:
| Source | What to Check | URL |
|---|---|---|
| Repology | Global package index (check first!) | https://repology.org/project/[app-name]/versions |
| Arch Linux | Official repos (core, extra) |
archlinux.org/packages |
| AUR | User repos (only if not in official!) | aur.archlinux.org |
| Ubuntu/Debian | Main/Universe repos only, NO PPAs | packages.ubuntu.com / packages.debian.org |
| Fedora | Official packages | packages.fedoraproject.org |
| OpenSUSE | Official packages | software.opensuse.org |
| NixOS | Nix packages | search.nixos.org |
| Flathub | Flatpak apps (get the App ID!) | flathub.org |
| Snapcraft | Snap packages | snapcraft.io |
| Homebrew Formulae | CLI tools (works on macOS + Linux) | formulae.brew.sh |
| Homebrew Casks | GUI apps (macOS only) | formulae.brew.sh/cask |
Entry Structure
{
id: 'app-id', // Unique, lowercase, kebab-case
name: 'App Name', // Official display name
description: 'Short description', // Max ~25 characters
category: 'Category', // Must match valid categories
iconUrl: si('icon-slug', '#color'), // See Icon System section
targets: {
ubuntu: 'exact-package-name', // apt package (official repos ONLY)
debian: 'exact-package-name', // apt package (official repos ONLY)
arch: 'exact-package-name', // pacman OR AUR package name
fedora: 'exact-package-name', // dnf package
opensuse: 'exact-package-name', // zypper package (CASE SENSITIVE!)
nix: 'exact-package-name', // nix package
flatpak: 'com.vendor.AppId', // FULL Flatpak App ID (reverse DNS)
snap: 'snap-name', // Add --classic if needed
homebrew: 'formula-name', // Formula (CLI) or '--cask cask-name' (GUI)
},
unavailableReason?: 'Markdown install instructions'
}
⛔ Strict Rules (Read Carefully!)
Package Name Rules
| Rule | ✅ Correct | ❌ Wrong |
|---|---|---|
| Case sensitivity | MozillaFirefox (openSUSE) |
firefox |
| Exact package name | firefox-esr (Debian) |
firefox |
| OpenJDK versions | openjdk-21-jdk (Ubuntu) |
openjdk |
| Arch package | firefox |
firefox-bin (when official exists) |
Arch Linux: arch vs AUR
| Situation | Field to Use | Example |
|---|---|---|
Package in official repos (core/extra) |
arch: 'package' |
arch: 'firefox' |
| Package NOT in official repos | arch: 'package-bin' |
arch: 'brave-bin' |
| NEVER mix both | Use only ONE | — |
How to check:
- Search archlinux.org/packages
- If found → use
archfield - If NOT found → search aur.archlinux.org → use
archfield with AUR package name - Prefer
-binsuffix packages in AUR (pre-built, faster install) - IMPORTANT: If your AUR package name does NOT end in
-bin,-git, or-appimage, you MUST add it toKNOWN_AUR_PACKAGESinsrc/lib/aur.tsso the app knows it's from AUR.
Ubuntu/Debian: Official Repos Only
| ✅ Allowed | ❌ NOT Allowed |
|---|---|
| Main repository packages | PPAs |
| Universe repository packages | Third-party repos |
| Packages on packages.ubuntu.com | Manual .deb downloads |
If a package requires a PPA: Leave the field empty and add install instructions to unavailableReason.
Flatpak: Full App ID Required
| ✅ Correct | ❌ Wrong |
|---|---|
com.spotify.Client |
spotify |
org.mozilla.firefox |
firefox |
app.zen_browser.zen |
zen-browser |
How to find: Go to flathub.org, search the app, copy the full App ID from the app page.
Snap: Classic Confinement
Some snaps require --classic flag. Check snapcraft.io for the app and look for "classic" confinement.
| App Type | Format |
|---|---|
| Regular snap | 'snap-name' |
| Classic confinement | 'snap-name --classic' |
Homebrew: Formulae vs Casks
Homebrew has two types of packages:
| Type | What It Is | Platform | Format in targets |
|---|---|---|---|
| Formula | CLI tools, libraries | macOS + Linux | 'package-name' |
| Cask | GUI applications (.app) | macOS only | '--cask package-name' |
Examples:
| App | Type | Correct Format |
|---|---|---|
| Git | Formula (CLI) | homebrew: 'git' |
| Node.js | Formula (CLI) | homebrew: 'node' |
| Python | Formula (versioned) | homebrew: 'python@3.12' |
| Firefox | Cask (GUI) | homebrew: '--cask firefox' |
| VS Code | Cask (GUI) | homebrew: '--cask visual-studio-code' |
| Discord | Cask (GUI) | homebrew: '--cask discord' |
| VLC | Cask (GUI) | homebrew: '--cask vlc' |
How to verify package names:
- Formulae: Search formulae.brew.sh or run
brew search <name> - Casks: Search formulae.brew.sh/cask or run
brew search --cask <name> - Check the exact name on the package page (e.g.,
visual-studio-codenotvscode)
Important notes:
- Casks are macOS-only — the generated script will skip them on Linux
- Always prefix GUI apps with
--cask(note the space after) - Some apps exist as both formula AND cask (e.g.,
emacsformula vsemacs-appcask) — choose based on user expectation - For versioned packages, use the explicit version:
python@3.12,node@20
Empty Fields
If a package doesn't exist in a source, leave the field empty (omit it entirely):
// ✅ Correct - Discord not in apt repos
targets: {
arch: 'discord',
flatpak: 'com.discordapp.Discord',
snap: 'discord'
}
// ❌ Wrong - Empty strings clutter the code
targets: {
ubuntu: '',
debian: '',
arch: 'discord',
fedora: '',
opensuse: '',
nix: '',
flatpak: 'com.discordapp.Discord',
snap: 'discord'
}
The unavailableReason Field
Use this to provide helpful installation alternatives when an app isn't available in most package managers.
Format: Markdown with clickable links
// ✅ Good example
unavailableReason: 'Not in official repos. Use [Flatpak](https://flathub.org/apps/com.example.App) or download from [example.com](https://example.com/download).'
// ❌ Bad examples
unavailableReason: 'Not available' // No helpful info
unavailableReason: 'Download from website' // No link provided
Valid Categories
Use exactly one of these:
Web Browsers • Communication • Dev: Languages • Dev: Editors • Dev: Tools
Terminal • CLI Tools • Media • Creative • Gaming • Office
VPN & Network • Security • File Sharing • System
🎨 Icon System
TuxMate uses the Iconify API for icons. Icon helpers are defined in src/lib/data.ts.
Helper Functions
| Function | Use Case | Example |
|---|---|---|
si('slug', '#color') |
Simple Icons (brands) | si('firefox', '#FF7139') |
lo('slug') |
Logos (already colorful) | lo('chrome') |
vs('slug') |
VS Code file icons | vs('file-type-shell') |
mdi('slug', '#color') |
Material Design icons | mdi('console', '#57F287') |
Finding Icon Slugs
| Source | URL | Notes |
|---|---|---|
| Simple Icons | simpleicons.org | Use lowercase slug, add hex color |
| Material Design | pictogrammers.com/library/mdi | Use icon name |
| Iconify Search | icon-sets.iconify.design | Search all sets |
| Fallback | — | Use mdi('application', '#color') |
Icon Requirements
- ✅ Must be recognizable at 24×24px
- ✅ Use official brand colors - click icon to copy hex
- ✅ Monochrome icons (si, mdi) require a color parameter
- ✅ Colorful icons (lo, sk, vs) don't need color
- ❌ Don't use blurry or low-quality external URLs
🔀 Pull Request Checklist
Before submitting, verify ALL of these:
Package Verification
- Checked Repology for global package availability
- Verified exact package names on each distro's official package search
- Confirmed case sensitivity (especially openSUSE:
MozillaFirefox,MozillaThunderbird) - Arch packages confirmed in official repos OR AUR
- Ubuntu/Debian packages are in Main/Universe only (no PPAs)
- Flatpak uses full App ID from Flathub
- Snap packages checked for
--classicrequirement - Nix packages checked for unfree license (add to
KNOWN_UNFREE_PACKAGESif needed) - Homebrew uses correct format:
'formula'for CLI,'--cask name'for GUI apps
Code Quality
- Tested locally with
npm run dev - Production build passes:
npm run build - Lint passes:
npm run lint - Unit tests pass:
npm run test - Apps added in alphabetical order within their category
- Icons display correctly at small sizes
📝 Pull Request Template
Use the following template when submitting a pull request:
## Summary
Brief description of changes made.
## Changes
### Apps Added
| App Name | Category | Package Sources |
|----------|----------|-----------------|
| Example App | Dev: Tools | apt, pacman, flatpak, homebrew |
### Apps Modified
- `app-id`: Description of change
## Verification
> All package names have been verified against official sources.
| Source | Verification Link |
|--------|-------------------|
| Repology | [repology.org/project/...](https://repology.org/) |
| Arch Linux | [archlinux.org/packages/...](https://archlinux.org/packages/) |
| AUR | [aur.archlinux.org/packages/...](https://aur.archlinux.org/) |
| Ubuntu | [packages.ubuntu.com/...](https://packages.ubuntu.com/) |
| Fedora | [packages.fedoraproject.org/...](https://packages.fedoraproject.org/) |
| openSUSE | [software.opensuse.org/...](https://software.opensuse.org/) |
| NixOS | [search.nixos.org/packages/...](https://search.nixos.org/packages) |
| Flathub | [flathub.org/apps/...](https://flathub.org/) |
| Snapcraft | [snapcraft.io/...](https://snapcraft.io/) |
| Homebrew | [formulae.brew.sh/...](https://formulae.brew.sh/) |
## Testing
- [ ] `npm run dev` — Local development server works
- [ ] `npm run build` — Production build passes
- [ ] `npm run lint` — No linting errors
- [ ] `npm run test` — All unit tests pass
- [ ] Verified in browser — UI renders correctly
## Screenshots (if applicable)
<!-- Add screenshots for UI changes -->
💻 Development Workflow
Initial Setup
# Clone the repository
git clone https://github.com/abusoww/tuxmate.git
cd tuxmate
# Install dependencies
npm install
# Start development server
npm run dev
The development server will be available at http://localhost:5173.
Quality Assurance
Run these commands before every commit:
| Command | Purpose |
|---|---|
npm run lint |
Check for code style issues |
npm run lint -- --fix |
Auto-fix linting errors |
npm run test |
Run unit test suite |
npm run build |
Verify production build |
Branch Naming Convention
| Type | Format | Example |
|---|---|---|
| New feature | feature/description |
feature/add-homebrew-support |
| Bug fix | fix/description |
fix/arch-aur-detection |
| Documentation | docs/description |
docs/update-contributing |
| Refactor | refactor/description |
refactor/script-generation |
Commit Message Format
Follow Conventional Commits:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types:
| Type | Description |
|---|---|
feat |
New feature or functionality |
fix |
Bug fix |
docs |
Documentation changes |
style |
Code style (formatting, no logic change) |
refactor |
Code restructuring (no feature change) |
test |
Adding or updating tests |
chore |
Maintenance tasks |
Examples:
feat(data): add Homebrew support for 50+ apps
fix(scripts): correct AUR package detection for -git suffix
docs(contributing): add Homebrew verification guidelines
🐧 Adding Distributions
Distributions are defined in src/lib/data.ts.
Distro Structure
{
id: 'distro-id',
name: 'Display Name',
iconUrl: si('distro-slug', '#color'),
color: '#HexColor',
installPrefix: 'sudo pkg install -y'
}
After Adding a Distro
- Add the distro ID to the
DistroIdtype insrc/lib/data.ts - Create a new script generator file:
src/lib/scripts/[distro].ts - Export the generator from
src/lib/scripts/index.ts - Add the case in
src/lib/generateInstallScript.ts(both functions) - Handle distro-specific logic (repo setup, package detection, etc.)
- Add
targets.[distro]entries to relevant apps indata.ts
⚙️ Script Generation
Script generation is modular. Each distro has its own generator:
src/lib/
├── generateInstallScript.ts # Main entry point
├── aur.ts # AUR package detection
└── scripts/
├── index.ts # Exports all generators
├── shared.ts # Colors, progress bars, utilities
├── arch.ts # Arch + AUR (yay)
├── debian.ts # Debian apt
├── ubuntu.ts # Ubuntu apt + PPA handling
├── fedora.ts # Fedora dnf + RPM Fusion
├── opensuse.ts # openSUSE zypper
├── nix.ts # Nix declarative config generator
├── flatpak.ts # Flatpak (parallel install)
├── snap.ts # Snap packages
└── homebrew.ts # Homebrew (formulae + casks)
Nix Unfree Packages
When adding Nix packages, check if they require allowUnfree = true. Unfree packages are detected in src/lib/nixUnfree.ts.
Known unfree packages (add new ones to KNOWN_UNFREE_PACKAGES):
- Communication:
discord,slack,zoom-us,teams,skypeforlinux - Browsers:
google-chrome,vivaldi,opera - Media:
spotify - Gaming:
steam - Dev:
vscode,sublime-text,postman,code-cursor,vagrant, JetBrains IDEs - Creative:
davinci-resolve - Other:
obsidian,dropbox,1password
How it works:
- User selects unfree packages with Nix distro
- UI shows amber warning listing affected apps
- Downloaded
configuration.nixincludes comment withallowUnfreeinstructions
Script Generator Features
Each script generator implements these core capabilities:
| Feature | Description | Implementation |
|---|---|---|
| Package Detection | Skip already-installed packages | Distro-specific checks (e.g., dpkg -l, brew list) |
| AUR Handling | Auto-install yay/paru helper for Arch |
See aur.ts for detection patterns |
| RPM Fusion | Auto-enable repos for Fedora multimedia | Enabled when proprietary codecs needed |
| Parallel Install | Concurrent package installation | Flatpak uses background jobs for speed |
| Network Retry | Exponential backoff on failures | with_retry() in shared.ts |
| Progress UI | Colored output with ETA | Progress bars, timing, summary |
| Shell Escaping | Prevent command injection | escapeShellString() in shared.ts |
| Homebrew Casks | Platform-aware formula/cask handling | Separate commands, skip casks on Linux |
Testing Script Changes
Automated Testing
# Run the full test suite
npm run test
# Run tests in watch mode during development
npm run test -- --watch
# Run specific test file
npm run test -- src/__tests__/aur.test.ts
Manual Testing Workflow
| Step | Action | Purpose |
|---|---|---|
| 1 | npm run dev |
Start development server |
| 2 | Select test packages | Choose mix of package types |
| 3 | Copy generated script | Use "Copy" button |
| 4 | Test in isolated environment | VM or container (see below) |
| 5 | Verify installation | Check packages installed correctly |
Container Testing
Use Docker containers for safe, isolated testing:
# Arch Linux
docker run -it --rm archlinux:latest bash -c "pacman -Sy && bash"
# Ubuntu
docker run -it --rm ubuntu:latest bash -c "apt update && bash"
# Fedora
docker run -it --rm fedora:latest bash -c "dnf check-update; bash"
# Debian
docker run -it --rm debian:latest bash -c "apt update && bash"
Tip
For Homebrew testing, use a macOS environment or Homebrew on Linux.
🐛 Reporting Issues
Bug Reports — Include:
- Browser & OS (e.g., Firefox 120 on Arch Linux)
- Steps to reproduce (numbered list)
- Expected vs actual behavior
- Console errors (F12 → Console tab)
- Screenshots if UI-related
Feature Requests — Include:
- Use case and why it's needed
- Proposed solution
- Alternatives considered
❓ Questions?
Open a Discussion or create an Issue.