google-health-cli

by Google-Health-APIVerified

Google Health CLI — one command-line tool for the Google Health API. Includes AI agent skills.

207
Stars
19
Forks
Go
Language
8/23/2026
Added
View on GitHubDownload ZIP

⚠️ Third-Party Software Notice

This skill is third-party open-source software developed and hosted independently on GitHub. SkillTip is an informational directory and does not control or maintain the underlying repository. Any security checks displayed are automated and limited in scope. Review the source code before installing.

Read the Terms of Service

Installation

Add to your Claude Code skills directory:

# Add to your Claude Code skills
git clone https://github.com/Google-Health-API/google-health-cli

Getting Started

Guides for using skills like google-health-cli.

Security Report

Verified

Last scanned: —

{
  "status": "PASSED",
  "issues": []
}

README.md

ghealth

CLI for the Google Health API v4 — built for AI agents and developers.

  • 40 verified data types: steps, heart rate, exercise, sleep, weight, SpO2, HRV, ECG, blood glucose, nutrition, and more
  • Agent-first: simplified JSON output, deterministic exit codes, --dry-run, --raw
  • Single binary: go build -o ghealth .

Quick Start

ghealth setup                                              # One-time: GCP project + OAuth
ghealth data steps daily-rollup --from 2026-03-22 --to 2026-03-29  # Weekly step totals
ghealth data heart-rate list --from today --limit 10       # Recent heart rate readings
ghealth schema types                                       # See all available data types

Requirements

Download and Install Go

Installation

git clone https://github.com/Google-Health-API/google-health-cli.git
cd google-health-cli
go build -o ghealth .

Setup

ghealth setup

Walks you through: GCP project ID, OAuth credentials (download from Console — Desktop application type), Health API enablement, scope selection, and browser-based OAuth login.

Files written under ~/.config/ghealth/ (override with GHEALTH_CONFIG_DIR):

  • client_secret.json — your OAuth client (mode 0600)
  • credentials.json — access + refresh tokens (mode 0600, plaintext JSON)
  • config.toml — active profile (project, scopes)

Tokens refresh automatically.

Non-interactive setup (for agents / CI)

ghealth setup \
  --project-id my-project \
  --client-secret ~/Downloads/client_secret_123.json \
  --scopes-preset readonly \
  --skip-enable-api \
  --no-prompt

Add --non-interactive-auth to skip the browser step too — complete later with ghealth auth login --complete <code> (see below).

Authentication

ScenarioMethod
Interactiveghealth setup or ghealth auth login
Headless / no browserghealth auth login --non-interactive → click URL on any device → ghealth auth login --complete <code>
Move tokens between machinesghealth auth exportghealth auth import
Pre-configured tokenexport GHEALTH_ACCESS_TOKEN=ya29...
Credential fileexport GHEALTH_CREDENTIALS_FILE=/path/to/creds.json
GCP environmentApplication Default Credentials (automatic)

Precedence: GHEALTH_ACCESS_TOKEN > GHEALTH_CREDENTIALS_FILE > stored credentials > ADC.

Headless OAuth flow

# 1. On the host running ghealth:
ghealth auth login --non-interactive --scopes-preset readonly
# → JSON with auth_url (PKCE S256 challenge + random state baked in)
#   and a complete_command. pending_auth.json holds the verifier locally.

# 2. Open auth_url in any browser, click "Allow".
#    The browser will redirect to a localhost URL that fails to load — expected.
#    Copy either the full redirected URL or just the 'code' query parameter.

# 3. Back on the ghealth host (both forms work):
ghealth auth login --complete 'http://localhost/?code=4/0AX4XfWh...&state=cQq...'
ghealth auth login --complete 4/0AX4XfWh...
# → state validated, PKCE verifier sent on exchange, tokens persisted.

State mismatch (URL paste with the wrong state parameter) clears the pending flow and returns exit 2. The bare-code form skips state validation but still consumes the pending file, so a stale flow can't be replayed.

Move tokens between machines

# source (already authenticated):
ghealth auth export > /tmp/ghealth-creds.json
scp /tmp/ghealth-creds.json target:

# target (also needs client_secret.json — either run 'ghealth setup --non-interactive-auth' or copy it):
ghealth auth import --file /tmp/ghealth-creds.json

Bootstrap from a fresh machine (no client_secret yet)

When no OAuth client_secret.json is configured, every auth command returns a structured error with a next_steps array — the same six steps every time — so an agent can relay it to a user verbatim without scraping prose:

ghealth auth login
# → exit 5, JSON on stderr:
# {
#   "error": {
#     "type": "config", "code": 5,
#     "message": "No OAuth client_secret.json configured",
#     "hint":    "Run 'ghealth setup' to create or import OAuth credentials",
#     "next_steps": [
#       "Open https://console.cloud.google.com/apis/credentials",
#       "Create or select a Google Cloud project",
#       "Enable the Google Health API (...)",
#       "Create OAuth client ID with Application type: Desktop app",
#       "Download the client_secret JSON",
#       "Run: ghealth setup --client-secret /path/to/client_secret.json"
#     ]
#   }
# }

Same next_steps are emitted by:

  • ghealth auth login (interactive / --non-interactive / --complete)
  • ghealth auth status when neither stored creds nor env creds are present
  • ghealth auth refresh, ghealth auth export (when nothing to refresh/export)
  • ghealth setup --no-prompt when --client-secret is missing

To fetch the checklist without triggering an error (e.g. so an agent can display the bootstrap steps before calling auth at all):

ghealth setup --instructions
# → exit 0, JSON on stdout with status: "instructions" and the next_steps array

Data Types

40 types verified against the live API. Run ghealth schema types for the full list.

TypeKey ValuesOperations
steps(use daily-rollup for countSum)list, rollup, daily-rollup, reconcile
heart-ratebeatsPerMinutelist, rollup, daily-rollup, reconcile
exercisetype, duration, calories, avgHeartRate, noteslist, get, create, update, delete, reconcile, export-tcx
sleepminutesAsleep, minutesAwake, stageMinuteslist, get, create, update, delete, reconcile
weightweightGramslist, get, create, update, delete, rollup, daily-rollup, reconcile
body-fatpercentagelist, get, create, update, delete, rollup, daily-rollup, reconcile
heightheightMillimeterslist, get, create, update, delete, reconcile
distance(use daily-rollup for millimetersSum)list, rollup, daily-rollup, reconcile
heart-rate-variabilityRMSSDlist, reconcile
oxygen-saturationpercentage (SpO2)list, reconcile
altitudealtitude valuelist, rollup, daily-rollup, reconcile
active-zone-minutesactiveZoneMinutes, heartRateZonelist, daily-rollup, reconcile
activity-levelSEDENTARY, LIGHT, MODERATE, VIGOROUSlist, reconcile
basal-energy-burnedkcal per interval (BMR)list, reconcile
active-energy-burnedkcal per interval (activity)list, rollup, daily-rollup, reconcile
vo2-maxVO2 max valuelist, reconcile
total-calories(use daily-rollup for kcalSum)daily-rollup
sedentary-periodsedentary intervalslist, daily-rollup, reconcile
swim-lengths-dataswimStrokeType, strokeCount (use daily-rollup for strokeCountSum)list, rollup, daily-rollup, reconcile
hydration-logmilliliters consumedlist, get, daily-rollup, reconcile
nutrition-lognutrients, energy, mealType, foodlist, get, rollup, daily-rollup, reconcile
foodnutrient profiles, servings (catalog — no time filter)list, get
food-measurement-unitdisplayName (catalog — no time filter)list, get
blood-glucosemg/dL, mealType, measurementTiminglist, get, rollup, daily-rollup, reconcile
core-body-temperaturetemperatureCelsiuslist, get, rollup, daily-rollup, reconcile
electrocardiogramwaveform, resultClassification (requires ecg.readonly)list
irregular-rhythm-notificationalert windows (requires irn.readonly)list
daily-resting-heart-ratebeatsPerMinute per daylist, reconcile
daily-heart-rate-variabilitydaily HRV summarylist, reconcile
daily-oxygen-saturationdaily SpO2 summarylist, reconcile
daily-respiratory-ratedaily respiratory ratelist, reconcile
daily-vo2-maxdaily VO2 maxlist, reconcile
daily-sleep-temperature-derivationstemp deviation from baselinelist, reconcile
respiratory-rate-sleep-summaryper-stage respiratory ratelist, reconcile
run-vo2-maxVO2 max from runninglist, daily-rollup, reconcile
floors(rollup only — countSum)rollup, daily-rollup, reconcile
active-minutes(rollup only)rollup, daily-rollup, reconcile
time-in-heart-rate-zone(rollup only)daily-rollup, reconcile
calories-in-heart-rate-zone(rollup only — caloriesInHeartRateZones array per bucket)rollup, daily-rollup, reconcile
daily-heart-rate-zones(reconcile only)reconcile

Exercise track export

export-tcx writes the raw Google TCX, or — with --as csv — flattens it to one row per trackpoint (time, activity, lap, sport, latitude_deg, longitude_deg, altitude_m, distance_m, heart_rate_bpm, cadence_rpm, speed_mps, watts) for direct pd.read_csv consumption. Indoor activities have no track and yield a header-only CSV; their summary/notes live in data exercise list. Pass --output - to stream to stdout instead of a file.

ghealth data exercise export-tcx --id <id> --output ride.csv --as csv
ghealth data exercise export-tcx --id <id> --output - --as csv | head   # stream to stdout

Usage

Reading data

# Recent heart rate (sample-type: returns individual readings)
ghealth data heart-rate list --from today --limit 10

# Daily step totals for a week (rollup: returns aggregated counts)
ghealth data steps daily-rollup --from 2026-03-22 --to 2026-03-29

# Exercises this month
ghealth data exercise list --from 2026-03-01

# Weight history
ghealth data weight list --limit 20

# Sleep (summary by default, --detail for stage-by-stage breakdown)
ghealth data sleep list --limit 5
ghealth data sleep list --limit 5 --detail

Every read (list, get, rollup, daily-rollup, reconcile) returns the same JSON shape — an object {"dataPoints": [...]} with optional _hints and nextPageToken — so the rows are always under dataPoints.

list returns up to --limit rows (default 500). When more exist it includes a nextPageToken; pass it back with --page-token to fetch the next page losslessly (no rows skipped or repeated):

ghealth data heart-rate list --from 2026-06-15 --limit 500            # → {"dataPoints":[…], "nextPageToken":"ABC"}
ghealth data heart-rate list --from 2026-06-15 --limit 500 --page-token ABC

Important: list vs daily-rollup

Some types (steps, distance) return time intervals without values from list. Use daily-rollup to get totals:

# This returns minute-by-minute intervals (no step count):
ghealth data steps list --from today --limit 5

# This returns daily totals with actual counts:
ghealth data steps daily-rollup --from 2026-03-22 --to 2026-03-29
# → {"dataPoints": [{"date": "2026-03-28", "countSum": "9037"}, ...]}

Gotcha: missing days are NOT zeros

For the presence-aware types — altitude, distance, floors, steps, total-calories — a date that is absent from rollup output means the device was not worn (or did not sync) that day, not that the value was zero. A bucket with countSum: "0" is a true zero: the device was worn and genuinely recorded no activity.

  • Missing date → render as "no data", never coalesce to 0
  • countSum: "0" → true zero (worn, no activity)
  • Never average over absent days as if they were zeros — that silently deflates weekly/monthly stats

Filtering

ghealth data heart-rate list --from 2026-03-28                  # From date
ghealth data heart-rate list --from 2026-03-28 --to 2026-03-29  # Date range
ghealth data heart-rate list --from today --limit 50            # Today, max 50
ghealth data heart-rate list --from yesterday                   # Since yesterday

