Personal Pomodoro: Gemini 3.7 Flash Builds a Native Mac App
Testing a model's ceiling by asking it to build a complete macOS menu bar Pomodoro timer — penalty engine, break micro-tasks, stats dashboard — in a single Antigravity session.

Default state. Classic Focus at 25 minutes, Quick Sprint, Deep Work, and custom presets. The 🍅 lives in your menu bar.




A focused model evaluation disguised as a productivity tool. The test: give Gemini 3.7 Flash a non-trivial native macOS app to build from scratch — not a web app, not a script, but a real SwiftUI menu bar application with SPM, AppKit integration, and system-level features — and see how far it gets without intervention.
It got all the way. 18 Swift files across a clean Models/Services/Views architecture, a snooze penalty engine with escalating consequences, 8 curated break micro-tasks, a daily stats dashboard with midnight resets, a sound system wrapping NSSound with live preview, and full preference persistence via UserDefaults. The app runs dockless as a pure LSUIElement accessory — no Dock icon, just a 🍅 in the menu bar that opens a glass popover. The entire build happened in a single session on August 14, 2026.
Timeline
Tested Gemini 3.7 Flash by asking it to build a native macOS Pomodoro timer from scratch — and it delivered a complete menu bar app in a single session. 18 Swift files, zero external dependencies, running dockless via NSApp.setActivationPolicy(.accessory). The app lives in the macOS status bar as a 🍅 icon, opens a 330×550 glass popover with NSPopover, and ticks down via DispatchSourceTimer at 250ms intervals against a wall-clock targetEndDate so the countdown stays accurate even if the system sleeps. The model chose SPM over Xcode, wired MenuBarController through Combine's objectWillChange to keep the menu bar title reactive, and even handled click-outside-to-dismiss with a global event monitor. No hand-holding, no corrections — the architecture decisions were the model's.
The difference between a Pomodoro app you use once and one you keep running is accountability — so the model built a penalty engine. Two free snoozes per session, no judgment. Hit snooze a third time and consequences escalate: a random physical challenge (20 squats, 15 push-ups, 45-second plank, 30 jumping jacks, 1-minute wall sit, or 25 high knees), a 50% break time tax, or a hard lockout that disables the snooze button entirely. There's a maximumDiscipline mode that applies all three. The penalty state tracks snooze count, manages challenge assignment via PenaltyChallenge.randomChallenge(), and resets cleanly between sessions. The menu bar icon swaps from 🍅 to ⚠️ when a penalty is active — a small visual shame signal that's surprisingly effective. Alongside this, the model generated 8 curated break micro-tasks across 7 categories — hydration, stretching, 20-20-20 eye relief, box breathing, desk tidying — each with specific instructions and time estimates. The break task system supports custom entries too.
The last batch of files rounded out the app — daily stats tracking, a sound system with 6 chime options, and the polish to make it feel native. The StatsView tracks completed pomodoros, total focus time, snooze count, penalties incurred, and break tasks checked off, all persisted through UserDefaults via a StorageService singleton that resets at midnight. The sound system wraps NSSound with system chimes (Glass, Ping, Hero, Bottle, Submarine, Tink) and includes a live preview in the settings panel. Every user preference — focus duration, break lengths, snooze increment, penalty policy, sound selection, menu bar display mode — persists across launches. The app runs as a pure LSUIElement accessory: no Dock icon, no window chrome, just a menu bar popover with a tabbed interface (Timer, Break, Stats, Settings) navigated via SF Symbol icon pills. make run builds and launches it. Gemini 3.7 Flash wrote all of this unprompted — 18 files across Models, Services, and Views, with clean separation of concerns and zero compile errors.
Eighteen files compiled, the app appeared in my menu bar, and nothing worked. The 🍅 icon was there. The popover opened. The timer showed 25:00. But clicking Start did nothing. Tapping the tab buttons — Timer, Break, Stats, Settings — nothing. The entire UI was a museum exhibit: look but don't touch. The issue: SwiftUI's default activation model inside an NSPopover doesn't make the popover the key window, so button targets never receive focus. The fix required explicit NSApp.activate(ignoringOtherApps: true) on popover show and rewiring the view hierarchy to use @State-driven tab switching instead of relying on implicit focus. Four minutes, three files rewritten, one rebuild — and the controls came alive. Then the user (me) reported tab label overflow: "Timer," "Break," "Stats," "Settings" crammed into a 330px popover was clipping text. Replaced text labels with SF Symbol icon pills — timer, leaf.fill, chart.bar.fill, gearshape — which fixed the width budget and looked better anyway. In the same pass, the timer's DispatchSourceTimer wasn't initializing on Start because the state machine expected a ready → running transition that the UI wasn't triggering. Wired the button directly to TimerManager.start() and the countdown began ticking. Total debug time from "nothing works" to "everything works": about six minutes. The 14-minute headline is real, but the honest story is 14 minutes to render + 6 minutes to respond.
Realized today that Personal Pomodoro — 26 files, 2,295 lines of Swift, and a full test suite — had been built, debugged, and documented without a single git commit. The project directory had everything: 18 source files across Models, Services, and Views, unit tests, a Makefile, build scripts, and an Info.plist — but git status returned fatal: not a git repository. Switched to Claude Opus 4.6 (Thinking) to handle the housekeeping. Wrote a .gitignore to keep .build/, .swiftpm/, and DerivedData out of the tree, updated the clone URL in README.md, and packaged 2,416 insertions across all 26 files into commit d5a5038. One gh repo create command pushed the whole thing public to GitHub on main — complete with the penalty engine, break micro-tasks, and dockless menu bar controller.