Local-first macOS activity tracker with a menu-bar UI and a Flask dashboard. Everything stays on your machine.
Status: early / experimental — works on the author's machine, your mileage may vary. Expect rough edges and breaking changes.
- Menu-bar app/task switcher with per-client weekly hour budgets
- Idle detection (5-minute default threshold)
- Active-tab URL capture for Chrome, Safari, and Brave
- Optional blurred screenshots of the active window (off by default)
- Local web dashboard at
http://127.0.0.1:9876 - All data stored locally in
~/.timetracker/(SQLite + JPEGs)
- macOS 12 or later
- Python 3.11+ (3.13 tested)
Download the latest TimeTracker.zip from Releases. It's signed with Apple Developer ID and notarized, so Gatekeeper accepts it on first launch with no warnings.
unzip TimeTracker.zip -d /Applications/
open /Applications/TimeTracker.apppip install -r requirements.txt
python3 run.pyEither way, a TT icon appears in the menu bar. Click it to pick a client/task, or open the dashboard:
open http://127.0.0.1:9876macOS will prompt for these the first time TimeTracker needs them. Here's what each is for, so you know what you're saying yes to:
| Permission | Why | Where in the code |
|---|---|---|
| Apple Events | Reads the active tab's URL from Chrome/Safari/Brave so web work can be categorized | tracker/browser.py |
| Accessibility | Reads the focused-window title via the AX API | tracker/monitor.py |
| Screen Recording (optional, off by default) | Only used if you turn on screenshots in the dashboard | tracker/screenshots.py |
~/.timetracker/
├── timetracker.db SQLite — activity, clients, tasks, budgets
├── timetracker.log Application log
├── crash.log Uncaught exceptions
├── screenshot_settings.json
└── screenshots/<date>/*.jpg Blurred JPEGs (if screenshots enabled)
Nothing is sent off-device.
config.py— poll interval, dashboard host/port, idle threshold, screenshot defaultscategories.json— app/domain → category mapping (edit to taste)
These are the first things to fix. PRs welcome.
- No auth on the dashboard. The Flask server binds to
127.0.0.1, but any local process on your machine can read all your activity, view screenshots, and POST changes. - No automated tests.
- macOS only — depends on PyObjC and Quartz APIs.
- No
pip install .support yet —setup.pyis currently py2app-only.