Garmin Tracker
Use this skill when the user asks to sync, rebuild, or validate Garmin training data in garmin_tracking.json (workspace root).
Runtime Prerequisite
playwright-coremust be available in the runtime where the skill executes.- If you get
MODULE_NOT_FOUND: playwright-core, install it in the active workspace:
npm install playwright-core
Scope
- This skill is intentionally narrow: goal tracking for Garmin runners/users (training history summary + upcoming training-plan).
- Out of scope by default: deep telemetry scraping (GPS route internals, split arrays, cadence/power/elevation raw series).
- Out of scope: nutrition workflow orchestration or external workflow integration.
Hard Rules
- Control start date is fixed:
2026-02-01. - Keep these top-level fields:
lastUpdate,planName,currentWeek,summary,history,upcoming,recurring_activities. summary.tomust always be today (YYYY-MM-DD).- Activities must use this canonical shape:
typedistanceKmdurationSecavgPaceSecPerKmavgHrBpmcaloriessourceId
Browser Flow (Garmin)
- Open Garmin activities list page and collect activities from
2026-02-01onward. - Open Garmin training plan page (
/app/training-plan) and refreshcurrentWeek+upcoming. - Keep extraction objective: list/table fields only. No GPS/splits/cadence/power deep scrape.
- If browser action fails, do one in-tool recovery sequence first (
tabs->focus-> freshsnapshot) before escalation.
Session/Auth Contract
- The user signs in locally to Garmin in the browser profile used by OpenClaw.
- If Garmin page indicates signed-out session, ask user to sign in and then rerun.
- Do not store user credentials in the skill files.
Authentication (Priority Order)
Use this strict order:
- Logged browser session (preferred): reuse existing authenticated Garmin session.
- Guided manual login in the controlled browser/profile.
- Credentials fallback only if browser login is not possible or explicitly rejected by the user.
sync_training_plan.mjs supports:
--auth-source auto(default): use existing browser session; if signed out and credentials are available, try credentials login.--auth-source browser: never use credentials; require manual login.--auth-source credentials: require credentials and attempt login directly.
Authentication (User Guidance)
If the user is signed out, guide with explicit steps:
- Ask for manual sign-in in the controlled browser profile:
https://connect.garmin.com/signin/->https://connect.garmin.com/app/training-plan-> rerun sync. - If browser sign-in is not possible, request credentials as fallback and run credentials mode.
Notes:
- Authentication policy (browser-first vs credentials-first) may be configured by the operator for each environment.
- In containerized browser setups that expose a remote UI, use the configured noVNC/VNC endpoint to complete login when needed.
- In host-browser mode, sign in directly in the host browser profile configured in OpenClaw.
Credentials Mode (Fallback)
If browser sign-in is not possible, credentials mode can be used as fallback.
Rules:
- Ask only what is strictly required (username/email + password, and 2FA code only if prompted).
- Use credentials only for the login action, then discard from working memory/context when possible.
- Never write credentials to
MEMORY.md,garmin_tracking.json, logs, or skill files. - Never echo credentials back in responses.
- After login success, continue with normal session-based flow.
Data Rebuild Flow
- Read current
garmin_tracking.json. - Preserve
planNameandrecurring_activities. - Rebuild
historyfrom Garmin activities (>= control start date). - Recompute
summaryfrom rebuilthistory. - Set
summary.toto today andlastUpdateto current timestamp.
Local Validator/Reconciler Script
Use the bundled script for schema normalization and summary recomputation:
python3 {baseDir}/scripts/reconcile_tracking.py --file garmin_tracking.json --write
Check-only mode:
python3 {baseDir}/scripts/reconcile_tracking.py --file garmin_tracking.json
Training Plan Sync Script
Use the bundled script to refresh currentWeek and upcoming from Garmin Training Plan:
node {baseDir}/scripts/sync_training_plan.mjs --file garmin_tracking.json --write
Credentials fallback example (last resort):
node {baseDir}/scripts/sync_training_plan.mjs \
--auth-source credentials \
--garmin-email "user@example.com" \
--garmin-password "***" \
--file garmin_tracking.json \
--write
CDP resolution priority:
--cdp-url(explicit override)- OpenClaw config (
browser.defaultProfile->browser.profiles.<profile>.cdpUrl) from--configpath - fallback to the script default CDP endpoint for local setups (
http://127.0.0.1:<port>)
Override example:
node {baseDir}/scripts/sync_training_plan.mjs --config data/config/openclaw.json --url "https://connect.garmin.com/app/training-plan" --file garmin_tracking.json --write
Minimal Parser Tests
Run parser fixtures:
node --test {baseDir}/scripts/__tests__/training_plan_parser.test.mjs
Final Checks
- File is valid JSON.
- No
nutritionLogkey exists. history[].activities[]are canonical.summary.toequals today.