Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
052b86b
Fix missing warning method in ProgressReporter
velazcod Dec 1, 2025
aeba69d
Fix MFA prompt not triggering during sync login
velazcod Dec 1, 2025
b6c97e4
Fix NULL value constraint failure in timeseries storage
velazcod Dec 1, 2025
7623cc7
Support saved authentication tokens in sync CLI
velazcod Dec 1, 2025
6c5aecb
Handle None values in metric parsing
velazcod Dec 1, 2025
575b6ac
Add exercise sets sync for strength training activities
velazcod Dec 2, 2025
0e1059b
Add splits/laps sync for cardio activities
velazcod Dec 2, 2025
393f435
Add body composition sync and enhanced sleep data fields
velazcod Dec 3, 2025
86d49c6
Populate activity distance from splits data
Dec 4, 2025
08257d0
Add .DS_Store to .gitignore
velazcod Dec 4, 2025
8b484de
Add multi-profile support via --profile-path and GARMY_PROFILE_PATH
velazcod Dec 4, 2025
2ed2a71
Add HTTP/SSE network transport support to MCP server
velazcod Dec 10, 2025
3901084
Add sync_health_data tool to MCP server
velazcod Dec 10, 2025
5f4b120
Add workout management module with fuzzy exercise name matching
velazcod Jan 15, 2026
f2805da
Fix workout reps end condition ID and improve MCP documentation
velazcod Jan 17, 2026
ec7e81e
Fix workout weight display on Garmin mobile app
velazcod Jan 17, 2026
c48b442
Add --resync-days flag to force re-fetch of recently completed sync r…
velazcod Mar 3, 2026
99998b0
Fix timeseries sync crash on NULL/NaN values
Mar 5, 2026
eb11122
Add skip-last-rest support for repeat groups in workouts and MCP server
velazcod Mar 7, 2026
32b28b4
Fix MCP workout tools failing when access token expires between daemo…
velazcod Mar 14, 2026
bc3efa0
Add SpO2 metric and enable HRV timeseries/baseline storage
Mar 24, 2026
40bd57a
Add resting HR, intensity minutes, and floors daily aggregate metrics
Mar 25, 2026
d88068e
Add post-activity performance metrics (training status, endurance score)
Mar 25, 2026
b32647e
Update README metrics table and package docstring with all PR1-PR3 me…
Mar 25, 2026
48bbb79
Clarify timeseries timestamp is epoch ms in MCP docs and SQL examples
Mar 25, 2026
df13230
Merge pull request #1 from zaheerm/fix-timeseries-null-nan-crash
velazcod Mar 25, 2026
2839ded
Merge pull request #2 from jtiisto/feature/timeseries-metrics
velazcod Mar 25, 2026
2f97625
Merge pull request #3 from jtiisto/feature/daily-aggregate-metrics
velazcod Mar 25, 2026
ae06504
Merge pull request #4 from jtiisto/feature/post-activity-metrics
velazcod Mar 25, 2026
c763d8d
feat: add health snapshot support across api, localdb, and mcp
velazcod May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ celerybeat.pid
*.sage.py

# Environments
.DS_Store
.env
.venv
env/
Expand Down Expand Up @@ -213,4 +214,4 @@ log.txt
*.broken
test_*coverage*.py
test_remaining*.py
test_final*.py
test_final*.py
106 changes: 104 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ An AI-powered Python library for Garmin Connect API designed specifically for he
- **🏥 Health Analytics**: Advanced data analysis capabilities for fitness and wellness insights
- **📊 Rich Metrics**: Complete access to sleep, heart rate, stress, training readiness, and more
- **💾 Local Database**: Built-in SQLite database for local health data storage and sync
- **👥 Multi-Profile Support**: Manage multiple Garmin accounts with isolated profile directories
- **🖥️ CLI Tools**: Command-line interfaces for data synchronization and MCP server management
- **🤖 MCP Server**: Model Context Protocol server for AI assistant integration (Claude Desktop)
- **⚡ High Performance**: Optimized for high-performance AI applications
Expand Down Expand Up @@ -89,6 +90,37 @@ garmy-mcp info --database health.db
garmy-mcp config
```

### Multi-Profile Support

Garmy supports multiple Garmin accounts through profile directories. Each profile contains its own authentication tokens and database.

```bash
# Using --profile-path (note: must come before the subcommand)
garmy-sync --profile-path ~/profiles/user1 sync --last-days 7
garmy-sync --profile-path ~/profiles/user2 sync --last-days 7

# Using environment variable
export GARMY_PROFILE_PATH=~/profiles/user1
garmy-sync sync --last-days 7

