FloDoro
Native macOS focus timer with adaptive work modes, intelligent check-ins, and flow state tracking.
The Problem
Traditional Pomodoro timers assume every work session is the same: 25 minutes on, 5 minutes off, repeat. But deep work doesn’t follow a fixed schedule. Some tasks need 10-minute bursts, others need uninterrupted 90-minute flow states. Switching between coding, writing, and planning requires different rhythms. Forcing a single timer pattern onto varied work types leads to either breaking flow or abandoning the timer entirely.
What I Built

FloDoro is a native macOS menu bar timer with six work modes designed around how focus actually works:
Micro (5-15 min) — Quick tasks, email triage, code reviews. Short bursts with minimal overhead. No check-ins needed because the session ends before distraction sets in.
Pomodoro (25/5) — The classic rhythm for structured work. Four cycles with a longer break. Best for tasks with clear boundaries like bug fixes, documentation, and data entry.
Flow (45-90 min) — Extended sessions for deep work. Gentle check-ins at intervals ask “still in flow?” rather than interrupting with a hard stop. If you’re locked in, the timer extends. If you’ve drifted, it suggests a break.
Adaptive — Starts at 25 minutes and adjusts based on your patterns. If you consistently work past the timer, it extends future sessions. If you take breaks early, it shortens. Learns your rhythm over the first week of use.
Deep Work (2-4 hr) — Blocks of protected time with built-in transition periods. Includes a 5-minute wind-down warning and structured break suggestions (walk, stretch, hydrate). Designed for architecture planning, writing, and complex problem-solving.
Custom — Set any duration with configurable check-in intervals, break lengths, and notification styles. For workflows that don’t fit predefined patterns.
Intelligent Check-ins
Rather than a binary timer-done alert, FloDoro uses graduated check-ins during longer sessions. At configured intervals, a subtle menu bar notification asks about your current state. The check-in is a single click — “Still focused”, “Need a break”, or “Wrapping up”. No modal dialogs, no app switching, no flow interruption.
Check-in responses feed into session analytics. If you consistently report “still focused” at the 45-minute mark in Flow mode, FloDoro learns to delay the first check-in. If you often switch to “need a break” around 30 minutes during afternoon sessions, it adjusts recommendations for that time of day.
Decay Signal Tracking
FloDoro tracks proxy signals for focus decay: time since your last check-in response, mouse idle time between active periods, and self-reported energy levels. These signals combine into a decay score that informs break timing suggestions.
The decay model is intentionally simple. Three inputs, weighted average, threshold-based recommendations. No machine learning, no complex modeling. The goal is useful nudges, not surveillance. All data stays local in a SQLite database on your machine.
App Activity Monitoring

FloDoro optionally monitors which application is in the foreground during focus sessions. After a session, you can see that you spent 80% of your time in your code editor but had two 3-minute detours to Slack. The data helps you understand your own patterns.
Activity data is stored locally and never transmitted. The monitoring uses macOS accessibility APIs with explicit user permission. You can disable it entirely without affecting timer functionality.
Technical Decisions
Native Swift over Electron — A timer lives in your menu bar all day. Electron apps consume 100-200MB for a timer that should use 15MB. SwiftUI provides native menu bar integration, system notifications, and accessibility support without the overhead.
SQLite over Core Data — Session data is simple tabular data: timestamps, durations, modes, check-in responses. SQLite handles this directly without Core Data’s object graph complexity. Direct SQL also makes data export straightforward for users who want to analyze their patterns externally.
Combine for reactive state — Timer state (running, paused, mode, elapsed) propagates through Combine publishers. The menu bar icon, any open windows, and notification scheduling all react to the same state stream. No manual synchronization, no stale UI.
Local-first architecture — All data stays on-device. No accounts, no cloud sync, no analytics collection. The app works offline from day one because there’s nothing to sync.