Thank you for taking the time to contribute. Below you'll find everything needed to get set up, make changes, and cut a release.
- Code of Conduct
- Filing a Bug or Feature
- Development Setup
- Project Structure
- Making Changes
- Releasing
Be kind and respectful to the members of the community. Take time to educate others who are seeking help. Harassment of any kind will not be tolerated.
- Check existing issues before opening a new one.
- Bug reports — include steps to reproduce, Pomotroid version, OS, and what you expected vs. what happened.
- Feature requests — open an issue with a clear title and description of the feature and why it would be useful.
| Tool | Version |
|---|---|
| Node.js | 22+ |
| Rust | stable (via rustup) |
| npm | bundled with Node.js |
Linux — install system dependencies:
sudo apt-get install -y \
libwebkit2gtk-4.1-dev libssl-dev \
libayatana-appindicator3-dev librsvg2-dev \
patchelf libasound2-devmacOS / Windows — no extra system dependencies required.
git clone https://github.com/Splode/pomotroid
cd pomotroid
npm install
npm run tauri dev# Format all frontend source files (Prettier)
npm run format
# TypeScript + Svelte type checking
npm run check
# Rust unit tests
cargo test --manifest-path src-tauri/Cargo.toml
# Rust linting (must pass with zero warnings)
cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warningsAll must pass before submitting a pull request. The CI pipeline runs them automatically.
If you use VS Code, formatting happens automatically on save — install the Prettier and Svelte for VS Code extensions.
To populate the statistics views with realistic historical data, use the seed script (requires Python 3, no extra dependencies):
# Preview what would be inserted — no database changes
python3 scripts/seed-db.py --dry-run
# Seed ~2 years of session history (default)
python3 scripts/seed-db.py
# Seed 1 year and wipe any existing sessions first
python3 scripts/seed-db.py --days 365 --clearThe database must exist before seeding — launch Pomotroid at least once to create it. The script resolves the platform-specific app-data path automatically; pass --db PATH to override.
pomotroid/
├── src/ # SvelteKit frontend (Svelte 5 runes)
│ ├── routes/ # Page components (main timer, settings, stats)
│ └── lib/
│ ├── components/ # Reusable UI components
│ ├── ipc/ # Frontend wrappers for Tauri commands
│ └── stores/ # Svelte stores (settings, theme)
├── src-tauri/ # Rust backend (Tauri 2)
│ └── src/
│ ├── commands.rs # IPC command handlers
│ ├── timer/ # Timer engine
│ ├── audio/ # Audio playback (rodio)
│ ├── db/ # SQLite persistence (rusqlite)
│ └── settings/ # Settings load/save
├── static/themes/ # Built-in JSON theme files
└── scripts/ # Maintainer scripts
- Fork the repository and create a feature branch from
main. - Make your changes. Keep commits focused and use conventional commit prefixes (
feat:,fix:,chore:, etc.). - Ensure all checks pass (
npm run format,npm run check,cargo test,cargo clippy). - Open a pull request against
mainwith a clear description of what changed and why.
Built-in themes are embedded into the binary at compile time, so adding one requires a small code change in addition to the JSON file.
-
Create the theme JSON in
static/themes/your-theme-name.json. SeeTHEMES.mdfor the required format and color keys. -
Register it in
src-tauri/src/themes/mod.rs— add aninclude_str!()entry to theBUNDLED_JSONarray:include_str!("../../../static/themes/your-theme-name.json"),
-
Update the bundled theme count in the test assertion in the same file (e.g.
assert_eq!(themes.len(), 38, ...)).
Custom user themes (placed in the app data themes/ folder) are discovered at runtime and require no code changes.
The app uses Inlang + Paraglide for translations. Adding a language requires two files to be touched, then a rebuild.
-
Create the message file at
src/messages/{locale}.json. Copysrc/messages/en.jsonas a starting point and translate all values — do not change any keys. -
Register the locale by adding it to the
localesarray inproject.inlang/settings.json:"locales": ["en", "zh", "pt", "your-locale"]
-
Rebuild (
npm run build) — Paraglide auto-generates the typed JS modules insrc/paraglide/messages/. No further code changes are needed; the language will appear in Settings automatically.
Settings are stored as key/value strings in SQLite. Adding a new setting involves:
- Adding the DB key and default value in
src-tauri/src/settings/defaults.rs - Adding the typed field to the
Settingsstruct insrc-tauri/src/settings/mod.rs - Updating the frontend
Settingstype insrc/lib/types.ts - Exposing a toggle or input in the relevant settings section under
src/lib/components/settings/sections/
Releases are managed by maintainers. The process is intentionally minimal: one script, one push.
- You are on the
mainbranch with a clean working tree. [Unreleased]inCHANGELOG.mdcontains the changes for this release.
1. Fill in the changelog
Open CHANGELOG.md and make sure [Unreleased] accurately describes everything going into the release. The release workflow uses this section as the GitHub Release body.
2. Run the bump script
./scripts/bump-version.sh <version>
# e.g.
./scripts/bump-version.sh 1.1.0This will:
- Update the version in
tauri.conf.json,Cargo.toml, andpackage.json - Rename
[Unreleased]inCHANGELOG.mdto[v1.1.0] - YYYY-MM-DD - Commit all changes and create an annotated
v1.1.0tag
3. Push
git push origin main --follow-tagsPushing the tag triggers the release workflow, which:
- Builds Linux (
.deb,.AppImage), macOS (universal.dmg), and Windows (.exeinstaller) in parallel - Creates a draft GitHub Release with all artifacts attached and the changelog section as the release body
- Commits
latest.json(auto-updater manifest) andpomotroid.json(Scoop manifest) tomain
4. Publish the draft
Go to the Releases page, review the draft, and click Publish release.
5. Open the changelog for the next release
After publishing, run:
./scripts/new-release-cycle.sh
git push origin mainThis adds a fresh [Unreleased] block at the top of CHANGELOG.md and commits it, ready to collect the next release's changes.
Pomotroid follows Semantic Versioning:
| Change | Version bump |
|---|---|
| Breaking changes or major rewrites | X.0.0 |
| New features, backward-compatible | X.Y.0 |
| Bug fixes only | X.Y.Z |