π¦ Personal macOS screen time & focus tracking with cloud-synced web dashboard
Gecko is a lightweight menu bar app that silently tracks which application and window you're focused on, recording sessions to a local SQLite database. A companion web dashboard provides screen time analytics with cloud sync via Cloudflare D1. Built for personal use β no telemetry, no App Store sandbox.
- Event-driven focus tracking β listens for app activations via
NSWorkspacenotifications, with an adaptive fallback timer for in-app changes (3s β 6s β 12s based on context stability) - State machine architecture β formal
TrackingStateenum (.stopped,.active,.idle,.locked,.asleep) with explicit transitions and co-located side effects - Energy efficient β 80-95% power reduction: idle detection (>60s), screen lock/sleep suspension, Low Power Mode awareness (1.5Γ interval), title change debounce (2s), and timer leeway for macOS wake-up coalescing
- Browser URL extraction β grabs the current URL from Chrome, Safari, Edge, Brave, Arc, and Vivaldi via AppleScript (skipped entirely for non-browser apps)
- Local SQLite storage β all data stays on your machine at
~/Library/Application Support/ai.hexly.gecko/gecko.sqlite - Cloud sync β background sync to Cloudflare D1 with network awareness (skips when offline), batched uploads, and watermark-based pagination
- Menu bar only β runs as
LSUIElement(no Dock icon), always accessible from the menu bar - Permission onboarding β guides you through granting Accessibility and Automation permissions, with exponential backoff polling
- Secure β API key stored in macOS Keychain, sync requires HTTPS
- Launch at login β optional auto-start via
SMAppService
- Screen time analytics β daily usage breakdown with interactive charts (Recharts), timeline view, and top apps table
- Daily Review β per-day deep dive with score cards, Gantt-style session timeline, and AI-powered analysis (Anthropic / OpenAI)
- Cloud sync β automatic background sync from local SQLite to Cloudflare D1, with batched writes respecting D1's 100-param limit
- App Categories β organize apps into categories (4 built-in defaults + custom). Each category has an icon and a stable hash-derived color
- Tags β flexible tagging system with multi-tag support per app
- App Notes β annotate apps with context for AI analysis
- Public API β
/api/v1/snapshotendpoint for external integrations (Bearer token auth) - API key management β create, rename, and revoke API keys for device sync and public API access
- Backy backup β push/pull cloud data to an external Backy backup service
- Timezone settings β configurable IANA timezone for accurate day boundaries
- Google OAuth β secure authentication via NextAuth v5 (email allowlist)
- Dark mode β system-aware theme switching
- Responsive sidebar β collapsible navigation with smooth CSS grid animations
- Monorepo β clean separation between macOS client and web dashboard
- 6DQ quality gates β L1 unit/coverage, L2 API E2E (real HTTP), L3 Playwright BDD; G1 typecheck+Biome/SwiftLint; G2 security; D1 isolated test DB
- Husky git hooks β pre-commit: G1 + L1; pre-push: L2 β G2; L3 BDD on-demand / CI
- Atomic commits β Conventional Commits format, one logical change per commit
| Tool | Version | Purpose |
|---|---|---|
| macOS | 14.0+ (Sonoma) | Operating system |
| Xcode | 16.0+ | Mac client build |
| XcodeGen | latest | Xcode project generation |
| SwiftLint | latest | Swift linting |
| Node.js | 22+ | Web dashboard runtime (production Docker image, vinext start / vinext dev) |
| Bun | latest | Web dashboard package manager, vinext build, and script runner |
# Clone the repo
git clone https://github.com/nocoo/gecko.git
cd gecko
# Install dependencies & git hooks
bun install
# ββ Mac Client ββ
cd apps/mac-client
xcodegen generate
open Gecko.xcodeproj # Build & run from Xcode
# ββ Web Dashboard ββ
cd apps/web-dashboard
bun install
bun run dev # http://localhost:7018gecko/
βββ π¦ logo.png # App logo (2048Γ2048)
βββ apps/
β βββ mac-client/ # macOS SwiftUI menu bar app
β β βββ project.yml # xcodegen config
β β βββ Gecko/Sources/ # App, Models, Services, Views
β β βββ GeckoTests/ # 194 unit + integration tests
β βββ web-dashboard/ # Web dashboard (vinext + React 19)
β βββ drizzle/ # D1 migration SQL files
β βββ src/
β β βββ app/ # Pages & API routes
β β βββ components/ # UI components (shadcn/ui + custom)
β β βββ lib/ # Utilities, sync queue, D1 client
β βββ src/__tests__/ # 608 unit + 11 E2E + 6 BDD tests
βββ docs/ # Architecture documentation
βββ packages/ # Shared config
βββ scripts/ # Git hooks & tooling
| Dim | Command | Notes |
|---|---|---|
| G1 | bun run typecheck Β· bun run lint Β· mac swiftlint --strict |
Static analysis |
| L1 | bun run test:l1 (web coverage) Β· mac xcodebuild test |
Unit / component |
| L2 | bun run test:l2 (= web test:e2e, port 17018) |
Real HTTP + local SQLite |
| L3 | bun run test:l3 (= web test:bdd, port 27018) |
Playwright browser |
| G2 | cd apps/web-dashboard && bun run gate:security |
osv-scanner + gitleaks |
# G1 + L1 (also what pre-commit runs for web)
bun run typecheck && bun run lint && bun run test:l1
# Mac client β L1 + G1
xcodebuild test -project apps/mac-client/Gecko.xcodeproj \
-scheme Gecko -destination 'platform=macOS' -quiet
cd apps/mac-client && swiftlint lint --strict
# L2 API E2E β stop other vinext dev (e.g. :7018) first
bun run test:l2
# L3 Playwright BDD (CI / on-demand)
bun run test:l3| Layer | Technology |
|---|---|
| Mac Client | Swift 5.10, SwiftUI, GRDB, NSWorkspace |
| Web Framework | vinext (Vite 7 + React 19 RSC) |
| Styling | Tailwind CSS v4, shadcn/ui, Radix UI |
| Auth | NextAuth v5 (Google OAuth) |
| Cloud DB | Cloudflare D1 (SQLite-compatible) |
| Local DB | SQLite via GRDB (mac) |
| Charts | Recharts |
| Testing | Vitest, Bun test (L2), Playwright (L3), XCTest, SwiftLint, Biome |
| CI/Hooks | Husky pre-commit (G1+L1) Β· pre-push (L2βG2) Β· base-ci |
MIT Β© 2026 Zheng Li
