Architecture
Overview
Local (Two UI Options) Remote Server (optional)
───────────────────── ─────────────────────────
Option A: Electron Menubar App
┌─────────────────────────────┐
│ VibeReps.app (port 8800) │──┬── ~/.vibereps/exercises.jsonl
│ ├── session-manager.js │ │
│ └── exercise_ui.html │ └── POST /api/log ──▶ FastAPI
└─────────────────────────────┘ (server/main.py)
Option B: Web Browser
┌─────────────────────────────┐
│ exercise_tracker.py │──┬── ~/.vibereps/exercises.jsonl
│ (ports 8765-8774) │ │
│ └── exercise_ui.html │ └── POST /api/log ──▶ FastAPI
└─────────────────────────────┘
Usage Statistics
┌─────────────────────────────┐
│ vibereps-usage.py │◀── ~/.vibereps/exercises.jsonl
│ │◀── ccusage (Claude Code usage)
└─────────────────────────────┘
Claude Code ────────MCP over HTTP────▶ /mcp endpoint
├── get_stats
├── get_leaderboard
├── check_streak
└── log_exercise_sessionLocal Components
Electron Menubar App (electron/)
Native macOS app with:
main.js: Main process, Express server on port 8800, tray managementsession-manager.js: Tracks multiple Claude instances (10-min timeout)preload.js: Secure IPC bridge to rendererassets/mediapipe/: Bundled pose detection models (~44MB)
Session states: active → waiting_exercise → exercising → complete
Exercise Tracker (exercise_tracker.py)
A Python script that:
- Launches a local HTTP server on ports 8765-8774
- Serves
exercise_ui.html - Handles exercise completion callbacks
- Logs results to
~/.vibereps/exercises.jsonl(always) - Posts results to remote server (if configured)
Key functions:
start_web_server()- Starts the HTTP serverlog_to_local()- Saves exercise data to local JSONL filelog_to_remote()- Sends data to remote API (optional)
Exercise UI (exercise_ui.html)
A self-contained HTML file with:
- MediaPipe Pose integration (loaded from CDN)
- Camera access and video processing
- Real-time pose landmark visualization
- Exercise detection state machines
- Rep counting logic
No build step required - everything is in one file.
Notification Hook (notify_complete.py)
Signals the exercise UI when Claude finishes:
- POSTs to
http://localhost:8765/notify - Exercise UI polls
/statusendpoint - Shows desktop notification when complete
Data Flow
PostToolUse Mode (Recommended)
1. Claude edits code
↓
2. PostToolUse hook triggers
↓
3. exercise_tracker.py launches with ?quick=true
↓
4. User does quick exercises
↓
5. Exercise complete → Hook POSTs to remote server
↓
6. Claude finishes task → Notification hook triggers
↓
7. notify_complete.py POSTs to /notify
↓
8. UI shows notification, user returns to ClaudeExercise Detection Flow
1. Camera captures frame
↓
2. MediaPipe extracts pose landmarks (33 points)
↓
3. Detection function calculates angles/positions
↓
4. State machine updates (ready → down → up)
↓
5. Rep counter increments on state transitions
↓
6. UI updates with new countState Machine
Each exercise uses a simple state machine:
┌──────────────────────────────────┐
│ │
▼ │
┌─────┐ ┌──────┐ ┌────┐ │
│ready│ ───▶ │ down │ ───▶ │ up │ ────┘
└─────┘ └──────┘ └────┘
│
│ repCount++
▼Hysteresis
Different thresholds for transitions prevent jitter:
javascript
// Squats example
DOWN_THRESHOLD = 100° // Must reach 100° to enter "down"
UP_THRESHOLD = 160° // Must reach 160° to complete rep
// The 60° gap prevents false triggers from small movementsPrivacy
- All video processing is client-side in the browser
- No video data is transmitted or stored
- Only rep counts go to the server
- Local server only listens on
localhost:8765 - Camera stream never leaves your machine