ivoronin/TomatoBar
π World's neatest Pomodoro timer for macOS menu bar
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained β safe to depend on.
Has a license, tests, and CI β clean foundation to fork and modify.
Documented and popular β useful reference codebase to read through.
No critical CVEs, sane security posture β runnable as-is.
- βLast commit 3mo ago
- β10 active contributors
- βMIT licensed
Show 3 more βShow less
- βCI configured
- β Single-maintainer risk β top contributor 89% of recent commits
- β No test directory detected
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README β live-updates from the latest cached analysis.
[](https://repopilot.app/r/ivoronin/tomatobar)Paste at the top of your README.md β renders inline like a shields.io badge.
βΈPreview social card (1200Γ630)
This card auto-renders when someone shares https://repopilot.app/r/ivoronin/tomatobar on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ivoronin/TomatoBar
Generated by RepoPilot Β· 2026-05-10 Β· Source
π€Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale β STOP and ask the user to regenerate it before proceeding. - Treat the AI Β· unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ivoronin/TomatoBar shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything β but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
π―Verdict
GO β Healthy across all four use cases
- Last commit 3mo ago
- 10 active contributors
- MIT licensed
- CI configured
- β Single-maintainer risk β top contributor 89% of recent commits
- β No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
β Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ivoronin/TomatoBar
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale β regenerate it at
repopilot.app/r/ivoronin/TomatoBar.
What it runs against: a local clone of ivoronin/TomatoBar β the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ivoronin/TomatoBar | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit β€ 110 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ivoronin/TomatoBar. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ivoronin/TomatoBar.git
# cd TomatoBar
#
# Then paste this script. Every check is read-only β no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ivoronin/TomatoBar and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ivoronin/TomatoBar(\\.git)?\\b" \\
&& ok "origin remote is ivoronin/TomatoBar" \\
|| miss "origin remote is not ivoronin/TomatoBar (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift β was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "TomatoBar/App.swift" \\
&& ok "TomatoBar/App.swift" \\
|| miss "missing critical file: TomatoBar/App.swift"
test -f "TomatoBar/State.swift" \\
&& ok "TomatoBar/State.swift" \\
|| miss "missing critical file: TomatoBar/State.swift"
test -f "TomatoBar/Timer.swift" \\
&& ok "TomatoBar/Timer.swift" \\
|| miss "missing critical file: TomatoBar/Timer.swift"
test -f "TomatoBar/View.swift" \\
&& ok "TomatoBar/View.swift" \\
|| miss "missing critical file: TomatoBar/View.swift"
test -f "TomatoBar/Notifications.swift" \\
&& ok "TomatoBar/Notifications.swift" \\
|| miss "missing critical file: TomatoBar/Notifications.swift"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 110 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~80d)"
else
miss "last commit was $days_since_last days ago β artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) β safe to trust"
else
echo "artifact has $fail stale claim(s) β regenerate at https://repopilot.app/r/ivoronin/TomatoBar"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
β‘TL;DR
TomatoBar is a lightweight, fully sandboxed macOS menu bar Pomodoro timer written in Swift that displays work/rest intervals in the system menu bar with configurable timers, optional sounds, and notifications. It solves the problem of context-switching fatigue by providing an always-visible, distraction-free time management tool integrated directly into macOS's status bar. Single-target Xcode project structure: TomatoBar/ contains App.swift as the entry point, with Assets.xcassets/ holding all menu bar icons (BarIconWork, BarIconShortRest, BarIconLongRest, BarIconIdle) for visual state indication. State management and timer logic are in the main App.swift file following SwiftUI patterns.
π₯Who it's for
macOS users (particularly developers, writers, and knowledge workers) who practice the Pomodoro Technique and want a minimalist timer that doesn't require a separate window and integrates with their workflow through hotkeys and URL schemes.
π±Maturity & risk
Production-ready and actively maintained. The project has meaningful GitHub downloads, Homebrew distribution, CI/CD via GitHub Actions (see .github/workflows/main.yml), and is at v3.0+ with support for Big Sur+. The codebase is well-organized with SwiftLint configuration, indicating code quality standards are enforced.
Low risk for a mature app. Single maintainer (ivoronin) is a moderate concern for long-term support, but the tight scope (menu bar timer only) and full sandbox (no entitlements) limit surface area. No complex dependency chain visibleβSwift standard library focused. Last activity and issue backlog not specified in provided data, so monitor commit recency.
Active areas of work
Active maintenance indicated by SwiftLint configuration and GitHub Actions CI setup. Version 3.0 dropped older macOS and Touch Bar support to modernize. Feature set is stable; focus appears to be on polish and compatibility (note the quarantine flag workaround in README for Homebrew distribution).
πGet running
Clone the repository, open in Xcode, and build: git clone https://github.com/ivoronin/TomatoBar.git && cd TomatoBar && open TomatoBar.xcodeproj. Xcode 12+ with Swift 5.3+ (check .swift-version) is required. Build via Xcode (Cmd+B) or xcodebuild build -scheme TomatoBar.
Daily commands:
In Xcode: select 'TomatoBar' scheme, pick a macOS target, press Cmd+R. The app will launch and appear in the menu bar. Alternatively: xcodebuild build -scheme TomatoBar then open build/Release/TomatoBar.app.
πΊοΈMap of the codebase
TomatoBar/App.swiftβ Entry point for the macOS app; defines the main application structure and menu bar integrationTomatoBar/State.swiftβ Core state management for the Pomodoro timer; holds session durations, current phase, and timer lifecycleTomatoBar/Timer.swiftβ Timer logic implementation; manages countdown, phase transitions, and observer notificationsTomatoBar/View.swiftβ SwiftUI view layer; renders the menu bar UI, popover, and interactive controlsTomatoBar/Notifications.swiftβ Handles macOS user notifications and desktop alerts when timer phases completeTomatoBar/Player.swiftβ Audio playback system; manages sound effects for timer events (ticking, ding, windup)
π§©Components & responsibilities
- State (ObservableObject) (Swift, Combine @Published, UserDefaults) β Holds all mutable timer state: current phase, elapsed/remaining time, session count, user settings (work/rest durations)
- Failure mode: If State is corrupted or loses reference, timer stops updating and UI freezes; app must be restarted
- Timer (Thread-based countdown) (DispatchSourceTimer, Thread, Combine) β Background thread that decrements time every 1 second and triggers phase transitions; publishes state changes
- Failure mode: If timer thread crashes or is blocked, countdown stalls and notifications are missed; app appears hung
π οΈHow to make changes
Add a new timer phase (e.g., break-within-rest)
- Define the phase enum case in State.swift (e.g., case breakWithinRest) (
TomatoBar/State.swift) - Add duration configuration for the new phase and transition logic in the Timer state machine (
TomatoBar/Timer.swift) - Add a new image asset in Assets.xcassets/BarIcon[PhaseName].imageset with 1x, 2x, 3x variants (
TomatoBar/Assets.xcassets) - Update View.swift to select the correct icon based on the new phase case (
TomatoBar/View.swift) - Add localized string keys in all .lproj/Localizable.strings files for the phase name (
TomatoBar/en.lproj/Localizable.strings)
Add a new sound effect event
- Add the .wav audio file to Assets.xcassets/[EventName].dataset and set the Contents.json accordingly (
TomatoBar/Assets.xcassets) - Add a new method to Player.swift to trigger playback (e.g., func playStartSound()) (
TomatoBar/Player.swift) - Call the new Player method from Timer.swift at the appropriate phase transition point (
TomatoBar/Timer.swift) - Optionally expose an audio toggle in View.swift to allow users to enable/disable the sound (
TomatoBar/View.swift)
Add support for a new language
- Create a new folder TomatoBar/[LanguageCode].lproj/ (e.g., fr.lproj for French) (
TomatoBar) - Copy the key structure from TomatoBar/en.lproj/Localizable.strings and translate all values (
TomatoBar/[LanguageCode].lproj/Localizable.strings) - Add the language configuration to the Xcode project in Build Settings β Localized String Macro Calls (
TomatoBar.xcodeproj/project.pbxproj) - Test on macOS with the system language set to the new locale to verify proper loading (
TomatoBar/App.swift)
π§Why these technologies
- SwiftUI β Modern declarative UI framework native to macOS, enabling efficient menu bar and popover rendering with state binding
- Combine Framework β Reactive programming for state management; Observable objects propagate timer updates to views without manual refresh
- AVFoundation β Native macOS audio playback for sound effects with minimal latency and system integration
- UserNotifications β Native macOS notification API for discreet, actionable alerts aligned with system notification center
- Swift Package Manager β Dependency management for SwiftPM packages; clean separation of local and external dependencies
βοΈTrade-offs already made
-
Menu barβonly UI (no dock app window by default)
- Why: Keeps the timer minimal and out of the way; aligns with Pomodoro philosophy of non-intrusive time tracking
- Consequence: Users must click the menu bar icon to see the popover; less discoverable for new users but reduces distraction
-
Single-phase timer state machine (work β short rest β work β long rest cycle)
- Why: Simple, deterministic Pomodoro flow reduces complexity and decision fatigue
- Consequence: Cannot easily support custom phase sequences or variable-length sessions without architectural changes
-
Configurable work/rest durations stored in UserDefaults (no cloud sync)
- Why: Fast local storage, no network dependency, full sandbox compliance
- Consequence: Settings do not sync across user's devices; each Mac gets independent configuration
-
Sound effects embedded in Assets.xcassets as .wav files
- Why: No external file downloads; app is fully self-contained and offline-capable
- Consequence: App size grows slightly; difficult to swap sounds without rebuilding and resubmitting to App Store
π«Non-goals (don't propose these)
- Does not support task tracking or task list management; timer-only Pomodoro tracker
- Does not sync settings or session history across devices or to cloud
- Does not provide detailed analytics or session reporting
- Does not support Linux or Windows; macOS-only (menu bar exclusive)
πͺ€Traps & gotchas
macOS 11 Big Sur+ is required (no backwards compatibility to earlier versions as of v3.0). App is fully sandboxed with no special entitlements, so file access is restricted to standard app container paths. URL scheme tomatobar:// must be registered in Info.plist for external control to work. The quarantine attribute applied by Homebrew download may prevent launch on first runβusers need --no-quarantine flag or manual approval.
ποΈArchitecture
πRelated repos
michaelvillar/timer-appβ Alternative macOS menu bar timer with similar visual approach; useful reference for state representation patternsamitshekhariitbhu/PomodoroTimerβ Cross-platform Pomodoro implementation; useful for understanding interval management patterns that could apply to TomatoBarSwiftUIX/SwiftUIXβ SwiftUI component library that extends menu bar and system integration capabilities available to menu bar appssindresorhus/macos-app-templateβ Template for modern macOS app development; useful reference for sandboxing patterns and build configuration similar to TomatoBar
πͺPR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add SwiftLint configuration validation to CI/CD pipeline
The repo contains .swiftlint.yml but there's no evidence in .github/workflows/main.yml that SwiftLint is being run as part of CI. This ensures code style consistency across contributions and prevents style-related review comments.
- [ ] Review current
.github/workflows/main.ymlto understand existing build steps - [ ] Add SwiftLint GitHub Action step that lints all Swift files in
TomatoBar/directory - [ ] Configure the action to fail the build on SwiftLint violations
- [ ] Test locally with
swiftlintcommand to verify.swiftlint.ymlrules are enforced
Extract Timer logic into comprehensive unit tests
TomatoBar/Timer.swift is a core component managing Pomodoro intervals but has no corresponding test file. Unit tests for timer state transitions, interval calculations, and pause/resume logic would improve code reliability and prevent regressions.
- [ ] Create
TomatoBarTests/TimerTests.swiftfile in the Xcode project - [ ] Add tests for Timer initialization with different work/rest/long-rest durations
- [ ] Add tests for state transitions (idle β work β shortRest β work β longRest)
- [ ] Add tests for pause/resume functionality and timer accuracy
- [ ] Run tests via
xcodebuild testto verify they pass
Add localization infrastructure for non-English languages
The repo has TomatoBar/en.lproj directory but no localization strings file (.strings) visible. With a growing user base, adding localization support and framework would enable community translations.
- [ ] Create
TomatoBar/en.lproj/Localizable.stringsto extract all hardcoded UI strings fromTomatoBar/View.swift,TomatoBar/App.swift, andTomatoBar/Notifications.swift - [ ] Add documentation in
README.mdexplaining how to contribute translations (e.g., reference to community localization process) - [ ] Add sample localization file (e.g.,
TomatoBar/fr.lproj/Localizable.strings) to demonstrate the structure - [ ] Update build configuration to include localized strings in app bundle and verify with
genstringstool
πΏGood first issues
- Add unit tests for timer state transitions: Create a test file (e.g., TomatoBar/TimerTests.swift) to test the workβrestβwork cycle logic and edge cases like pause/resume, which appear untested in the file list
- Expand JSON event logging: The log file at ~/Library/Containers/.../TomatoBar.log is mentioned in README but no test coverage visible; add tests verifying JSON serialization of state changes and document the schema
- Improve preferences UI documentation: The README lacks a 'Configuration' section explaining all available settings (work duration, rest duration, sound toggle, hotkey); add a Preferences.md file with screenshots
βTop contributors
Click to expand
Top contributors
- @ivoronin β 89 commits
- @Jerry23011 β 3 commits
- @voronin-ilya β 1 commits
- @YiGeon β 1 commits
- @evnoj β 1 commits
πRecent commits
Click to expand
Recent commits
7a92386β Build universal binary in CI to fix Intel Mac support (voronin-ilya)7c5f27eβ Fix CI: trust cert, use build instead of archive, fix awk pattern (ivoronin)d1c1facβ Set manual code signing style for CI (ivoronin)6b134c9β Use self-signed certificate for CI code signing (ivoronin)e6de19fβ Use ad-hoc signing identity in CI build (ivoronin)317369eβ Switch CI from archive to build to avoid code signing (ivoronin)447358cβ Fix code signing for CI with ad-hoc identity (ivoronin)43ecf4eβ Disable code signing in CI (ivoronin)92f52f9β Update CI runner to macos-15 and bump action versions (ivoronin)e9d9b4dβ Update KeyboardShortcuts to 2.4.0 and LaunchAtLogin to 5.0.2 (ivoronin)
πSecurity observations
TomatoBar is a relatively simple macOS Pomodoro timer application with minimal security risks. The codebase shows good security practices: no apparent hardcoded secrets, credentials, or injection vulnerabilities visible in the file structure. The application is a desktop utility without network operations exposed, database interactions, or web components. Main recommendations are to implement proper code signing, add security policy documentation, and regularly audit Swift Package Manager dependencies. Overall security posture is strong for an application of this type.
- Low Β· Missing Code Signing Configuration β
TomatoBar/TomatoBar.entitlements, TomatoBar.xcodeproj/project.pbxproj. The TomatoBar.entitlements file exists but there is no explicit evidence of code signing configuration in the visible project structure. For a macOS application, proper code signing is important for security and distribution through the App Store or direct downloads. Fix: Ensure proper code signing certificates are configured in Xcode build settings and verify signing identity is set for Release builds. - Low Β· No Security Policy Documentation β
Repository root. There is no SECURITY.md or security policy file visible in the repository root. This makes it difficult for security researchers to report vulnerabilities responsibly. Fix: Add a SECURITY.md file with instructions for responsible disclosure of security vulnerabilities. - Low Β· Limited Dependency Visibility β
TomatoBar.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved. The Package.resolved file exists but its contents are not provided for analysis. Without reviewing Swift Package Manager dependencies, potential vulnerable third-party packages cannot be assessed. Fix: Regularly audit Swift Package dependencies using tools like SwiftSec or GitHub's dependency scanning. Review Package.resolved for known vulnerabilities.
LLM-derived; treat as a starting point, not a security audit.
πWhere to read next
- Open issues β current backlog
- Recent PRs β what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals β see the live page for receipts. Re-run on a new commit to refresh.