# MCP server with profile
garmy-mcp server --profile-path ~/profiles/user1
```

**Profile Directory Structure:**
```
~/profiles/user1/
├── oauth1_token.json # Garmin OAuth1 credentials
├── oauth2_token.json # Garmin OAuth2 credentials
├── health.db # User's health database
└── logs/ # Sync logs
```

**Priority Order:**
1. `--profile-path` CLI argument (highest)
2. `GARMY_PROFILE_PATH` environment variable
3. `~/.garmy/` default directory (fallback)

### AI Assistant Integration (Claude Desktop)

Add to your Claude Desktop configuration (`~/.claude_desktop_config.json`):
Expand All @@ -104,6 +136,35 @@ Add to your Claude Desktop configuration (`~/.claude_desktop_config.json`):
}
```

**Using profiles with Claude Desktop:**

```json
{
"mcpServers": {
"garmy-localdb": {
"command": "garmy-mcp",
"args": ["server", "--profile-path", "/path/to/profiles/user1", "--max-rows", "500"]
}
}
}
```

Or using environment variables:

```json
{
"mcpServers": {
"garmy-localdb": {
"command": "garmy-mcp",
"args": ["server", "--max-rows", "500"],
"env": {
"GARMY_PROFILE_PATH": "/path/to/profiles/user1"
}
}
}
}
```

Now ask Claude: *"What health data do I have available? Analyze my sleep patterns over the last month."*

## 📊 Available Health Metrics
Expand All @@ -119,6 +180,14 @@ Garmy provides access to a comprehensive set of Garmin Connect metrics:
| `training_readiness` | Training readiness scores and factors | `api_client.metrics.get('training_readiness').get()` |
| `body_battery` | Body battery energy levels | `api_client.metrics.get('body_battery').get()` |
| `activities` | Activity summaries and details | `api_client.metrics.get('activities').list(days=30)` |
| `hrv` | Heart rate variability with sleep readings | `api_client.metrics.get('hrv').get()` |
| `spo2` | Blood oxygen saturation with hourly averages | `api_client.metrics.get('spo2').get()` |
| `respiration` | Breathing rate (waking and sleep) | `api_client.metrics.get('respiration').get()` |
| `resting_heart_rate` | Dedicated resting HR from user stats | `api_client.metrics.get('resting_heart_rate').get()` |
| `intensity_minutes` | Moderate/vigorous intensity with timeseries | `api_client.metrics.get('intensity_minutes').get()` |
| `floors` | Floors climbed and descended | `api_client.metrics.get('floors').get()` |
| `training_status` | Training status, load balance (acute/chronic) | `api_client.metrics.get('training_status').get()` |
| `endurance_score` | Endurance score with classification | `api_client.metrics.get('endurance_score').get()` |

## 🧑‍💻 Architecture Overview

Expand Down Expand Up @@ -187,14 +256,25 @@ def health_agent():
garmy-sync sync --last-days 90 # Sync 3 months of data
garmy-mcp server --database health.db # Start MCP server
# Use Claude Desktop or Python to analyze trends, correlations, patterns

# Multi-user household analysis
garmy-sync --profile-path ~/profiles/user1 sync --last-days 90
garmy-sync --profile-path ~/profiles/user2 sync --last-days 90
# Each profile has isolated credentials and database
```

### For Health Researchers
### For Health Researchers
```python
# Large-scale health data collection
from garmy.localdb import SyncManager
from pathlib import Path

sync_manager = SyncManager(db_path="research_data.db")
# Using a profile directory for tokens and database
profile_path = Path.home() / "profiles" / "researcher"
sync_manager = SyncManager(
db_path=profile_path / "health.db",
token_dir=str(profile_path) # Tokens stored in profile directory
)
sync_manager.initialize(email, password)

# Collect comprehensive health dataset
Expand All @@ -213,6 +293,28 @@ stats = sync_manager.sync_range(
- **🛡️ Query Validation**: SQL injection prevention and query limits
- **🔑 Secure Auth**: OAuth token management with automatic refresh
- **🚫 No Data Sharing**: Health data never leaves your local environment
- **👥 Profile Isolation**: Each profile has separate credentials and database

## ⚙️ Configuration

### Environment Variables

| Variable | Description |
|----------|-------------|
| `GARMY_PROFILE_PATH` | Profile directory path (contains tokens and database) |
| `GARMY_DB_PATH` | Database file path (for MCP server, overridden by `--database`) |

### Shell Configuration Example

Add to your `~/.zshrc` or `~/.bashrc`:

```bash
# Set default profile
export GARMY_PROFILE_PATH="$HOME/Services/Garmy/profiles/default"

# Optional: Activate venv alias
alias garmy-activate="source ~/Services/Garmy/.venv/bin/activate"
```

## 🧪 Examples

Expand Down
Loading