FreeReps
Self-hosted health data server with visualization dashboard and MCP interface
Ask AI about FreeReps
Powered by Claude Β· Grounded in docs
I know everything about FreeReps. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
FreeReps
Freely hosted Records, Evaluation & Processing Server
A self-hosted server that receives health data from Apple Watch and Oura Ring, stores it persistently, visualizes it through a web dashboard with freely configurable correlations, and exposes it as an MCP server for LLMs. The iOS companion app syncs HealthKit data directly to your server, and the built-in Oura integration pulls data via the Oura API.
Acknowledgements
The FreeReps iOS companion app is based on HealthBeat by kempu, an open-source iOS app for syncing Apple Health data. HealthBeat was adapted into the FreeReps companion app for the self-hosted FreeReps server. Licensed under the MIT License.
Screenshots
| Dashboard | Sleep |
|---|---|
![]() | ![]() |
| Metrics | Trends |
|---|---|
![]() | ![]() |
| MCP |
|---|
![]() |
| iOS App | |||
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
Why FreeReps?
Apple Health collects extensive data but offers no way to relate metrics to each other, no API for external analysis, and no export into a queryable system you own.
Other apps compute scores but are closed-source, subscription-based, and opaque. FreeReps takes the opposite approach: raw data + flexible visualization + LLM for interpretation.
Architecture
ββββββββββββββββ HealthKit βββββββββββββββββββββββββββββββββββββββββββ
β FreeReps β βββββββββββββββββ β FreeReps Server β
β iOS App β HTTP POST β β
ββββββββββββββββ β ββββββββββββ βββββββββββββββββββ β
β β Ingest ββ β Storage (DB) β β
ββββββββββββββββ OAuth2 + Poll β β API β β Time Series β β
β Oura Ring β ββββββββββββββββ β ββββββββββββ ββββββββββ¬βββββββββ β
β (API v2) β β ββββββββββββ β β
ββββββββββββββββ β β Oura βββββββββββββ β
β β Sync β (source-priority dedup) β
β ββββββββββββ β
β ββββββββββββ¬βββββββββββ β
β βΌ βΌ β
β ββββββββββββββββββ βββββββββββββββ β
β β Web Dashboard β β MCP Server β β
β β Correlations β β stdio / SSE β β
β β Trends, Charts β ββββββββ¬βββββββ β
β ββββββββββββββββββ β β
βββββββββββββββββββββββββββββββΌββββββββββ
βΌ
Claude (via MCP)
= the actual
"AI coach"
Tech Stack
| Component | Technology |
|---|---|
| Backend | Go (single binary with embedded frontend) |
| Frontend | React 19 + Vite + Tailwind CSS 4 |
| Charts | uPlot (time-series) + Recharts (bar/scatter) |
| Database | PostgreSQL + TimescaleDB |
| Auth & Networking | Tailscale (tsnet) β zero-config TLS + identity |
| iOS App | Swift (HealthKit, BackgroundTasks, ActivityKit) |
| Config | YAML |
| Deployment | Docker Compose |
iOS Companion App
The FreeReps companion app syncs Apple HealthKit data directly to the server over HTTP. No intermediate cloud services, no third-party dependencies β just HealthKit to your server.
What it syncs
- 85+ quantity types β steps, heart rate, blood pressure, blood glucose, body temperature, VO2 max, nutrition, audio exposure, and more
- 22 category types β sleep analysis, menstrual cycles, symptoms, mindfulness, heart events, stand hours
- Workouts β activity type, duration, energy burned, distance, swim strokes, flights climbed
- Blood pressure β systolic/diastolic correlation pairs
- ECG recordings β classification, heart rate, voltage measurements
- Audiograms β hearing sensitivity by frequency
- Workout routes β GPS coordinates recorded during workouts
- Activity summaries β daily ring data (active energy, exercise minutes, stand hours)
Features
- Full and incremental sync β initial backfill of all historical data, then ongoing incremental syncs
- Real-time background sync β HealthKit observer queries for immediate delivery when new data is recorded
- Background processing β periodic sync via BGProcessingTask when the app isn't active
- Live Activity β sync progress on the lock screen and Dynamic Island
- CSV import β import Alpha Progression CSV files via share sheet or file picker
- No dependencies β pure Swift using only Apple frameworks
Requirements
- iOS 16.2+
- Physical device (HealthKit is not available in the Simulator)
- A running FreeReps server accessible from the device's network
Prerequisites
- Tailscale β FreeReps uses Tailscale for authentication and TLS natively (via tsnet). There are no passwords or API keys β access is controlled by your tailnet. Tailscale must be set up before running FreeReps.
- Health Auto Export (iOS, optional) β An alternative way to get Apple Health data into FreeReps via
.haefile exports uploaded withfreereps-upload. Not needed if using the FreeReps companion app. - mcp-proxy (optional) β Required for connecting Claude Desktop to a remote FreeReps instance. Bridges stdioβSSE transports. Install with
brew install mcp-proxyorpip install mcp-proxy.
Quick Start
Server (Docker Compose)
git clone https://github.com/meltforce/FreeReps.git
cd FreeReps/server
cp config.example.yaml config.yaml
# Edit config.yaml β set database password, enable Tailscale
docker compose up -d
To use the pre-built image from Docker Hub instead of building locally, replace the app service's build: . with image: meltforce/freereps:latest in docker-compose.yml.
Test Server (Demo Mode)
Run a FreeReps server with demo data (e.g., for App Store review or sync testing):
Using Docker (recommended)
cd FreeReps/server
cp config.example.yaml config.yaml
# Set tailscale.enabled: false in config.yaml for local dev
docker compose up -d db
docker compose run --rm -e FREEREPS_DEMO=true app
From source
cd FreeReps/server
cp config.example.yaml config.yaml
# Set tailscale.enabled: false in config.yaml for local dev
docker compose up -d db
cd web && npm ci && npm run build && cd ..
go run ./cmd/freereps -config config.yaml -demo
This seeds the database with 90 days of realistic health data including heart rate, sleep, workouts, and activity rings. The data is deterministic and idempotent β restarting with -demo or FREEREPS_DEMO=true won't create duplicates.
The server will be available at http://localhost:8080. To tear down:
docker compose down -v
iOS App
- Open
app/FreeReps.xcodeprojin Xcode - Set your development team and bundle identifier in Signing & Capabilities
- Build and run on a physical device
- In Settings, enter your FreeReps server URL
- Grant HealthKit permissions and start syncing
Upload Tool (macOS)
freereps-upload is a client-side CLI tool that reads .hae files from your iCloud Drive (exported by Health Auto Export), converts them to REST API format, and uploads them to your FreeReps server over Tailscale.
Install:
curl -sSL https://raw.githubusercontent.com/meltforce/FreeReps/main/server/scripts/install-upload.sh | bash
Usage:
# First run β upload all historical data
freereps-upload \
-server https://freereps.your-tailnet.ts.net \
-path ~/Library/Mobile\ Documents/com~apple~CloudDocs/Health\ Auto\ Export/AutoSync
# Subsequent runs β only new/changed files are uploaded (resumable)
freereps-upload \
-server https://freereps.your-tailnet.ts.net \
-path ~/Library/Mobile\ Documents/com~apple~CloudDocs/Health\ Auto\ Export/AutoSync
Flags:
| Flag | Default | Description |
|---|---|---|
-server | (required) | FreeReps server URL |
-path | (required) | Path to AutoSync directory (or parent) |
-dry-run | false | Parse and convert without sending |
-batch-size | 2000 | Data points per metric payload |
-version | Print version and exit |
Requirements: lzfse must be installed (brew install lzfse).
Update / Uninstall:
# Update to latest version
curl -sSL https://raw.githubusercontent.com/meltforce/FreeReps/main/server/scripts/install-upload.sh | bash -s -- --update
# Uninstall
curl -sSL https://raw.githubusercontent.com/meltforce/FreeReps/main/server/scripts/install-upload.sh | bash -s -- --uninstall
State tracking: Upload progress is tracked in ~/.freereps-upload/state.db (SQLite). Files are identified by path + size + SHA-256 hash, so changed files are re-uploaded and the tool is fully resumable.
Data Sources
FreeReps iOS App (recommended)
The companion app syncs HealthKit data directly to the server via HTTP POST. Supports full historical backfill and real-time incremental sync.
Oura Ring
FreeReps integrates directly with the Oura API v2 to pull ring data. Syncs every 30 minutes with 90-day initial backfill.
Data synced:
- Oura-exclusive β readiness score, sleep score, activity score, temperature deviation, stress, recovery, resilience, cardiovascular age
- Overlapping with Apple Watch β heart rate, HRV, SpO2, respiratory rate, steps, active calories, workouts, sleep sessions/stages
Source priority dedup: When both Oura and Apple Watch report the same metric, FreeReps deduplicates at query time using configurable source priority (Settings > Source Priority). Only the highest-priority source's data is shown β no double-counting.
Oura Setup
-
Register an Oura API app at cloud.ouraring.com/oauth/applications:
- Redirect URI:
https://your-freereps-host.ts.net/oura/callback - Privacy Policy URL: your FreeReps website's privacy page
- Terms of Service URL: your FreeReps website's terms page
- Enable all scopes
- Redirect URI:
-
Enter credentials in FreeReps: Go to Settings > Oura Ring, enter your Client ID and Client Secret, click "Save Credentials"
-
Authorize: Click "Authorize with Oura", approve access on Oura's page. You'll be redirected back to FreeReps.
-
Sync starts automatically every 30 minutes. Use "Sync Now" for immediate sync. Check Settings > Import Logs for sync status.
Health Auto Export (iOS, legacy)
The iOS app Health Auto Export can export Apple Health data as .hae files to iCloud Drive, which can then be uploaded to FreeReps using the freereps-upload CLI tool.
Alpha Progression (iOS)
Alpha Progression CSV exports provide detailed strength training data (exercises, sets, reps, weight, RIR).
Upload via the dashboard, the iOS companion app (share sheet / file picker), or POST to /api/v1/ingest/alpha.
Dashboard Features
- Daily Overview β Key metrics at a glance (sleep, HRV, RHR, activity)
- Correlation Explorer β Plot any metric against any other (scatter + overlay, Pearson r)
- Sleep View β Hypnogram, stages, HR/HRV/SpO2 during sleep
- Workout View β HR zones, route map, Alpha Progression sets
- Metrics Deep Dive β Time-series with moving average, normal range band
- Saved Views β Store correlation configurations for quick recall
MCP Server
FreeReps exposes health data to Claude (and other LLMs) via the Model Context Protocol.
Tools: get_health_metrics, get_workouts, get_sleep_data, get_metric_stats, get_correlation, compare_periods, list_available_metrics, get_workout_sets
Resources: daily_summary, recent_workouts, metric_catalog
stdio (Claude Code)
freereps --mcp -config config.yaml
Add to your Claude Code MCP config:
{
"mcpServers": {
"freereps": {
"command": "/path/to/freereps",
"args": ["--mcp", "-config", "/path/to/config.yaml"]
}
}
}
SSE (Remote via mcp-proxy)
The MCP SSE endpoint is available at /mcp/sse when the server is running. To connect Claude Desktop (or other stdio-only clients) to a remote FreeReps instance, use mcp-proxy to bridge stdioβSSE:
brew install mcp-proxy # or: pip install mcp-proxy
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"freereps": {
"command": "mcp-proxy",
"args": ["https://freereps.your-tailnet.ts.net/mcp/sse"]
}
}
}
No local FreeReps binary needed β mcp-proxy handles the transport bridging, and Tailscale handles authentication.
Supported Metrics
| Category | Metrics |
|---|---|
| Cardiovascular | heart_rate, resting_heart_rate, heart_rate_variability, blood_oxygen_saturation, respiratory_rate, vo2_max |
| Sleep | sleep_analysis, apple_sleeping_wrist_temperature |
| Body | weight_body_mass, body_fat_percentage |
| Activity | active_energy, basal_energy_burned, step_count, flights_climbed, apple_exercise_time |
| Oura | readiness_score, sleep_score, activity_score, temperature_deviation, stress, recovery, resilience, cardiovascular_age |
| Workouts | All types (with HR data + routes, deduped across sources) |
Design Principles
- Privacy first β All data stays local. No cloud uploads, no telemetry.
- Self-hosted β Runs on your own server/homelab.
- Data over scores β Raw data + visualization + LLM instead of proprietary algorithms.
- Flexible over opinionated β Correlation explorer instead of hard-wired dashboards.
- Single binary β Go binary with embedded web UI.
API Reference
| Endpoint | Method | Description |
|---|---|---|
/api/v1/ingest/ | POST | Ingest health data JSON |
/api/v1/ingest/alpha | POST | Ingest Alpha Progression CSV |
/api/v1/ingest/import | POST | Unified import (auto-detects format) |
/api/v1/metrics/latest | GET | Latest value per metric |
/api/v1/metrics | GET | Time-range metric query |
/api/v1/metrics/stats | GET | Metric statistics (avg, min, max, stddev) |
/api/v1/timeseries | GET | Time-bucketed metric data |
/api/v1/correlation | GET | Pearson r between two metrics |
/api/v1/sleep | GET | Sleep sessions + stages |
/api/v1/workouts | GET | Workout list with filters |
/api/v1/workouts/{id} | GET | Workout detail |
/api/v1/workouts/{id}/sets | GET | Alpha Progression sets |
/api/v1/allowlist | GET | Metric allowlist |
/api/v1/metrics/available | GET | Available metrics with display metadata |
/api/v1/metrics/visibility | PUT | Save per-user metric visibility |
/api/v1/source-priority | GET/PUT | Source priority configuration |
/api/v1/oura/status | GET | Oura connection status |
/api/v1/oura/credentials | PUT | Save Oura OAuth2 credentials |
/api/v1/oura/authorize | POST | Start Oura OAuth2 flow |
/api/v1/oura/sync | POST | Trigger manual Oura sync |
/api/v1/oura/disconnect | DELETE | Remove Oura connection |
/api/v1/me | GET | Current user identity |









