Skip to content

Commit eee4e19

Browse files
DTTerastarclaude
andauthored
docs: trim prime to one screen, per CONTRACT §6 (#33)
The prime as shipped was 143 lines — three terminal screens — exactly the man-page bloat the shared contract calls out: "Prime is short. It is not a man page. If it grows past one terminal screen, something belongs in this contract instead." What came out: - Per-subcommand JSON key dumps (~35 lines): redundant with '<subcommand> --since 1d --format json', which is now the documented way to discover row schemas. - OAuth setup prose (~15 lines): the redirectmeto trick stays because it's the one non-obvious bit; everything else belongs in 'auth login --help'. - Two of the five examples; multi-line gotchas tightened to bullets. Result: 47 lines, fits on a single terminal screen. Same shape as crono and liftoff after their parallel diet. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5269502 commit eee4e19

1 file changed

Lines changed: 32 additions & 118 deletions

File tree

‎cmd/prime.go‎

Lines changed: 32 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -10,145 +10,59 @@ const primeText = `withings-export — primer for LLM agents
1010
=======================================
1111
1212
WHAT IT IS
13-
A CLI that reads your personal Withings health data — activity, sleep,
14-
workouts, body measurements (weight/fat/BP/etc), and minute-level
15-
intraday samples (HR/HRV/SpO2/steps) — and prints it on stdout.
13+
CLI for personal Withings data: activity, sleep, workouts, body
14+
measurements, minute-level intraday samples (HR/HRV/SpO2/steps).
1615
17-
OUTPUT FORMATS
18-
Default: narrow, fitdown-style markdown — date-grouped headings, tight
19-
one-line stat blocks per row, easy to skim and easy for an LLM to
20-
consume inline.
21-
22-
--format json Pretty-printed JSON ARRAY of full rows. Use this when
23-
you want the complete row, when piping to jq, or when
24-
round-tripping into other tools.
25-
26-
--format csv Spreadsheet-friendly columnar output. Useful for
27-
pandas, Excel, or quick correlations across rows.
28-
29-
Errors go to stderr. You do NOT need '2>&1'. Exit code is 0 on
30-
success and non-zero on auth or network failure. An empty result is
31-
success — markdown is empty, JSON is '[]', CSV has just the header.
16+
I/O
17+
stdout: data in --format markdown (default), json, or csv.
18+
stderr: errors. Exit 0 on success including empty results.
3219
3320
AUTH
34-
Withings auth is OAuth2. You need a Withings developer app — create
35-
one at https://developer.withings.com/. Withings requires an HTTPS
36-
callback URL; the recommended workaround is to register
37-
https://redirectmeto.com/http://localhost:8128/oauth/authorize and set
38-
WITHINGS_CALLBACK_URL to that exact value (the CLI binds locally and
39-
catches the redirect).
40-
41-
'withings-export auth login' opens a browser to authorize and writes
42-
~/.config/withings-export/auth.json (access/refresh tokens, user id,
43-
client id/secret). Subsequent calls auto-refresh ~5 min before expiry.
21+
withings-export auth login OAuth2 in browser; tokens stored locally.
22+
withings-export auth status Exit 0 if usable, 1 with reason. No network call.
23+
withings-export auth refresh|logout
4424
45-
'withings-export auth status' is a fast local check that exits 0 when a
46-
saved token is present and not yet expired, 1 with a clear "not logged
47-
in" or "token expired" message otherwise. No network call.
25+
Optional env: WITHINGS_CLIENT_ID, WITHINGS_CLIENT_SECRET, WITHINGS_CALLBACK_URL.
26+
HTTPS-callback workaround: register https://redirectmeto.com/http://localhost:8128/oauth/authorize
27+
(verbatim) and set WITHINGS_CALLBACK_URL to the same string.
4828
49-
'withings-export auth refresh' forces a refresh now.
50-
'withings-export auth logout' deletes the stored tokens.
51-
52-
Optional env vars (read by 'auth login' so the prompts can be skipped):
53-
WITHINGS_CLIENT_ID developer app client id
54-
WITHINGS_CLIENT_SECRET developer app client secret
55-
WITHINGS_CALLBACK_URL redirect URI registered with Withings
56-
57-
DATE FLAGS (every export subcommand accepts these)
58-
--since VALUE inclusive lower bound
59-
--until VALUE inclusive upper bound; defaults to now
29+
DATE FLAGS (every subcommand)
30+
--since VALUE / --until VALUE
6031
VALUE: today | yesterday | YYYY-MM-DD | Nd/Nw/Nm/Ny
61-
6232
See https://github.com/quantcli/common/blob/main/CONTRACT.md#3-date-flags
63-
for the cross-CLI specification.
64-
65-
SUBCOMMANDS
6633
67-
activity — daily activity rollups (steps, distance, calories,
68-
active-time bands, HR average/min/max, HR zones).
69-
Default window: 30d.
70-
JSON keys: date, timezone, steps, distance, elevation, soft, moderate,
71-
intense, active, calories, totalcalories, hr_average,
72-
hr_min, hr_max, hr_zone_0..3.
34+
SUBCOMMANDS (defaults in parens)
35+
activity (30d) daily steps/distance/calories/HR zones
36+
sleep (30d) stages, score, HR/RR; --derive polyfills missing nights
37+
workouts (90d) runs/walks/bikes/lifts with calories/HR/distance
38+
measurements (30d) weight/fat/BP/SpO2/temp; --types LIST filters
39+
intraday (1d) minute-level HR/HRV/SpO2/steps; dense — keep windows narrow
7340
74-
sleep — nightly sleep summaries (light/deep/REM minutes,
75-
latency, score, HR & RR ranges, snore/apnea). Default
76-
window: 30d.
77-
--derive for nights with no Withings summary, polyfill
78-
start/end from intraday HR samples. Adds a
79-
'source' column distinguishing summary vs
80-
derived rows.
81-
JSON keys: id, timezone, startdate, enddate, date, data{...}, source.
82-
83-
workouts — workouts (runs/walks/bikes/swims/lifts/etc) with
84-
calories, effective duration, distance, HR/zones,
85-
device id, category code. Default window: 90d.
86-
JSON keys: id, category, timezone, startdate, enddate, date,
87-
deviceid, data{...}.
88-
89-
measurements — body measurements: weight, body fat %, lean mass,
90-
BP, heart pulse, SpO2, body temp, hydration, bone mass,
91-
PWV, VO2 max. Default window: 30d.
92-
--types LIST comma-separated measure type codes (e.g.
93-
'1,6,76' = weight,fat_ratio,muscle_mass).
94-
JSON keys: date, type, type_code, value, device_id, grp_id.
95-
96-
intraday — minute-level samples (HR, HRV rmssd/sdnn1, SpO2, steps,
97-
distance) from Apple Watch via HealthKit or native
98-
Withings trackers. Default window: 1d.
99-
Withings caps requests at 24h windows; the CLI auto-
100-
chunks wider ranges.
41+
Inspect any subcommand's row schema with: <subcommand> --since 1d --format json
10142
10243
EXAMPLES
103-
104-
# Last week's sleep, scannable
10544
withings-export sleep --since 7d
106-
107-
# Workout HR distribution as JSON
108-
withings-export workouts --since 30d --format json | jq '
109-
.[] | { date: .date, category: .category, hr_avg: .data.hr_average }'
110-
111-
# Latest weight reading
45+
withings-export workouts --since 30d --format json |
46+
jq '.[] | {date, category, hr: .data.hr_average}'
11247
withings-export measurements --since 30d --types 1 --format json |
11348
jq 'sort_by(.date) | last'
11449
115-
# Resting HR across last 30 days (intraday is dense — narrow window)
116-
withings-export intraday --since 1d --format json |
117-
jq '[.[] | select(.heart_rate > 0) | .heart_rate] | min'
118-
119-
# Sleep efficiency derived from light+deep+rem vs in-bed time
120-
withings-export sleep --since 30d --format json | jq '.[] | {
121-
date,
122-
sleep_min: ((.data.lightsleepduration + .data.deepsleepduration +
123-
.data.remsleepduration) / 60),
124-
inbed_min: ((.enddate - .startdate) / 60)
125-
}'
126-
12750
GOTCHAS
128-
- Times are LOCAL. RFC3339 fields in CSV/markdown carry the user's
129-
offset; epoch seconds are timezone-agnostic in JSON.
130-
- 'intraday' is a firehose. A 7d query returns ~10K rows and takes
131-
minutes (auto-chunked into 24h slices, each rate-limited). Stick
132-
to 1-2d unless you need the full history.
133-
- Withings rate-limits aggressive callers (HTTP 601 "Too many
134-
requests"). 'sleep --derive' on a wide window throttles itself
135-
(250ms between calls); ad-hoc loops should do the same.
136-
- Sleep score and apnea fields are populated only on supported devices.
137-
'data.sleep_score' is null on unsupported wakeup-light models.
138-
- 'workouts' category is a Withings integer code in JSON (1=walk,
139-
2=run, 6=bicycling, 16=lift_weights, ...). Markdown and CSV map
140-
common codes to string names ('lift_weights', 'walk', ...) and
141-
unknown codes render as 'unknown'; CSV also keeps the raw integer
142-
in a 'category_code' column.
51+
- Times are LOCAL; JSON epoch seconds are zone-agnostic.
52+
- 'intraday' is a firehose — wide windows take minutes.
53+
- Withings rate-limits aggressive callers (HTTP 601). 'sleep --derive' throttles itself.
54+
- Sleep score / apnea fields appear only on supported devices.
55+
- 'workouts.category' is an integer code in JSON; markdown/CSV map common codes to names.
14356
`
14457

14558
var primeCmd = &cobra.Command{
14659
Use: "prime",
147-
Short: "Print an LLM-targeted primer (output formats, subcommands, jq recipes)",
60+
Short: "Print an LLM-targeted primer (one screen)",
14861
Long: `Print a one-screen primer aimed at LLM agents calling this CLI as a tool.
149-
Covers the output formats (markdown by default, --format json/csv for structured),
150-
auth subcommands and OAuth setup, the subcommands and what their rows look like,
151-
the shared date flags, and a few jq recipes for common questions.`,
62+
Covers I/O, auth, the shared date flags, the subcommand menu, and a few jq
63+
recipes. Per the quantcli contract, prime is short — anything that wants
64+
to grow into a man page belongs in --help on the relevant subcommand or
65+
in https://github.com/quantcli/common/blob/main/CONTRACT.md.`,
15266
RunE: func(cmd *cobra.Command, _ []string) error {
15367
_, err := fmt.Fprint(cmd.OutOrStdout(), primeText)
15468
return err

0 commit comments

Comments
 (0)