From 42f37a89f8c80595e2d654437e3692e465159f99 Mon Sep 17 00:00:00 2001 From: Moritz Graf Date: Sun, 20 Sep 2026 08:04:55 +0200 Subject: [PATCH] feat(skills): add garmin-workout skill with sportType validation and schema reference --- skills/garmin-workout/SKILL.md | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 skills/garmin-workout/SKILL.md 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" +} +```