whoop-up 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -0
- package/CLAUDE.md +277 -0
- package/README.md +278 -0
- package/SKILL.md +235 -0
- package/dist/api/client.d.ts +24 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +149 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/endpoints.d.ts +18 -0
- package/dist/api/endpoints.d.ts.map +1 -0
- package/dist/api/endpoints.js +19 -0
- package/dist/api/endpoints.js.map +1 -0
- package/dist/auth/oauth.d.ts +5 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +140 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/tokens.d.ts +12 -0
- package/dist/auth/tokens.d.ts.map +1 -0
- package/dist/auth/tokens.js +102 -0
- package/dist/auth/tokens.js.map +1 -0
- package/dist/charts/generator.d.ts +8 -0
- package/dist/charts/generator.d.ts.map +1 -0
- package/dist/charts/generator.js +445 -0
- package/dist/charts/generator.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +370 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/types/whoop.d.ts +156 -0
- package/dist/types/whoop.d.ts.map +1 -0
- package/dist/types/whoop.js +3 -0
- package/dist/types/whoop.js.map +1 -0
- package/dist/utils/analysis.d.ts +30 -0
- package/dist/utils/analysis.d.ts.map +1 -0
- package/dist/utils/analysis.js +246 -0
- package/dist/utils/analysis.js.map +1 -0
- package/dist/utils/constants.d.ts +16 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +25 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/date.d.ts +14 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +48 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/errors.d.ts +14 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +36 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/format.d.ts +25 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +262 -0
- package/dist/utils/format.js.map +1 -0
- package/docs/COMMANDS.md +435 -0
- package/package.json +54 -0
- package/references/health_analysis.md +212 -0
- package/src/api/client.ts +207 -0
- package/src/api/endpoints.ts +20 -0
- package/src/auth/oauth.ts +171 -0
- package/src/auth/tokens.ts +120 -0
- package/src/charts/generator.ts +493 -0
- package/src/cli.ts +433 -0
- package/src/index.ts +8 -0
- package/src/types/whoop.ts +192 -0
- package/src/utils/analysis.ts +321 -0
- package/src/utils/constants.ts +32 -0
- package/src/utils/date.ts +58 -0
- package/src/utils/errors.ts +38 -0
- package/src/utils/format.ts +323 -0
- package/tests/cli/cli.test.ts +49 -0
- package/tests/utils/analysis.test.ts +152 -0
- package/tests/utils/date.test.ts +69 -0
- package/tests/utils/errors.test.ts +33 -0
- package/tests/utils/format.test.ts +229 -0
- package/tsconfig.json +19 -0
package/.env.example
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# whoop-up — Claude Code Guide
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
`whoop-up` is a TypeScript CLI tool that fetches, analyzes, and visualizes health data from the WHOOP API v2. It is published to npm and installed globally: `npm install -g whoop-up`.
|
|
6
|
+
|
|
7
|
+
**Origin:** Built on top of [whoop-cli](https://github.com/xonika9/whoop-cli) by xonika9. Extended with:
|
|
8
|
+
- Trend analysis, health insights, full dashboard, interactive HTML charts
|
|
9
|
+
- Retry logic, `--days` shorthand, summary averages, per-minute rate limit awareness
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Architecture
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
src/
|
|
17
|
+
├── index.ts Entry point — loads .env, runs Commander program
|
|
18
|
+
├── cli.ts All CLI commands (Commander.js)
|
|
19
|
+
├── api/
|
|
20
|
+
│ ├── endpoints.ts Base URL, named endpoint paths, byId helpers
|
|
21
|
+
│ └── client.ts All API functions + retry logic + pagination
|
|
22
|
+
├── auth/
|
|
23
|
+
│ ├── oauth.ts OAuth 2.0 login/logout/status/refresh
|
|
24
|
+
│ └── tokens.ts Token storage at ~/.whoop-up/tokens.json
|
|
25
|
+
├── charts/
|
|
26
|
+
│ └── generator.ts HTML chart generation (ApexCharts, opens in browser)
|
|
27
|
+
├── types/
|
|
28
|
+
│ └── whoop.ts All TypeScript interfaces matching the WHOOP API schema
|
|
29
|
+
└── utils/
|
|
30
|
+
├── date.ts Date helpers, WHOOP day boundary (4am cutoff)
|
|
31
|
+
├── format.ts CLI output formatting, summary stats computation
|
|
32
|
+
├── analysis.ts Trend analysis, health insights generation
|
|
33
|
+
└── errors.ts WhoopError class, ExitCode enum, handleError()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Build output:** `dist/` (compiled JS + `.d.ts` + sourcemaps)
|
|
37
|
+
**Binary:** `dist/index.js` — wired to `whoop` via `package.json` `bin` field
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## WHOOP API v2
|
|
42
|
+
|
|
43
|
+
**Base URL:** `https://api.prod.whoop.com/developer/v2`
|
|
44
|
+
**Auth:** OAuth 2.0 Authorization Code flow
|
|
45
|
+
**Token URL:** `https://api.prod.whoop.com/oauth/oauth2/token`
|
|
46
|
+
|
|
47
|
+
### Endpoints we use
|
|
48
|
+
|
|
49
|
+
| Endpoint | Function |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `GET /user/profile/basic` | `getProfile()` |
|
|
52
|
+
| `GET /user/measurement/body` | `getBody()` |
|
|
53
|
+
| `GET /activity/sleep` | `getSleep()` |
|
|
54
|
+
| `GET /activity/sleep/{id}` | `getSleepById(id)` |
|
|
55
|
+
| `GET /recovery` | `getRecovery()` |
|
|
56
|
+
| `GET /cycle` | `getCycle()` |
|
|
57
|
+
| `GET /cycle/{id}` | `getCycleById(id)` |
|
|
58
|
+
| `GET /cycle/{id}/sleep` | `getSleepForCycle(cycleId)` |
|
|
59
|
+
| `GET /cycle/{id}/recovery` | `getRecoveryForCycle(cycleId)` |
|
|
60
|
+
| `GET /activity/workout` | `getWorkout()` |
|
|
61
|
+
| `GET /activity/workout/{id}` | `getWorkoutById(id)` |
|
|
62
|
+
| `DELETE /user/access` | Called by `logout()` to revoke on WHOOP server |
|
|
63
|
+
|
|
64
|
+
### Endpoints NOT used (in spec but unimplemented)
|
|
65
|
+
- `GET /v1/activity-mapping/{activityV1Id}` — maps legacy v1 activity IDs to v2 UUIDs (migration utility, low priority)
|
|
66
|
+
|
|
67
|
+
### Pagination
|
|
68
|
+
All collection endpoints support: `limit` (max 25), `start`, `end`, `nextToken`.
|
|
69
|
+
`fetchAll()` in `client.ts` handles multi-page fetching with a 50-page safety cap.
|
|
70
|
+
|
|
71
|
+
### Rate limiting
|
|
72
|
+
The client retries on HTTP `{429, 500, 502, 503, 504}` with exponential backoff starting at 1s, max 3 retries.
|
|
73
|
+
|
|
74
|
+
**API rate limits (enforced by WHOOP):**
|
|
75
|
+
- **100 requests per minute** ← the binding constraint
|
|
76
|
+
- 10,000 requests per day
|
|
77
|
+
|
|
78
|
+
**During tests and development — always respect the per-minute limit:**
|
|
79
|
+
- Tests must use pure in-memory mocks/fixtures — never call the live API
|
|
80
|
+
- Avoid running multiple `--all` fetches in quick succession in scripts
|
|
81
|
+
- If writing a script that loops over multiple commands, add a delay between calls
|
|
82
|
+
- The `fetchAll()` 50-page safety cap helps stay within daily limits, but the minute limit is the one that bites in practice
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Critical Type System Rules
|
|
87
|
+
|
|
88
|
+
### `score_state` is always checked before accessing `score`
|
|
89
|
+
|
|
90
|
+
Every scored record (`WhoopSleep`, `WhoopRecovery`, `WhoopWorkout`, `WhoopCycle`) has:
|
|
91
|
+
```typescript
|
|
92
|
+
score_state: 'SCORED' | 'PENDING_SCORE' | 'UNSCORABLE'
|
|
93
|
+
score?: <ScoreType> // ONLY present when score_state === 'SCORED'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Always filter before accessing `score`:**
|
|
97
|
+
```typescript
|
|
98
|
+
// Correct
|
|
99
|
+
const scored = records.filter(r => r.score_state === 'SCORED' && r.score != null);
|
|
100
|
+
const value = scored[0].score!.hrv_rmssd_milli;
|
|
101
|
+
|
|
102
|
+
// Wrong — will crash on PENDING_SCORE records
|
|
103
|
+
const value = records[0].score.hrv_rmssd_milli;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This pattern is applied consistently throughout `format.ts` and `analysis.ts`.
|
|
107
|
+
|
|
108
|
+
### `WhoopCycle` does NOT have a `recovery` field
|
|
109
|
+
|
|
110
|
+
The WHOOP API `/v2/cycle` response does **not** embed recovery data. Recovery is a separate resource linked by `cycle_id`. Use `getRecoveryForCycle(cycleId)` or the `/v2/recovery` collection endpoint.
|
|
111
|
+
|
|
112
|
+
### `WhoopSleep.id` is a UUID string, not a number
|
|
113
|
+
|
|
114
|
+
The API returns sleep IDs as UUID strings (e.g. `"ecfc6a15-4661-442f-a9a4-f160dd7afae8"`). Cycle IDs are integers.
|
|
115
|
+
|
|
116
|
+
### Optional score subfields
|
|
117
|
+
|
|
118
|
+
Some score fields are only present on WHOOP 4.0+ hardware:
|
|
119
|
+
- `RecoveryScore.spo2_percentage` — optional
|
|
120
|
+
- `RecoveryScore.skin_temp_celsius` — optional
|
|
121
|
+
|
|
122
|
+
Some sleep score fields may be absent if WHOOP has insufficient data:
|
|
123
|
+
- `SleepScore.sleep_performance_percentage` — optional
|
|
124
|
+
- `SleepScore.sleep_consistency_percentage` — optional
|
|
125
|
+
- `SleepScore.sleep_efficiency_percentage` — optional
|
|
126
|
+
|
|
127
|
+
Always use `?.` or null checks for these.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Key Design Decisions
|
|
132
|
+
|
|
133
|
+
### Default date range is last 7 days (not today)
|
|
134
|
+
Unlike the original `whoopskill_v2`, all data commands default to `--days 7`. This matches the Python skill's behavior and produces more useful results by default.
|
|
135
|
+
|
|
136
|
+
### WHOOP day boundary = 4am
|
|
137
|
+
WHOOP considers a new "day" to start at 4:00 AM. `getWhoopDay()` in `date.ts` handles this — calls before 4am still reference the previous calendar day.
|
|
138
|
+
|
|
139
|
+
### Token storage at `~/.whoop-up/tokens.json`
|
|
140
|
+
Permissions: directory `0700`, file `0600`. Tokens auto-refresh 15 minutes before expiry (`REFRESH_BUFFER_SECONDS = 900`).
|
|
141
|
+
|
|
142
|
+
### Logout revokes server-side
|
|
143
|
+
`logout()` calls `DELETE /v2/user/access` before clearing the local token file. If the server call fails (expired token, network error), it still clears locally and logs a note — never leaves user in a broken state.
|
|
144
|
+
|
|
145
|
+
### No circular imports: auth ↔ client
|
|
146
|
+
`client.ts` imports from `auth/tokens.ts`. `auth/oauth.ts` must NOT import from `client.ts`. The revoke call in `oauth.ts` is implemented as a raw `fetch()` to avoid the cycle.
|
|
147
|
+
|
|
148
|
+
### Charts use CDN ApexCharts
|
|
149
|
+
`charts/generator.ts` produces self-contained HTML files referencing `https://cdn.jsdelivr.net/npm/apexcharts@3`. No local chart dependencies. Files are written to `os.tmpdir()` and opened with the `open` package, or saved with `--output`.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## CLI Commands Reference
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Auth
|
|
157
|
+
whoop auth login
|
|
158
|
+
whoop auth logout # revokes on WHOOP server + clears local tokens
|
|
159
|
+
whoop auth status
|
|
160
|
+
whoop auth refresh
|
|
161
|
+
|
|
162
|
+
# Data collection (all support: -n/--days, -s/--start, -e/--end, -d/--date, -l/--limit, -a/--all, -p/--pretty)
|
|
163
|
+
whoop sleep [options]
|
|
164
|
+
whoop recovery [options]
|
|
165
|
+
whoop workout [options]
|
|
166
|
+
whoop cycle [options]
|
|
167
|
+
whoop profile
|
|
168
|
+
whoop body
|
|
169
|
+
|
|
170
|
+
# Multi-day summary with averages (HRV, RHR, sleep%, sleep hours, strain)
|
|
171
|
+
whoop summary [-n days] [-s start] [-e end] [-c/--color] [--json]
|
|
172
|
+
|
|
173
|
+
# Trend analysis — days must be 7, 14, or 30
|
|
174
|
+
whoop trends [-n 7|14|30] [--json]
|
|
175
|
+
|
|
176
|
+
# AI-style insights
|
|
177
|
+
whoop insights [-n days] [--json]
|
|
178
|
+
|
|
179
|
+
# Full terminal dashboard with today's data and 7-day trends
|
|
180
|
+
whoop dashboard [--json]
|
|
181
|
+
|
|
182
|
+
# HTML charts — opens in browser
|
|
183
|
+
whoop chart <sleep|recovery|strain|hrv|dashboard> [-n days] [-o output.html]
|
|
184
|
+
|
|
185
|
+
# By-ID lookups
|
|
186
|
+
whoop get <sleep|workout|cycle> <id>
|
|
187
|
+
whoop cycle-sleep <cycleId> # sleep linked to a cycle
|
|
188
|
+
whoop cycle-recovery <cycleId> # recovery linked to a cycle
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Development Workflow
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Install and build
|
|
197
|
+
npm install # also runs 'prepare' → 'npm run build'
|
|
198
|
+
|
|
199
|
+
# Development (run without building)
|
|
200
|
+
npm run dev -- sleep --days 7
|
|
201
|
+
|
|
202
|
+
# Build TypeScript → dist/
|
|
203
|
+
npm run build
|
|
204
|
+
|
|
205
|
+
# Test locally as installed CLI
|
|
206
|
+
npm install -g .
|
|
207
|
+
whoop --help
|
|
208
|
+
|
|
209
|
+
# One-shot run (compiled)
|
|
210
|
+
node dist/index.js summary --color
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Environment variables (copy from `.env.example`)
|
|
214
|
+
```
|
|
215
|
+
WHOOP_CLIENT_ID=...
|
|
216
|
+
WHOOP_CLIENT_SECRET=...
|
|
217
|
+
WHOOP_REDIRECT_URI=http://localhost:9876/callback
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Place in `.env` at project root — loaded by `dotenv` at startup.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Publishing to npm
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# First-time login
|
|
228
|
+
npm login
|
|
229
|
+
|
|
230
|
+
# Publish (prepare hook auto-builds)
|
|
231
|
+
npm publish --access public
|
|
232
|
+
|
|
233
|
+
# Users install with:
|
|
234
|
+
npm install -g whoop-up
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Version is set in `package.json`. Bump it before each publish.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Adding a New Feature — Checklist
|
|
242
|
+
|
|
243
|
+
1. **New endpoint?** Add to `src/api/endpoints.ts` (`ENDPOINTS` or `byId`), implement in `src/api/client.ts`, wire up in `src/cli.ts`
|
|
244
|
+
2. **New type?** Add to `src/types/whoop.ts`. If it has a score, use `ScoreState` + optional `score?`
|
|
245
|
+
3. **New CLI command?** Add in `src/cli.ts` before the root flags block
|
|
246
|
+
4. **New chart?** Add to `src/charts/generator.ts`, add `case` to the `chart` command in `cli.ts`
|
|
247
|
+
5. **Always run:** `npm run build` — zero TypeScript errors required before committing
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## File Ownership Map
|
|
252
|
+
|
|
253
|
+
| What you want to change | File to edit |
|
|
254
|
+
|---|---|
|
|
255
|
+
| API endpoint URLs | `src/api/endpoints.ts` |
|
|
256
|
+
| Retry logic, pagination, API auth | `src/api/client.ts` |
|
|
257
|
+
| OAuth login/logout/token refresh | `src/auth/oauth.ts` |
|
|
258
|
+
| Token storage location/format | `src/auth/tokens.ts` |
|
|
259
|
+
| TypeScript types matching API | `src/types/whoop.ts` |
|
|
260
|
+
| CLI commands and options | `src/cli.ts` |
|
|
261
|
+
| Terminal output formatting | `src/utils/format.ts` |
|
|
262
|
+
| Trend/insight calculations | `src/utils/analysis.ts` |
|
|
263
|
+
| Date helpers, WHOOP day boundary | `src/utils/date.ts` |
|
|
264
|
+
| Error codes and handling | `src/utils/errors.ts` |
|
|
265
|
+
| HTML chart generation | `src/charts/generator.ts` |
|
|
266
|
+
| Science-backed health reference | `references/health_analysis.md` |
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Known Constraints
|
|
271
|
+
|
|
272
|
+
- `limit` max is **25** per page (enforced by WHOOP API — sending higher values is silently capped)
|
|
273
|
+
- `trends` command only accepts 7, 14, or 30 days (enforced in CLI; `analyzeTrends()` itself accepts any number)
|
|
274
|
+
- Token expiry buffer is 15 minutes — cron jobs should call `auth refresh` before running to ensure a fresh token
|
|
275
|
+
- `sport_id` on workouts is deprecated and will stop appearing after 09/01/2025 — use `sport_name`
|
|
276
|
+
- `v1_id` on sleep/workout records is deprecated and will stop appearing after 09/01/2025
|
|
277
|
+
- SpO2 and skin temperature only appear for WHOOP 4.0+ hardware users — always check for `null`
|
package/README.md
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# whoop-up
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/whoop-up)
|
|
4
|
+
|
|
5
|
+
CLI for WHOOP health data — fetch, analyze, and visualize via the WHOOP API v2.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g whoop-up
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
whoop auth login # authenticate via browser
|
|
15
|
+
whoop summary --color # color-coded daily snapshot
|
|
16
|
+
whoop dashboard # full dashboard + 7-day trends
|
|
17
|
+
whoop chart dashboard -n 30 -o /tmp/whoop.html # interactive HTML chart
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
1. Register a WHOOP application at [developer.whoop.com](https://developer.whoop.com)
|
|
23
|
+
- Apps with fewer than 10 users don't need WHOOP review (immediate use)
|
|
24
|
+
|
|
25
|
+
2. Set environment variables — create a `.env` file in your working directory:
|
|
26
|
+
|
|
27
|
+
```env
|
|
28
|
+
WHOOP_CLIENT_ID=your_client_id
|
|
29
|
+
WHOOP_CLIENT_SECRET=your_client_secret
|
|
30
|
+
WHOOP_REDIRECT_URI=https://your-redirect-uri.com/callback
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. Authenticate:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
whoop auth login
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Tokens are stored at `~/.whoop-up/tokens.json` and auto-refresh 15 minutes before expiry.
|
|
40
|
+
|
|
41
|
+
## Commands
|
|
42
|
+
|
|
43
|
+
### Auth
|
|
44
|
+
|
|
45
|
+
| Command | Description |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `whoop auth login` | OAuth flow — opens browser, paste callback URL |
|
|
48
|
+
| `whoop auth logout` | Revoke access on WHOOP server + clear local tokens |
|
|
49
|
+
| `whoop auth status` | Show token expiry (does not refresh) |
|
|
50
|
+
| `whoop auth refresh` | Force refresh access token using refresh token |
|
|
51
|
+
|
|
52
|
+
### Data
|
|
53
|
+
|
|
54
|
+
Output is JSON by default. Add `--pretty` for human-readable formatted output.
|
|
55
|
+
|
|
56
|
+
| Command | Description |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `whoop sleep` | Sleep stages, efficiency, respiratory rate |
|
|
59
|
+
| `whoop recovery` | Recovery score, HRV, RHR, SpO2, skin temperature |
|
|
60
|
+
| `whoop workout` | Workouts with strain, HR zones, calories |
|
|
61
|
+
| `whoop cycle` | Daily physiological cycle (strain, calories) |
|
|
62
|
+
| `whoop profile` | User info (name, email) |
|
|
63
|
+
| `whoop body` | Body measurements (height, weight, max HR) |
|
|
64
|
+
|
|
65
|
+
### Analysis
|
|
66
|
+
|
|
67
|
+
Output is pretty-printed by default. Add `--json` for raw JSON.
|
|
68
|
+
|
|
69
|
+
| Command | Description |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `whoop summary` | Multi-day averages: recovery, HRV, RHR, sleep, strain |
|
|
72
|
+
| `whoop summary --color` | Same with 🔴🟡🟢 color-coded status indicators |
|
|
73
|
+
| `whoop dashboard` | Full terminal dashboard with 7-day trends |
|
|
74
|
+
| `whoop trends` | Multi-day trend analysis with direction arrows ↑↓→ |
|
|
75
|
+
| `whoop insights` | Health recommendations based on your recent data |
|
|
76
|
+
|
|
77
|
+
### Charts
|
|
78
|
+
|
|
79
|
+
Interactive HTML charts, opened in browser automatically. Use `-o file.html` to save instead.
|
|
80
|
+
|
|
81
|
+
| Command | Description |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `whoop chart sleep` | Sleep performance and stage breakdown |
|
|
84
|
+
| `whoop chart recovery` | Recovery score and HRV over time |
|
|
85
|
+
| `whoop chart strain` | Daily strain and calorie burn |
|
|
86
|
+
| `whoop chart hrv` | HRV trend |
|
|
87
|
+
| `whoop chart dashboard` | Combined overview (recommended) |
|
|
88
|
+
|
|
89
|
+
### Lookups
|
|
90
|
+
|
|
91
|
+
Fetch a single record by ID. IDs come from collection endpoint responses or `dashboard --json`.
|
|
92
|
+
|
|
93
|
+
| Command | Description |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `whoop get sleep <uuid>` | Full detail for one sleep record (UUID string) |
|
|
96
|
+
| `whoop get workout <uuid>` | Full detail for one workout record (UUID string) |
|
|
97
|
+
| `whoop get cycle <id>` | Full detail for one cycle (integer ID) |
|
|
98
|
+
| `whoop cycle-sleep <cycleId>` | Sleep record linked to a given cycle |
|
|
99
|
+
| `whoop cycle-recovery <cycleId>` | Recovery record linked to a given cycle |
|
|
100
|
+
|
|
101
|
+
## Flags
|
|
102
|
+
|
|
103
|
+
### Data command flags
|
|
104
|
+
|
|
105
|
+
| Flag | Description |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `-n, --days <number>` | Days of history (default: 7) |
|
|
108
|
+
| `-d, --date <date>` | Specific date (YYYY-MM-DD) |
|
|
109
|
+
| `-s, --start <date>` | Range start date |
|
|
110
|
+
| `-e, --end <date>` | Range end date |
|
|
111
|
+
| `-l, --limit <n>` | Max results per page (max: 25) |
|
|
112
|
+
| `-a, --all` | Fetch all pages |
|
|
113
|
+
| `-p, --pretty` | Human-readable output |
|
|
114
|
+
|
|
115
|
+
### Analysis command flags
|
|
116
|
+
|
|
117
|
+
| Flag | Applies to | Description |
|
|
118
|
+
| --- | --- | --- |
|
|
119
|
+
| `-n, --days <number>` | all analysis | Days of history (default: 7) |
|
|
120
|
+
| `-c, --color` | summary | Color-coded status indicators |
|
|
121
|
+
| `--json` | dashboard, trends, insights | Raw JSON output |
|
|
122
|
+
|
|
123
|
+
### Chart flags
|
|
124
|
+
|
|
125
|
+
| Flag | Description |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `-n, --days <number>` | Days of history to chart (default: 7) |
|
|
128
|
+
| `-o, --output <file>` | Save HTML to file instead of opening browser |
|
|
129
|
+
|
|
130
|
+
### Global flags (combine data types)
|
|
131
|
+
|
|
132
|
+
| Flag | Description |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| `--sleep` | Include sleep data |
|
|
135
|
+
| `--recovery` | Include recovery data |
|
|
136
|
+
| `--workout` | Include workout data |
|
|
137
|
+
| `--cycle` | Include cycle data |
|
|
138
|
+
| `--profile` | Include profile |
|
|
139
|
+
| `--body` | Include body measurements |
|
|
140
|
+
|
|
141
|
+
Running `whoop` with no arguments fetches all data types.
|
|
142
|
+
|
|
143
|
+
## Example output
|
|
144
|
+
|
|
145
|
+
`whoop summary --color`:
|
|
146
|
+
```
|
|
147
|
+
📊 7-Day Summary
|
|
148
|
+
|
|
149
|
+
🔴 Avg Recovery: 31.5%
|
|
150
|
+
💓 Avg HRV: 124.4ms
|
|
151
|
+
❤️ Avg RHR: 56.1bpm
|
|
152
|
+
🔴 Avg Sleep: 44.8% | 4.0h
|
|
153
|
+
🔥 Avg Strain: 6.8
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`whoop dashboard`:
|
|
157
|
+
```
|
|
158
|
+
📅 2026-02-17 | Ruben Khachaturov
|
|
159
|
+
|
|
160
|
+
── Recovery ──────────────────────────
|
|
161
|
+
🔴 13% | HRV: 129ms (↑ vs 124 avg) | RHR: 60bpm (↑ vs 56 avg)
|
|
162
|
+
SpO2: 96% | Skin: 33.1°C | Resp: 15.6/min
|
|
163
|
+
|
|
164
|
+
── Sleep ─────────────────────────────
|
|
165
|
+
😴 27% | 2.0h total | Efficiency: 100%
|
|
166
|
+
Deep: 1.0h (49%) | REM: 0.6h (30%) | Light: 0.4h
|
|
167
|
+
Disturbances: 1 | Consistency: 66%
|
|
168
|
+
💤 Sleep debt: 2.1h | Need tonight: 9.7h
|
|
169
|
+
|
|
170
|
+
── Strain ────────────────────────────
|
|
171
|
+
🔥 4.1 / 6 optimal | 767 cal
|
|
172
|
+
|
|
173
|
+
── 7-Day Trends ──────────────────────
|
|
174
|
+
HRV: 148 → 129ms ↓ (range 66-179)
|
|
175
|
+
RHR: 49 → 60bpm ↑ (range 49-64)
|
|
176
|
+
Recovery: 44 → 13% ↓
|
|
177
|
+
Sleep: 4.6 → 2.0h ↓
|
|
178
|
+
Strain: 6.8 avg (range 4.1-16.4)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`whoop trends --days 7`:
|
|
182
|
+
```
|
|
183
|
+
📊 7-Day Trends
|
|
184
|
+
|
|
185
|
+
💚 Recovery: 31.5% avg (5-85) ↓
|
|
186
|
+
💓 HRV: 124.4ms avg (66-179) ↓
|
|
187
|
+
❤️ RHR: 56.1bpm avg (49-64) ↑
|
|
188
|
+
😴 Sleep: 44.8% avg (25-78) ↓
|
|
189
|
+
🛏️ Hours: 4.3h avg (1.3-7.2) ↓
|
|
190
|
+
🔥 Strain: 6.8 avg (4.1-16.4) ↓
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`whoop insights`:
|
|
194
|
+
```
|
|
195
|
+
💡 Insights & Recommendations
|
|
196
|
+
|
|
197
|
+
🔴 Red Recovery
|
|
198
|
+
Recovery at 13% — body needs rest.
|
|
199
|
+
→ Prioritize rest, hydration, and sleep tonight.
|
|
200
|
+
|
|
201
|
+
🔴 Significant Sleep Debt
|
|
202
|
+
You have 2.1 hours of accumulated sleep debt.
|
|
203
|
+
→ Try to get to bed 30-60 min earlier for the next few days.
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`whoop recovery` (default JSON):
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"cycle_id": 1317587415,
|
|
210
|
+
"sleep_id": "5d225f07-8722-4dcf-be52-528e2500bad3",
|
|
211
|
+
"user_id": 30398164,
|
|
212
|
+
"created_at": "2026-02-17T20:02:32.740Z",
|
|
213
|
+
"updated_at": "2026-02-17T20:02:32.740Z",
|
|
214
|
+
"score_state": "SCORED",
|
|
215
|
+
"score": {
|
|
216
|
+
"user_calibrating": false,
|
|
217
|
+
"recovery_score": 13,
|
|
218
|
+
"resting_heart_rate": 60,
|
|
219
|
+
"hrv_rmssd_milli": 128.51297,
|
|
220
|
+
"spo2_percentage": 96,
|
|
221
|
+
"skin_temp_celsius": 33.145668
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Token management
|
|
227
|
+
|
|
228
|
+
`whoop auth status` **does not refresh tokens** — it only reports expiry.
|
|
229
|
+
|
|
230
|
+
For cron jobs or automation:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# Recommended pattern
|
|
234
|
+
whoop auth refresh # ensure fresh token before fetching
|
|
235
|
+
whoop dashboard --json
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
If refresh fails with an expired refresh token, re-authenticate interactively:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
whoop auth login
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Exit codes
|
|
245
|
+
|
|
246
|
+
| Code | Meaning |
|
|
247
|
+
| --- | --- |
|
|
248
|
+
| 0 | Success |
|
|
249
|
+
| 1 | General error |
|
|
250
|
+
| 2 | Authentication error |
|
|
251
|
+
| 3 | Rate limit exceeded |
|
|
252
|
+
| 4 | Network error |
|
|
253
|
+
|
|
254
|
+
## Development
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
git clone https://github.com/mrkhachaturov/whoop-up.git
|
|
258
|
+
cd whoop-up
|
|
259
|
+
npm install
|
|
260
|
+
|
|
261
|
+
npm run dev -- dashboard # run without building
|
|
262
|
+
npm run build # compile TypeScript → dist/
|
|
263
|
+
npm test # run test suite
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Node.js 22+ required.
|
|
267
|
+
|
|
268
|
+
## Full command reference
|
|
269
|
+
|
|
270
|
+
→ [docs/COMMANDS.md](docs/COMMANDS.md)
|
|
271
|
+
|
|
272
|
+
## Attribution
|
|
273
|
+
|
|
274
|
+
Built on top of [whoop-cli](https://github.com/xonika9/whoop-cli) by [xonika9](https://github.com/xonika9).
|
|
275
|
+
|
|
276
|
+
## License
|
|
277
|
+
|
|
278
|
+
MIT
|