diff --git a/skills/garmin-workout/SKILL.md b/skills/garmin-workout/SKILL.md new file mode 100644 index 0000000..6c3cda8 --- /dev/null +++ b/skills/garmin-workout/SKILL.md @@ -0,0 +1,120 @@ +--- +name: garmin-workout +description: Design, validate, upload, repair, delete, and schedule Garmin Connect workouts. Enforces strict sportType IDs, DTO schemas, and avoids Garmin Connect mobile app list corruption. Use when creating, modifying, uploading, scheduling, or deleting workouts in Garmin Connect. +--- + +# 🏋️ Garmin Connect Workout Manager & Schema Validator + +This skill defines the technical standards, DTO schemas, sport type identifiers, and safety protocols for creating, uploading, scheduling, and managing Garmin Connect workouts without corrupting the Garmin Connect mobile app or web client. + +--- + +## 🚨 Critical Safety Rule: Sport Type Integrity + +Whenever creating or uploading workouts via `garmin__upload_workout` or `schedule_workout`, **BOTH `sportTypeId` (integer) AND `sportTypeKey` (string)** MUST be provided in: +1. The top-level workout object: `workout_data["sportType"]` +2. Every segment object: `workout_data["workoutSegments"][i]["sportType"]` + +### ⚠️ The "0 Workouts" Bug +If you send only `{"sportTypeKey": "yoga"}` without `sportTypeId`, Garmin's backend accepts the HTTP POST but defaults `sportTypeId` to `0` and sets `sportTypeKey: null` in its database. +When the Garmin Connect mobile app (iOS / Android) or modern web UI attempts to deserialize the workout list, it crashes on `null` and displays **"0 Workouts"**, making it appear as if all user workouts were deleted! + +### 📋 Canonical Garmin Sport Type Mapping +| Sport | `sportTypeId` | `sportTypeKey` | `displayOrder` | Notes | +|---|---|---|---|---| +| **Yoga** | `7` | `"yoga"` | `8` | Essential for yoga flows | +| **Running** | `1` | `"running"` | `1` | Standard running | +| **Cycling** | `2` | `"cycling"` | `2` | Road, gravel, Tacx indoor | +| **Strength** | `5` | `"strength_training"` | `5` | Home gym, supersets | +| **Cardio** | `6` | `"cardio_training"` | `6` | General cardio | +| **Pilates** | `8` | `"pilates"` | `9` | Core & flexibility | +| **HIIT** | `9` | `"hiit"` | `7` | Tabata, SIT, sprint intervals | +| **Swimming** | `4` | `"lap_swimming"` | `4` | Pool swimming | +| **Walking** | `12` | `"walking"` | `10` | Recovery walks | +| **Mobility** | `11` | `"mobility"` | `11` | Joint mobility | + +--- + +## 🏗️ Workout JSON Structure Reference + +```json +{ + "workoutName": "GeminiYoga#1 Fixed", + "description": "Optimierte Yoga-Sequenz ohne Redundanz.", + "estimatedDurationInSecs": 1800, + "sportType": { + "sportTypeId": 7, + "sportTypeKey": "yoga", + "displayOrder": 8 + }, + "workoutSegments": [ + { + "segmentOrder": 1, + "sportType": { + "sportTypeId": 7, + "sportTypeKey": "yoga", + "displayOrder": 8 + }, + "workoutSteps": [ + { + "type": "ExecutableStepDTO", + "stepOrder": 1, + "stepType": { + "stepTypeId": 1, + "stepTypeKey": "warmup" + }, + "endCondition": { + "conditionTypeId": 2, + "conditionTypeKey": "time" + }, + "endConditionValue": 60.0, + "targetType": { + "workoutTargetTypeId": 1, + "workoutTargetTypeKey": "no.target" + }, + "description": "Mountain Pose - Atmung etablieren" + } + ] + } + ] +} +``` + +--- + +## 🛠️ Operational Recipes + +### 1. Removing a Corrupted Workout +If a workout was uploaded with `sportTypeId: 0` or corrupt data: +```json +// Tool: mcp:garmin:garmin__delete_workout +{ + "workout_id": 1703067815 +} +``` +*Effect:* Instantly restores Garmin Connect app visibility for all remaining workouts. + +### 2. Uploading a Fixed Workout +```json +// Tool: mcp:garmin:garmin__upload_workout +{ + "workout_data": { + "workoutName": "...", + "sportType": { + "sportTypeId": 7, + "sportTypeKey": "yoga", + "displayOrder": 8 + }, + "workoutSegments": [ ... ] + } +} +``` + +### 3. Scheduling to Watch Calendar +```json +// Tool: mcp:garmin:garmin__schedule_workout +{ + "workout_id": 1703067815, + "calendar_date": "2026-09-20" +} +```