A desktop-first Pomodoro timer that turns the break into a productive habit window. User accounts, hosted backend, per-user habit sync. The Flutter client ships on Linux desktop and Android from one codebase; other client platforms are v2.
Traditional Pomodoro apps treat the break as a passive countdown. Pomohabits replaces that with a full-screen break presentation: every time a focus session ends, the app shows the user's always-shown habits plus one randomized habit drawn from their personal pool (falling back to a built-in suggestion when the pool is empty). The randomization rule, eligibility filtering, and daily-reset behaviour are the product's domain decisions; the break presentation is the user-visible payoff. The app is vendor-neutral by design: it owns the habit pool and exposes a hosted integration endpoint so external clients (agents, scripts, bridges) can push habits into the pool from whatever system the user already uses. No third-party task manager is privileged inside the app.
Working and shipping releases. Latest release: v0.3.0.
The repo holds two apps that share one Supabase backend:
- Flutter client (repo root:
lib/,linux/,android/) targets Linux desktop and Android from one Dart codebase, and talks to Supabase viasupabase_flutter. Localized in Polish and English (lib/l10n/). - Astro landing + dashboard (
landing/) is Astro 6 SSR on Cloudflare Workers with React 19 islands and Supabase SSR auth, Polish by default with English under/en/. It owns the database migrations underlanding/supabase/migrations/, which are the schema source of truth.
The break screen shows every habit flagged always_shown plus one drawn at random from the rest, filtered by whether the habit applies to a short or long break, with a built-in suggestion as the fallback when the pool is empty.
The Flutter client reads and writes through PostgREST RPCs defined in the migrations: list_habits, add_habit, complete_habit, update_habit, delete_habit, record_focus_session, list_focus_sessions, habit_stats.
Run from the repo root.
flutter run -d linux- desktop dev loop.flutter analyze- static analysis.flutter test- unit + widget tests.
Supabase credentials are passed at the command line via --dart-define, not a .env file. See SETUP.md for the exact invocation and the one-time Supabase project link and migration push.
Run from landing/.
npm run dev- dev server.npm run build- production build.npm run lint- ESLint.npm run test:e2e- Playwright e2e suite.
See landing/README.md for environment variables and details.
.github/workflows/ci.yml runs three jobs on every push and pull request to main: flutter (pub get, analyze, test), landing (lint, build), and e2e (Playwright against a local dev server). On a push to main where all three succeed, a version job computes the next semver from conventional-commit subjects since the last v* tag; if there is a releasable commit, a release job builds the Flutter app, tags the release, and attaches the Linux bundle as a zip.
The Android APK is built in CI but not published: android/app/build.gradle.kts still signs release builds with the debug keystore, so a publicly downloadable APK would not be a safe, upgradeable install. That will change once real release signing is configured.
- No offline-first or local-cache mode in v1. The desktop client is online-first; offline operation is a v2 capability.
- No vendor-specific integrations baked into the app. External clients handle bridging; the app exposes the surface.
- No focus-task linking or external time recording in v1. The integration surface is for habit data only.
- No rich habit details (description, image, links, notes) in v1.