Agent-first CLI for Garmin Connect: sleep, steps, and activities.
Project description
garmin-cli
Agent-first CLI for Garmin Connect. Wraps the garminconnect Python library so it can be driven from a shell or by an AI agent. Every command emits JSON, exits with a typed code, and carries an actionable hint on failure.
Scope: sleep, steps, and auto-detected activities. Designed to grow.
Not affiliated with, endorsed by, or sponsored by Garmin Ltd. This tool talks to Garmin Connect through the unofficial, reverse-engineered
garminconnectlibrary, not an official Garmin API; it can break if Garmin changes their endpoints.
Install
Requires Python 3.12+.
pipx install garmin-cli
# or:
uv tool install garmin-cli
# or:
pip install garmin-cli
garmin is now on your PATH.
Auth (one-time)
Interactive login. Caches OAuth tokens to ~/.garminconnect (override with $GARMINTOKENS).
garmin auth login
Prompts for email, password, and MFA. Re-run only if subsequent calls fail with auth errors (≈ yearly).
For headless hosts (no TTY): run auth login on a machine with a terminal, then copy ~/.garminconnect/ to the headless host.
Quickstart
# Sleep that ended on 2026-05-11 (Garmin's "wake date" convention)
garmin sleep get --date 2026-05-11
# Steps for a day in 30-min buckets (default is 15m — Garmin's native granularity)
garmin steps get --date 2026-05-11 --bucket 30m
# Walks that Garmin auto-detected on a given day
garmin activities list --date 2026-05-11 --type walking
# All activity types over a date range
garmin activities list --start 2026-05-01 --end 2026-05-11
# Just the timestamps from sleep
garmin sleep get --date 2026-05-11 \
--fields sleepStartTimestampGMT,sleepEndTimestampGMT,sleepWindowConfirmed
# What operations exist?
garmin schema --list
# What does any operation accept and return?
garmin schema sleep.get
garmin schema steps.get
garmin schema activities.list
Agent skills
Bundled, offline agent docs ship inside the package. An agent can read them at runtime or install them locally — no credentials needed.
garmin skills list # one line per skill (name + description)
garmin skills get garmin-shared # print a skill's body
garmin skills install # interactive: ./.claude/skills or ~/.claude/skills
garmin skills install --output-dir ./.claude/skills # non-interactive
Start with garmin-shared (the front door), then the per-resource skills
(garmin-sleep, garmin-steps, garmin-activities) and the
recipe-reconstruct-day workflow.
Common recipes
"Was my 09:00–09:30 commute active?" Pull steps in 30-min buckets, find the slot that overlaps:
garmin steps get --date 2026-05-11 --bucket 30m \
| jq '.[] | select(.startGMT | startswith("2026-05-11T07:00"))'
# (note: startGMT is UTC; convert your local time first)
"Was that empty calendar slot a walk?" Check Garmin's auto-detected activities for that day:
garmin activities list --date 2026-05-11 --type walking \
--fields startTimeLocal,duration,distance,activityName
If nothing comes back, fall back to step buckets and look for sustained primaryActivityLevel == "active" runs.
Output contract
- stdout: JSON (default), NDJSON (
--format ndjson, one object per line), or one-line text (--format text). - stderr: errors as JSON
{"error": ..., "hint": ...}. --fields a.b,c.d: dotted-path filter, comma-separated. Arrays descend implicitly.- Envelope:
garmin sleep getpeels Garmin's outerdailySleepDTOwrapper; you consume the inner object directly. So--fields sleepStartTimestampGMT(notdailySleepDTO.sleepStartTimestampGMT).steps getandactivities listreturn arrays as-is. - Bucket aggregation (steps): Garmin's API returns 15-min buckets.
--bucketrolls them up client-side; sumsstepsand takes the most-activeprimaryActivityLevelacross constituents (none < sleeping < sedentary < active < highlyActive). Bucket must be a multiple of 15 minutes.
Exit codes
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | API error (no confirmed sleep for date, etc.) |
| 2 | auth error (no cached tokens / expired) |
| 3 | validation error (bad --date, etc.) |
| 4 | schema error (unknown op in schema <op>) |
| 5 | internal error |
Tests
uv run pytest -v
License
MIT.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file garmin_cli-0.1.0.tar.gz.
File metadata
- Download URL: garmin_cli-0.1.0.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7214ed43e99c28f3296714b14b73564c72df1d9e6ce80a7b0fe6916f62a75b5f
|
|
| MD5 |
6e73ca0c8cbc39a16f67d4fa20911573
|
|
| BLAKE2b-256 |
b9fa13dc60533252197daf4b634da7418916452d12b76a586ce1e83e5fe8ee89
|
Provenance
The following attestation bundles were made for garmin_cli-0.1.0.tar.gz:
Publisher:
publish.yml on glebmish/garmin-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
garmin_cli-0.1.0.tar.gz -
Subject digest:
7214ed43e99c28f3296714b14b73564c72df1d9e6ce80a7b0fe6916f62a75b5f - Sigstore transparency entry: 1839871597
- Sigstore integration time:
-
Permalink:
glebmish/garmin-cli@72ccd7151e1cf0ab9c77551a00be371e9da0ddbc -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/glebmish
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@72ccd7151e1cf0ab9c77551a00be371e9da0ddbc -
Trigger Event:
push
-
Statement type:
File details
Details for the file garmin_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: garmin_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9270b0ce3eb8d7158b7cd6437133708b022f6944772bdc8f061d6f8b3a3a311a
|
|
| MD5 |
65600d08f40385c614c97a6c927ee201
|
|
| BLAKE2b-256 |
aa4f98afa62028adc1342f0e510b6ade24e67bb03f6daae47c41ccd5bf8f2898
|
Provenance
The following attestation bundles were made for garmin_cli-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on glebmish/garmin-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
garmin_cli-0.1.0-py3-none-any.whl -
Subject digest:
9270b0ce3eb8d7158b7cd6437133708b022f6944772bdc8f061d6f8b3a3a311a - Sigstore transparency entry: 1839871599
- Sigstore integration time:
-
Permalink:
glebmish/garmin-cli@72ccd7151e1cf0ab9c77551a00be371e9da0ddbc -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/glebmish
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@72ccd7151e1cf0ab9c77551a00be371e9da0ddbc -
Trigger Event:
push
-
Statement type: