garminctl

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2026 License: MIT

README

garminctl

Drive Garmin Connect from the terminal — body composition, sleep, steps, heart rate, stress, body battery, and every other Connect endpoint — with named profiles for several accounts, OS-keyring token storage, and table/json/yaml/csv output.

garminctl wraps llehouerou/go-garmin, which does the reverse-engineered auth (OAuth1 → OAuth2 exchange with automatic refresh) and the typed endpoint surface. garminctl adds the parts you actually run: keyring-backed sessions, named profiles, a one-command import from an existing garth / python-garminconnect setup, an MCP server, and an agent safety guard.

The bug it fixes. A long-lived cron that reads Garmin data eventually dies with GarminConnectAuthenticationError because the short-lived OAuth2 token expired and nothing refreshed it. garminctl refreshes before every request from the ~1-year OAuth1 token and persists the new token back to the keyring — so it keeps working unattended.

Built with cliwright.

Install

# Homebrew (macOS/Linux)
brew install jjuanrivvera/tap/garminctl

# Scoop (Windows)
scoop bucket add jjuanrivvera https://github.com/jjuanrivvera/scoop-bucket
scoop install garminctl

# install script (Linux/macOS)
curl -fsSL https://raw.githubusercontent.com/jjuanrivvera/garminctl/main/install.sh | sh

# from source
go install github.com/jjuanrivvera/garminctl/cmd/garminctl@latest

Debian/RPM/Alpine packages are attached to each release.

Authenticate

garminctl has no MFA flow — it reuses tokens you already have or logs in with email + password.

Import an existing garth / python-garminconnect session (recommended):

garminctl init                          # auto-detects ~/.garminconnect
garminctl auth import --from ~/.garminconnect            --profile juan
garminctl auth import --from ~/.garminconnect-vane       --profile vane

import reads oauth1_token.json + oauth2_token.json and stores the translated session in your OS keyring. Nothing is written back to the token directory.

Or log in fresh:

garminctl auth login --email you@example.com     # prompts for the password (hidden)

Check status (offline — no API call):

garminctl auth status
# profile:        juan
# authenticated:  true
# oauth2 expiry:  2026-03-14T09:22:10Z  (expired — refreshes on next call)

Read your data

Every resource takes an optional --date (default today) and honors the global -o format:

garminctl steps
garminctl sleep --date 2026-07-09
garminctl body-composition -o json           # weight, BMI, body-fat %
garminctl stress
garminctl body-battery
garminctl heart-rate
garminctl respiration
garminctl intensity-minutes
Everything else: the connect bridge

The typed resources are the common reads; connect exposes go-garmin's full endpoint registry (68 endpoints) for anything not surfaced directly:

garminctl connect --help                     # list every endpoint group
garminctl connect activities list
Raw escape hatch: api

For a Connect endpoint neither the resources nor connect wrap:

garminctl api /usersummary-service/usersummary/daily
garminctl --dry-run api /userprofile-service/userprofile   # prints the equivalent curl

api signs the request with the active profile's token (redacted under --dry-run). Writes (-X POST|PUT|DELETE) are possible but unusual — the agent guard blocks them by default.

Profiles

garminctl config list                # * marks the default
garminctl config use vane
garminctl --profile juan steps       # one-off override; env GARMINCTL_PROFILE also works

Output

-o table (default), json, yaml, csv. table/csv flatten one level so nested objects stay one row per field.

For AI agents

garminctl mcp                                   # expose the read surface as MCP tools
garminctl agent guard --host claude-code        # emit a PreToolUse safety hook

garminctl is read-only health data, so the guard blocks only the mutation vectors: auth logout (deletes the session), alias set (mints indirections), and api with a write method. See AGENTS.md.

Diagnostics

garminctl doctor        # offline: config + keyring + each profile's token state
garminctl version --check

License

MIT — see LICENSE.

Directories

Path Synopsis
cmd
garminctl command
Command garminctl is a command-line tool for the Garmin Connect API.
Command garminctl is a command-line tool for the Garmin Connect API.
Package commands holds the garminctl command tree.
Package commands holds the garminctl command tree.
internal
api
Package api is a thin authenticated HTTP client for raw Garmin Connect requests — the engine behind `garminctl api`, the escape hatch for endpoints the typed surface doesn't wrap.
Package api is a thin authenticated HTTP client for raw Garmin Connect requests — the engine behind `garminctl api`, the escape hatch for endpoints the typed surface doesn't wrap.
auth
Package auth stores bot tokens out of plaintext.
Package auth stores bot tokens out of plaintext.
config
Package config resolves garminctl's tiny configuration: which profiles (Garmin accounts) exist and which is the default.
Package config resolves garminctl's tiny configuration: which profiles (Garmin accounts) exist and which is the default.
garmin
Package garmin wraps llehouerou/go-garmin with keyring-backed sessions and garth token import.
Package garmin wraps llehouerou/go-garmin with keyring-backed sessions and garth token import.
version
Package version holds build metadata, injected at link time via -ldflags.
Package version holds build metadata, injected at link time via -ldflags.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL