一键导入
whoop-fitness
WHOOP fitness integration — daily sleep/recovery/strain profiles, token auto-refresh, and summary delivery via Hermes stdout.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
WHOOP fitness integration — daily sleep/recovery/strain profiles, token auto-refresh, and summary delivery via Hermes stdout.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | whoop-fitness |
| version | 0.1.0 |
| description | WHOOP fitness integration — daily sleep/recovery/strain profiles, token auto-refresh, and summary delivery via Hermes stdout. |
| triggers | ["whoop","recovery","sleep score","strain","fitness data","workout data"] |
Daily WHOOP data sync with automatic token refresh and summary delivery via Hermes. Provides contextual awareness of the user's sleep, recovery, strain, and workout history.
0 12 * * *. ET run time shifts by 1 hour with DST because the cron schedule is fixed in UTC. → fetches WHOOP data → outputs summary to stdout (captured by Hermes for delivery)offline scope refresh token (no re-auth needed)/opt/data/whoop/daily_profile.json is readable by Hermes for contextual awareness/opt/data/whoop/
├── tokens.json # OAuth tokens (access + refresh + client credentials)
├── daily_profile.json # Latest profile summary (JSON: {timestamp, summary_text})
├── daily_profile_raw.json # Latest raw API data (JSON)
skills/custom/whoop-fitness/scripts/
├── whoop_daily.py # Main daily sync script (cron target)
├── whoop_query.py # On-demand Q&A data fetcher
└── run_coach.py # WHOOP-powered running coach
Install: symlink or copy scripts into `/opt/data/scripts/` for cron access.
read:recovery, read:sleep, read:workout, read:cycles, read:profile, read:body_measurement, offlinehttps://<your-fly-app>.fly.dev/callbackGenerate auth URL:
https://api.prod.whoop.com/oauth/oauth2/auth?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&scope=read%3Arecovery+read%3Asleep+read%3Aworkout+read%3Acycles+read%3Aprofile+read%3Abody_measurement+offline&state=<random_8_chars>
Exchange code for tokens (atomic — token never exposed to LLM due to redaction):
curl -s -X POST https://api.prod.whoop.com/oauth/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=<CODE>" \
-d "client_id=<CLIENT_ID>" \
-d "client_secret=<CLIENT_SECRET>" \
-d "redirect_uri=<REDIRECT_URI>" | python3 -c "
import sys, json, os
d = json.load(sys.stdin)
path = '/opt/data/whoop/tokens.json'
os.makedirs(os.path.dirname(path), exist_ok=True)
open(path,'w').write(json.dumps({
'access_token': d['access_token'],
'refresh_token': d.get('refresh_token',''),
'expires_at': '',
'client_id': '<CLIENT_ID>',
'client_secret': '<CLIENT_SECRET>',
'redirect_uri': '<REDIRECT_URI>'
}, indent=2))
os.chmod(path, 0o600)
print(f'Saved. refresh_token: {len(d.get(\"refresh_token\",\"\"))} chars')
"
# In Hermes (8am ET = 12pm UTC during EDT):
cronjob create --name "WHOOP Daily Profile" --schedule "0 12 * * *" --script whoop_daily.py
Note: Cron is hardcoded to UTC. Adjust for DST: 12pm UTC = 8am EDT, 1pm UTC = 8am EST.
https://api.prod.whoop.com/developeroffline scope for refresh tokensGET /v2/user/profile/basic — name, emailGET /v2/user/measurement/body — height, weight, max HRGET /v2/recovery?limit=14 — recovery score, HRV, RHR, SpO2GET /v2/activity/sleep?limit=14 — sleep stages, performance, efficiency, wake time (end field)GET /v2/activity/workout?limit=14 — strain, HR, duration, sport typeGET /v2/cycle?limit=14 — daily strain, caloriesNote: The daily cron (
whoop_daily.py) and run coach (run_coach.py) fetchlimit=14(cycles) tolimit=30(recovery/sleep/workout). On-demand Q&A (whoop_query.py) defaults to 30 days, configurable via argument.
On fetch:
1. Attempt all API calls with current access_token
2. If any endpoint returns 401:
a. POST to /oauth/oauth2/token with grant_type=refresh_token
b. Save new access_token (keep existing refresh_token if none returned)
c. Retry full fetch with new token
d. If refresh fails → write error profile JSON with re-auth URL (built from stored redirect_uri)
security.redact_secrets: true). All token handling must be atomic (curl | python3 → file). Never pass tokens through LLM context. Use execute_code or single shell pipelines.urllib requests (error 1010). Add User-Agent: Mozilla/5.0 hermes-whoop/1.0 header, or use curl instead.timeout=30 (single int), NOT timeout=(5, 30) (tuple is for requests library)./opt/data/whoop/tokens.json (not .env — avoids redaction issues).https://developer.whoop.com/docs/developing/oauth.https://api.prod.whoop.com/developer (not just /whoop.com). Discovered via OpenAPI spec at /developer/doc/openapi.json.state with minimum 8 characters./callback vs /whoop-callback) — no trailing slash.Sleep records include end time which is the user's wake-up time. Scripts convert from UTC to ET using zoneinfo.ZoneInfo('America/New_York') (DST-aware). Typical wake window: 7:50–9:00 AM ET.
When Rishi asks fitness questions, use the WHOOP data to answer. Two approaches:
Read /opt/data/whoop/daily_profile_raw.json — contains data from the last fetch. The daily cron (whoop_daily.py) fetches the last 14 records per endpoint; on-demand runs via whoop_query.py default to 30 days (configurable). Check the file's timestamp to confirm freshness.
python3 /opt/data/scripts/whoop_query.py 30 # fetches last 30 days
Outputs JSON to stdout. Also updates the cache file.
| Type | Example | Approach |
|---|---|---|
| State | "How's my recovery?" | Read latest recovery from cache |
| Trend | "Is my HRV improving?" | Compare 7-day vs 30-day averages |
| Causal | "Did my run affect sleep?" | Correlate workout date → next day sleep |
| Comparison | "Runs vs lifts — what recovers better?" | Group workouts by type, avg next-day recovery |
| Advice | "Should I work out today?" | Check recovery + recent strain + sleep debt |
| Specific | "How much did I sleep Tuesday?" | Filter sleep by date |
| Aggregate | "Total miles this month?" | Sum workout distances |
Q: "Should I run today?" A: "Recovery is 61 🟡. You ran yesterday (strain 13.2) and sleep debt is 1.8hrs. Swap for Z2 stairmaster or rest. If you do run, 30min max, stay in Z2."
Q: "Do I sleep better after runs or lifts?" A: "Last 30 days: after runs — avg sleep perf 84%, 7h 12m. After lifts — 78%, 6h 48m. Run days give you better sleep, especially morning runs. Evening lifts past 7pm correlate with worst sleep."
Q: "Am I overtraining?" A: "Checking... Last 7 days: 6 workouts, avg strain 11.4. Recovery declined 4 of 5 days (72→41). Sleep debt climbing. HRV dipped to 38ms (avg 52ms). ⚠️ Yes, looks like overreaching. Take 2 rest days."
Peer-to-peer call to another Hermes agent over Fly's private network. Use to delegate work to a specialized agent (e.g., squad for coding) or to relay to the user via the gateway. Same skill installed on every agent.
Push a message into Rishi's Telegram chat from inside an API-server invocation. Use when a peer agent (squad, research, etc.) needs to surface a status update, PR-ready notification, or escalation to Rishi but the work was triggered via /v1/chat/completions (where responses don't otherwise land in Telegram). Fire-and-forget: this does not wait for Rishi's reply.
Orchestrate a coding task end-to-end on the Coding Squad: validate scope, plan, dispatch implementer + reviewer subagents, open a PR, handle review feedback, and escalate to the user via Telegram on failure. Enforces all guardrails (repo whitelist, Microsoft firewall, scope ceiling, no merge).
Search NYC apartment listings using NYBits (no-bot-detection). Works from headless servers where StreetEasy/Zillow/Apartments.com block with captchas. Supports filtering by neighborhood, bedrooms, price, fee status, and amenities. Use this skill whenever the user asks to find, search, or browse apartments in NYC.
Install and configure Chrome for headless browser automation on Fly.io. Fixes "Chrome not found" errors from agent-browser. Covers npm global install, Chrome download, AGENT_BROWSER_EXECUTABLE_PATH setup, and PATH configuration.
Generate project ideas via creative constraints.