A complete modernization of karpathy/ulogme for modern macOS (Apple Silicon compatible).
📜 Looking for the original legacy version? See old/README.md
ulogme is a personal activity tracker that runs in the background and logs:
- Active window titles — What apps and windows you're using
- Keystroke counts — How much you're typing (not what you type!)
- Browser URLs — Optional URL tracking for browsers
All data stays on your machine in a local DuckDB database. There are no cloud services or network calls.
- 🍎 Native macOS support (Apple Silicon & Intel)
- 🔒 Privacy-first: only counts keystrokes, never logs key values
- 📊 Beautiful React dashboard with charts and visualizations
- 📅 Logical day boundaries (late night sessions count as previous day)
- 📝 Add notes and daily blog entries
- ⚡ Fast DuckDB storage with powerful analytics queries
# Install Python dependencies
uv sync
# Start the tracker (runs in foreground)
uv run python -m tracker startThe first time you run the tracker, macOS will prompt you to grant Accessibility permission for keystroke monitoring. Go to:
- System Settings → Privacy & Security → Accessibility
- Add your terminal app (Terminal, iTerm, etc.)
To have the tracker start automatically when you log in:
uv run python -m tracker installTo uninstall:
uv run python -m tracker uninstallcd site-template/
# Install dependencies
bun install
# Start the development server
bun run devOpen http://localhost:5173 to view your activity data.
# Start tracker in foreground
uv run python -m tracker start
# Stop running tracker
uv run python -m tracker stop
# Check status
uv run python -m tracker status
# Install as launchd service (auto-start on login)
uv run python -m tracker install
# Remove launchd service
uv run python -m tracker uninstallcd site-template/
# Development mode with hot reload
bun run dev
# Production build
bun run build
bun run prodEdit ulogme.toml to customize:
[tracking]
window_titles = true # Track window titles
browser_tabs = true # Track browser tab titles
browser_urls = true # Track full URLs
keystrokes = true # Count keystrokes
window_poll_interval = 2 # Seconds between window checks
[day_boundary]
hour = 7 # Day starts at 7am (late night = previous day)
[category_mappings.rules]
# Regex patterns to categorize apps
[[category_mappings.rules]]
pattern = "Google Chrome|Safari|Arc"
category = "Browser"
[[category_mappings.rules]]
pattern = "VS Code|Cursor"
category = "Coding"ulogme/
├── tracker/ # Python daemon
│ ├── daemon.py # Main entry point
│ ├── window.py # Window tracking (PyObjC)
│ ├── keyboard.py # Keystroke counting
│ ├── storage.py # DuckDB operations
│ └── launchd.py # macOS service integration
├── site-template/ # React dashboard
│ ├── server.ts # Hono API server
│ ├── backend-lib/ # DuckDB queries
│ └── src/ # React frontend
├── data/ # Database and logs
│ └── ulogme.duckdb
├── old/ # Legacy Python 2.7 version
│ └── README.md # Original documentation
├── pyproject.toml # Python dependencies
├── ulogme.toml # Configuration
└── REWRITE_PLAN.md # Architecture documentation
All data is stored in data/ulogme.duckdb, a local DuckDB database file.
window_events— Active window changes with timestampskey_events— Keystroke counts per time windownotes— User annotationsdaily_blog— Daily journal entriessettings— User preferences
- Keystroke counting only — We never log actual key characters
- Local storage only — All data stays on your machine
- No network calls — The tracker daemon is fully offline
- Accessibility permission — Required for global key monitoring
| Layer | Technology |
|---|---|
| Package Managers | uv (Python), Bun (TypeScript) |
| Database | DuckDB (embedded, columnar, analytics-optimized) |
| Backend | Hono on Bun |
| Frontend | React 19 + Vite + Tailwind CSS + shadcn/ui |
| Charts | Recharts via shadcn/ui ChartContainer |
| Tracker | Python 3.13 + PyObjC (native macOS APIs) |
Original project: karpathy/ulogme by Andrej Karpathy
This is a complete rewrite with modern tooling while preserving the core concepts.


