본문으로 건너뛰기
L

garmin-connect-plugin-for-dsh

likenttt/garmin-connect-plugin-for-dsh

DeepSeek Harness plugin for Garmin Connect — AI-powered fitness data access

설치

dsh plugin --profile web add github:likenttt/garmin-connect-plugin-for-dsh

README

dsh-plugin-garmin-connect

A DeepSeek Harness plugin that brings your Garmin fitness & health data into the AI agent loop.

License: MIT Node.js


More Apps

IconAppWhat it does
GameraSnapGameraSnapControl your phone camera from your Garmin watch
WristAlbumWristAlbumKeep a private photo album on your Garmin
WristTaleWristTaleRead TXT and Markdown on your Garmin watch
WristPassWristPassKeep cards and tickets ready on your wrist
2FA4G2FA4GKeep offline 2FA codes on your Garmin
JiaKe.appJiaKe.appTurn Garmin screenshots into polished assets

What It Does

This plugin connects DeepSeek Harness to Garmin Connect, exposing your wearable data as AI-callable tools. Once installed, the DeepSeek agent can automatically query your activities, sleep, steps, and heart rate to provide personalized fitness insights — all through natural language.

Registered Tools

ToolDescriptionExample Args
get_garmin_activitiesFetch recent activities (runs, rides, swims…) with pace, HR, calories
get_garmin_sleepSleep score, duration, and stage breakdown (deep / light / REM)
get_garmin_stepsDaily step count, goal progress, and walking distance
get_garmin_heart_rateResting, max, and min heart rate for a given day{"startDate": "2023-10-01", "endDate": "2023-10-02"}
get_garmin_weightBody composition (weight, BMI, body fat %, muscle mass, etc.){"startDate": "2023-10-01"}
get_garmin_workoutsPlanned workouts from your Garmin calendar{"limit": 10, "offset": 0}
get_garmin_profileUser profile summarynull
export_garmin_sessionExport a session token for password-free future loginsnull
get_running_skill_adviceExpert running coaching: 8 core training skills with HR zones, practice methods & common mistakes{"query": "threshold", "includeRecentActivities": true}
create_garmin_workoutCreate a structured workout (warmup/interval/repeat/cooldown with pace & HR targets) that syncs to the watch{"name": "Threshold 3×8min", "steps": [...]}

Quick Start

npx --legacy-peer-deps=false @deepseek-ai/dsh plugin --profile web add dsh-plugin-garmin-connect

This single command installs the dependency and activates the plugin layer — the first run automatically initializes the web profile. You only need pnpm on your PATH:

npm install -g pnpm

--legacy-peer-deps=false makes npm resolve peer dependencies normally. If your npm config has legacy-peer-deps=true (it skips peer packages), dsh would fail to boot with ERR_MODULE_NOT_FOUND: Cannot find package '@deepseek-ai/cordis-plugin-group'. On machines without that setting the flag is a harmless no-op.

Verify the plugin layer is composed without booting:

npx --legacy-peer-deps=false @deepseek-ai/dsh --profile web --dump-config | grep -A 2 garmin-connect

Other install sources:

# Local checkout (development)
cd dsh-plugin-garmin-connect && npm install
npx --legacy-peer-deps=false @deepseek-ai/dsh plugin --profile web add .

# GitHub source install
npx --legacy-peer-deps=false @deepseek-ai/dsh plugin --profile web add github:<owner>/<repo>