--filter passes a raw expression to the API (overrides --from/--to). Filter syntax follows AIP-160 — interval types use {type}.interval.civil_start_time (ISO 8601, no Z), sleep uses sleep.interval.civil_end_time (only end-time is filterable), sample types use {type}.sample_time.physical_time (RFC-3339, with Z). Only >= and < comparators are supported.

Writing data

Writable types: exercise, sleep, weight, body-fat, height.

Write operations are asynchronous — the API returns an Operation object. Use list to verify the data was persisted.

To discover the correct JSON format, inspect a real response: ghealth data weight list --raw --limit 1

# Create (use --raw list output to model the payload structure)
ghealth data weight create --json '{"weight": {"weightGrams": 75500, "sampleTime": {"physicalTime": "2026-03-29T10:00:00Z", "utcOffset": "3600s"}}}'

# Update (use --update-mask to specify which fields to change)
ghealth data weight update --id <id> --json '{"weight": {"weightGrams": 76000}}'

# Delete (accepts bare IDs or full resource names)
ghealth data exercise delete --ids 7649353586249326520

Output

Responses are simplified by default — redundant timestamps, empty fields, and repeated metadata are stripped. Timestamps include the user's UTC offset (e.g., +01:00).

ghealth data heart-rate list --from today --limit 2
{
  "dataPoints": [
    {"time": "2026-03-29T16:33:07+01:00", "beatsPerMinute": "80", "source": "Google Pixel Watch 4 (41mm)"},
    {"time": "2026-03-29T16:33:04+01:00", "beatsPerMinute": "80", "source": "Google Pixel Watch 4 (41mm)"}
  ]
}
ghealth data steps daily-rollup --from 2026-03-26 --to 2026-03-29
{
  "dataPoints": [
    {"date": "2026-03-28", "countSum": "9037"},
    {"date": "2026-03-27", "countSum": "2408"},
    {"date": "2026-03-26", "countSum": "6474"}
  ]
}
FlagEffect
--rawReturn the original API response with no simplification
--format tableAligned columns
--format csvCSV output (nested objects flatten to dot-separated columns)
-o, --output <file>Write data to the file; print only a column schema + 3-row preview to stdout. Prefer this over > file (which gives the file but no schema)
--dry-runShow the HTTP request without executing

In --format csv and --format table, the data stream stays pure: _hints and a leftover nextPageToken are written to stderr rather than mixed into the rows, and an empty result emits an empty CSV (never a JSON object). Use -o <file> and the stderr signals together to page through a large export without polluting the CSV.

AI Agent Skills

The repo ships 2 Agent Skills (SKILL.md files) — one for shared prerequisites (auth, setup, global flags) and one covering all 40 data types, operations, patterns, and gotchas.

# Install all skills at once
npx skills add https://github.com/Google-Health-API/google-health-cli

# Or pick only what you need
npx skills add https://github.com/Google-Health-API/google-health-cli/tree/main/skills/ghealth
npx skills add https://github.com/Google-Health-API/google-health-cli/tree/main/skills/ghealth-shared

Agents don't need to read the full skill file upfront. The CLI supports progressive self-discovery:

ghealth schema types              # What types exist? What operations?
ghealth schema type heart-rate    # Fields, parameters, scope for one type
ghealth data <type> --help        # What operations does this type support?
ghealth data <type> list --help   # What flags does this operation take?
ghealth --dry-run ...             # What HTTP request would this send?

Other Commands

ghealth user identity                    # User identity
ghealth user profile get                 # Profile (age, stride length)
ghealth user settings get                # Settings (timezone, units)
ghealth auth status                      # Auth state (scopes, expiry)
ghealth schema types                     # All data types + operations
ghealth schema type heart-rate           # Detail for one type
ghealth schema scopes                    # OAuth scopes
ghealth schema endpoints                 # All API endpoints
ghealth config show                      # Show active configuration (project, scopes, format)
ghealth config set timezone <IANA zone>  # Set a config value (keys: project_id, format, timezone)
ghealth webhooks subscribers list        # Manage push-notification subscribers / subscriptions

