Minimal Bun CLI focused on reliability and ownership of Whoop data.
- OAuth login flow (
login) - one-shot data collection (
dump) - scheduled server mode with periodic token refresh (
server) - SQLite export by default
- optional JSON export
- Runtime/build/test: Bun
- Scheduler: Croner
- OAuth library: openid-client
- DB:
bun:sqlitewith WAL mode
whoosh uses pino with pino-pretty for structured, single-line logs with timestamps.
- Service name is fixed to
whoosh - Level comes from
LOG_LEVEL(defaults toinfo) - Sensitive values are redacted (tokens/cookies/auth headers)
- Login callback server logs request start/end/error with
reqId(x-request-idor generated UUID)
bun installCreate a self-contained native executable for the current platform:
bun run buildOutput:
dist/whoosh
Run it directly:
./dist/whoosh --helpOptional bundle-only build (non-executable JS output):
bun run build:bundleRequired for login and server:
WHOOP_CLIENT_IDWHOOP_CLIENT_SECRET
Optional:
WHOOP_CREDENTIALS_FILE
You can copy .env.example to .env.
Config file format is TOML. If --config is omitted, the app checks ~/.whoosh.toml.
debug = "info"
[credentials]
file = "token.toml"
[export]
output = "sqlite" # sqlite | json
[export.sqlite]
path = "./data/whoosh.sqlite"
[export.json]
path = "./data/whoosh.json"
[server]
crontab = "0 13 * * *"
jwt_refresh_minutes = 45- Tokens are written as TOML (
token.tomldefault). logindefaults to writingtoken.toml(unless--credentialsorWHOOP_CREDENTIALS_FILEoverrides it).
bun run src/cli.ts --helpbun run src/cli.ts loginRemote/server workflow (manual callback paste):
bun run src/cli.ts login --manual --no-auto-openIn manual mode, whoosh prints an authorization URL for your local browser. After authentication, the browser may show a redirect failure page; copy the full redirect URL and paste it back into the CLI prompt to complete token exchange.
bun run src/cli.ts dump --db ./data/whoosh.sqlitebun run src/cli.ts dump --output json --json-path ./data/whoosh.jsonbun run src/cli.ts server --db ./data/whoosh.sqlite- Endpoint fetches are sequential to avoid API burst spikes.
- Retry logic covers transient network/rate-limit/server errors.
- Unrecoverable auth failures are treated as fatal in server mode.
- Dump/server commands require explicit output path via CLI or config.
Schema SQL: src/export/schema.sql
Detailed schema docs: docs/SCHEMA.md
Sample SQL queries: docs/QUERY_EXAMPLES.sql
-- Latest runs
SELECT id, mode, status, started_at, finished_at
FROM dump_runs
ORDER BY id DESC
LIMIT 10;-- Sleep trend
SELECT r.start_time, s.sleep_performance_percentage
FROM sleep_records r
JOIN sleep_score s ON s.sleep_id = r.id
ORDER BY r.start_time DESC
LIMIT 30;-- Recent workouts
SELECT wr.start_time, wr.sport_name, ws.strain, ws.distance_meter
FROM workout_records wr
JOIN workout_score ws ON ws.workout_id = wr.id
ORDER BY wr.start_time DESC
LIMIT 30;bun run typecheck
bun test
bun run check- Agent workflow:
AGENTS.md - Contribution guide:
CONTRIBUTING.md - Architecture notes:
docs/ARCHITECTURE.md - Schema reference:
docs/SCHEMA.md - SQL query examples:
docs/QUERY_EXAMPLES.sql
Apache License 2.0. See LICENSE.