2. Install the Harness CLI (if you haven't already)

npx --legacy-peer-deps=false @deepseek-ai/dsh web

The web UI starts at http://127.0.0.1:3080 by default. If you launch Harness via npx, keep using the same prefix for the commands below (npx --legacy-peer-deps=false @deepseek-ai/dsh …); if you have dsh installed globally, you can drop the npx @deepseek-ai/ prefix.

3. Configure Credentials

This plugin never stores passwords in config files or logs. Credentials are resolved through environment variables.

# Copy the template
cp .env.example .env

# Edit .env and fill in your Garmin credentials

Put the .env file in the directory you run dsh from (your workspace root) — the plugin loads it automatically.

VariableRequiredDescription
GARMIN_USERNAMEYour Garmin account email
GARMIN_PASSWORD✅*Account password
GARMIN_SESSION_TOKEN✅*Pre-authenticated token (alternative to password)
GARMIN_REGIONglobal (default) or cn for Garmin China
GARMIN_CACHE_TTLCache duration in seconds (default: 300)
GARMIN_LOG_LEVELdebug | info | warn | error
GARMIN_ACTIVITY_DETAILDefault detail for get_garmin_activities: compact (default, curated fields, saves context) or full (all raw Garmin fields)

* You need either GARMIN_PASSWORD or GARMIN_SESSION_TOKEN, not both.

⚠️ If your password contains # or other special characters, wrap it in double quotes — otherwise # and everything after it will be treated as a comment:

GARMIN_PASSWORD="my#secret!pass"

4. Run

npx --legacy-peer-deps=false @deepseek-ai/dsh web

Open http://127.0.0.1:3080. The plugin is loaded when Settings → Plugins → Plugin list shows plugin-garmin-connect as mounted & enabled. Then try: "How was my sleep last night?" or "Show me my last 5 runs."

5. Integration Test (optional)

After configuring .env, you can run the integration test to verify all API connections:

npm run test:integration
📋 Click to expand sample output
🔌 Garmin Connect Integration Test
   Domain : garmin.com
   User   : your-email@example.com
   Date   : 2026-08-18

── 1. Login ──
  ✅ Login successful

── 2. Activities ──
  ✅ Got 3 activities
{
  "id": 23998327113,
  "name": "Wuhan Running",
  "type": "running",
  "startTime": "2026-08-16 19:33:05",
  "distanceMeters": 10017.73,
  "durationSeconds": 3965,
  "averageHeartRate": 145,
  "maxHeartRate": 180,
  "averagePaceMinPerKm": 6.6,
  "calories": 656,
  "elevationGainMeters": 4,
  "averageCadence": 141.78
}

── 3. Sleep ──
  ✅ Sleep score: 82, duration: 7.5h

── 4. Steps ──
  ✅ Steps: {
  "date": "2026-08-18",
  "totalSteps": 8523,
  "goal": 10000,
  "distanceMeters": 6120,
  "highlyActiveSeconds": 1800
}

── 5. Heart Rate ──
  ✅ Resting HR: 42, Max: 98

── 6. Weight / Body Composition ──
  ✅ Weight: 70.5 kg, BMI: 22.3, Body Fat: 15.2%

── 7. Workouts / Calendar ──
  ✅ Got 5 planned workouts
{
  "id": 1422905279,
  "name": "跃升之阶",
  "description": "",
  "sportType": "running",
  "createdDate": "2025-12-28T19:28:56.0",
  "estimatedDurationMins": 94,
  "estimatedDistanceMeters": null
}

── 8. User Profile ──
  ✅ Profile: loaded

── 9. Export Session Token ──
  ✅ Token exported (oauth1 key: ********…)
   💡 To use token-based auth, save the full JSON to GARMIN_SESSION_TOKEN in .env

🏁 Integration test complete.

Security

Your credentials never leave your machine.

Credential Resolution Order

1. Plugin config values (set on the plugin row in a profile patch / `--patch` overlay)
   ↓ fallback
2. Environment variables (.env / shell)
   ↓ fallback
3. Schema defaults

Best Practices

PracticeStatus
Passwords loaded exclusively from process.env
.env is in .gitignore
Secrets marked with role('secret') in Cordis schema — excluded from trajectory logs
Session token support — avoids storing password entirely
Tool outputs never include raw credentials
In-memory cache reduces API calls (rate-limit protection)

For maximum security, log in once with a password, then export and store only the session token:

You (to DeepSeek agent): "Export my Garmin session token"

# Agent calls: export_garmin_session
# → Returns a token string

# Add to .env:
GARMIN_SESSION_TOKEN=<the-token>
# Remove the password:
# GARMIN_PASSWORD=

Use with Other AI Coding Agents (MCP)

This plugin also ships as a standalone MCP (Model Context Protocol) server, so you can use the same Garmin tools with Claude Desktop, Codex CLI, Cursor, Windsurf, and any other MCP-compatible client — no DeepSeek Harness required.

Claude Desktop

Edit ~/.claude/claude_desktop_config.json (Mac) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "garmin-connect": {
      "command": "npx",
      "args": ["-y", "dsh-plugin-garmin-connect", "garmin-connect-mcp"],
      "env": {
        "GARMIN_USERNAME": "your@email.com",
        "GARMIN_PASSWORD": "yourpassword",
        "GARMIN_REGION": "global"
      }
    }
  }
}

Restart Claude Desktop. You'll see a 🔌 icon indicating the tools are loaded. Try: "Show my last 5 runs" or "Create a threshold workout and sync to my watch".

Cursor / Windsurf

  1. Open Settings → MCP Servers → Add Server
  2. Name: garmin-connect
  3. Type: stdio
  4. Command: npx -y dsh-plugin-garmin-connect garmin-connect-mcp
  5. Add environment variables: GARMIN_USERNAME, GARMIN_PASSWORD, GARMIN_REGION

OpenAI Codex CLI

Add to your .codex/config.json:

{
  "mcpServers": {
    "garmin-connect": {
      "command": "npx",
      "args": ["-y", "dsh-plugin-garmin-connect", "garmin-connect-mcp"],
      "env": {
        "GARMIN_USERNAME": "your@email.com",
        "GARMIN_PASSWORD": "yourpassword"
      }
    }
  }
}

Local Development / Manual Run

# Clone and build
git clone https://github.com/Likenttt/garmin-connect-plugin-for-dsh.git
cd dsh-plugin-garmin-connect && npm install && npm run build