webhooks (subscribers, subscriptions, verify) manages project-level push notifications and requires the cloud-platform scope plus a configured project ID — see the skill docs for details.

Because a cloud-platform token is rejected by the data-plane endpoints, keep webhook credentials in a separate config dir from your health-data credentials. auth login always writes tokens to the active config dir, so use a dedicated GHEALTH_CONFIG_DIR for webhooks (not GHEALTH_CREDENTIALS_FILE, which only changes where tokens are read from):

export GHEALTH_CONFIG_DIR=~/.config/ghealth-webhooks
ghealth setup                              # its own client_secret + project
ghealth auth login --scopes cloud-platform
ghealth webhooks subscribers list

Timezones

Date arguments (--from/--to, today, yesterday) resolve against exactly one timezone, chosen in this order:

  1. the active profile's configured zone — ghealth config set timezone <IANA zone>
  2. otherwise, the machine-local timezone

Verifying tokens

ghealth auth status is a fast local check by default — it reports what's configured without making any network calls, and the authenticated field reflects local state only. For env-token / credentials-file modes it is omitted entirely (presence of a token doesn't prove validity).

ghealth auth status --validate

Verifies the access token against Google's tokeninfo endpoint. authenticated then reflects actual validity, and the response includes expires_in and scope from Google.

Exit Codes

CodeMeaning
0Success
1API error (4xx/5xx)
2Auth error (have client_secret, missing or invalid tokens — run ghealth auth login)
3Validation error
4Network error
5Config error (often: no client_secret.json — error carries next_steps for bootstrap)

Errors are always JSON on stderr and may include a next_steps: []string array for multi-step recovery (currently only emitted when no OAuth client is configured).

Environment Variables

VariablePurpose
GHEALTH_ACCESS_TOKENDirect access token
GHEALTH_CREDENTIALS_FILEPath to credential JSON
GHEALTH_CONFIG_DIRConfig directory override
GHEALTH_PROFILEActive profile name
GHEALTH_FORMATDefault output format (json/table/csv)
GHEALTH_BASE_URLOverride the API base URL

License

Apache 2.0 — see LICENSE.

Frequently Asked Questions

What is google-health-cli?

google-health-cli is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by Google-Health-API. Google Health CLI — one command-line tool for the Google Health API. Includes AI agent skills. It has 207 GitHub stars.

Is google-health-cli safe to use?

Yes. google-health-cli passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.

How do I install google-health-cli?

Clone the repository with "git clone https://github.com/Google-Health-API/google-health-cli" and add it to your Claude Code skills directory (see the Installation section above).

What programming language is google-health-cli written in?

google-health-cli is primarily written in Go. It is open-source under Google-Health-API on GitHub, so you can review or fork the full source.

Are there alternatives to google-health-cli?

Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh google-health-cli against similar tools.

Comments (0)

No comments yet. Be the first to share your thoughts!

ECC

by affaan-m

10

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

242,21936,702JavaScript
AI Agentsai-agentsanthropicclaude-code
View details
15

An agentic skills framework & software development methodology that works.

234,96620,863Shell
AI Agentsai-agentsbrainstorming
View details

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

185,94028,768JavaScript
AI Agentsai-agentsanthropicclaude-code
View details

cc-switch

by farion1231

3

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

128,8688,826Rust
AI Agentsclaude-codeai-tools
View details

claude-code

by anthropics

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

120,03119,897Shell
AI Agents
View details

Developers Also Liked

Based on votes and bookmarks from developers who liked this skill

ECC

by affaan-m

10

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

242,21936,702JavaScript
AI Agentsai-agentsanthropicclaude-code
View details
15

An agentic skills framework & software development methodology that works.

234,96620,863Shell
AI Agentsai-agentsbrainstorming
View details

n8n

by n8n-io

12

Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

201,88160,308TypeScript
MCP Serversapisai-tools
View details

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

185,94028,768JavaScript
AI Agentsai-agentsanthropicclaude-code
View details

cc-switch

by farion1231

3

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

128,8688,826Rust
AI Agentsclaude-codeai-tools
View details