# Run the MCP server (stdin/stdout)
GARMIN_USERNAME=xxx GARMIN_PASSWORD=xxx node lib/mcp.js

The MCP server exposes all 10 tools (activities, sleep, steps, heart rate, weight, workouts, profile, session export, running skills, and workout creation) through standard MCP protocol.


Architecture

┌─────────────────────────────────────────┐
│         DeepSeek Harness (dsh)          │
│                                         │
│  ┌───────────────────────────────────┐  │
│  │     dsh-plugin-garmin-connect     │  │
│  │                                   │  │
│  │  ┌─────────┐    ┌─────────────┐  │  │
│  │  │  Config  │───▶│ GarminClient│  │  │
│  │  │ (Schema) │    │  (cached)   │  │  │
│  │  └─────────┘    └──────┬──────┘  │  │
│  │                        │         │  │
│  │  ┌─────────────────────▼───────┐ │  │
│  │  │      Tool Registry (10)     │ │  │
│  │  │  • get_garmin_activities    │ │  │
│  │  │  • get_garmin_sleep         │ │  │
│  │  │  • get_garmin_steps         │ │  │
│  │  │  • get_garmin_heart_rate    │ │  │
│  │  │  • get_garmin_weight        │ │  │
│  │  │  • get_garmin_workouts      │ │  │
│  │  │  • get_garmin_profile       │ │  │
│  │  │  • export_garmin_session    │ │  │
│  │  │  • get_running_skill_advice │ │  │
│  │  │  • create_garmin_workout    │ │  │
│  │  └─────────────────────────────┘ │  │
│  └───────────────────────────────────┘  │
│               Cordis Runtime            │
└────────────────┬────────────────────────┘
                 │
      ┌──────────┴──────────┐
      ▼                     ▼
connect.garmin.com    MCP Server (stdio)
connect.garmin.cn     → Claude / Codex /
                        Cursor / Windsurf

Development

# Clone & install
git clone https://github.com/Likenttt/garmin-connect-plugin-for-dsh.git
cd dsh-plugin-garmin-connect
npm install

# Build
npm run build

# Watch mode
npm run dev

# Run tests
npm test

Project Structure

src/
├── index.ts          # Plugin entry point (Cordis apply function)
├── config.ts         # Configuration schema with env-var resolution
├── client.ts         # Garmin API wrapper with caching
├── mcp.ts            # Standalone MCP server for Claude/Codex/Cursor
├── knowledge/
│   ├── running-skills.ts  # 8-skill running coaching knowledge base
│   └── workout-schema.ts  # Workout definition → Garmin JSON builder
├── tools/
│   └── index.ts      # Tool definitions & registration (10 tools)
└── utils/
    ├── cache.ts       # In-memory TTL cache with SWR
    └── format.ts      # Raw-data → LLM-friendly formatters

Publishing & Distribution

The package is a standard dsh bundle: package.json declares dsh.bundle.patchcordis.patch.yml, and files ships the compiled lib/, both READMEs, and the patch file.

npm run build   # prepublishOnly also runs this automatically
npm publish

After publishing, users install with a single command:

npx --legacy-peer-deps=false @deepseek-ai/dsh plugin --profile web add dsh-plugin-garmin-connect

Distribution notes:

  • npm registry (recommended) — the tarball ships prebuilt lib/, so no build permission is needed at install time.
  • Local checkoutnpx --legacy-peer-deps=false @deepseek-ai/dsh plugin --profile web add . links the source directory; run npm install first.
  • GitHub installsnpx --legacy-peer-deps=false @deepseek-ai/dsh plugin --profile web add github:<owner>/<repo> fetches sources and runs the package's prepare script to build them (self-contained, pinned TypeScript via npx); pnpm ≥ 10 refuses to run the script until you allow it — dsh prints the exact allowBuilds key for the profile's pnpm-workspace.yaml.
  • Add the dsh-plugin topic to your GitHub repository for discoverability.

Roadmap

  • Body Composition — weight, BMI, body fat %
  • Garmin Calendar — planned workouts
  • Workout Creation — create structured workouts that sync to the watch
  • MCP Server — use with Claude Desktop, Codex CLI, Cursor, Windsurf
  • Running Coach — 8-skill training knowledge base
  • Training Status — VO2 Max, training load, recovery time
  • Multi-account Sync — sync activities between CN ↔ Global accounts
    • list_garmin_accounts — list configured accounts with connection status
    • compare_garmin_accounts — diff activities across two accounts (fuzzy match by time + distance + type)
    • sync_garmin_activity — download FIT from source account → upload to target account
    • Duplicate detection — skip activities that already exist in the target
    • Env vars: GARMIN_USERNAME_2 / GARMIN_PASSWORD_2 / GARMIN_REGION_2 (fully backward-compatible)
  • Webhook / Push — real-time activity upload notifications
  • OAuth 2.0 — migrate to official Garmin API when available for personal use

License

MIT


Acknowledgements

관련 플러그인