@wattsonclub/wattson-cli 0.0.0-stage → 0.1.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/CHANGELOG.md +19 -0
- package/README.md +158 -2
- package/dist/THIRD-PARTY-NOTICES.txt +23 -0
- package/dist/bin.js +8476 -0
- package/package.json +37 -4
- package/skill/SKILL.md +62 -0
- package/skill/references/commands.md +280 -0
- package/skill/references/workout-building-blocks.md +292 -0
- package/skill/references/workout-text-format.md +122 -0
package/package.json
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wattsonclub/wattson-cli",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.1.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"wattson": "./dist/bin.js",
|
|
8
|
+
"trainer-planner": "./dist/bin.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"build": "node build.mjs",
|
|
14
|
+
"prepack": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"description": "Wattson training planner CLI",
|
|
17
|
+
"license": "UNLICENSED",
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=22"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist/bin.js",
|
|
23
|
+
"dist/bin.js.LEGAL.txt",
|
|
24
|
+
"dist/THIRD-PARTY-NOTICES.txt",
|
|
25
|
+
"skill/SKILL.md",
|
|
26
|
+
"skill/references/commands.md",
|
|
27
|
+
"skill/references/workout-building-blocks.md",
|
|
28
|
+
"skill/references/workout-text-format.md",
|
|
29
|
+
"README.md",
|
|
30
|
+
"CHANGELOG.md"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"zod": "^3.25.76",
|
|
37
|
+
"esbuild": "^0.25.12"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wattson
|
|
3
|
+
description: Use the Wattson CLI to authenticate a local or remote agent, inspect athlete profiles and uploaded rides, and draft, validate and save structured cycling workouts. Use for terminal automation with Wattson, not remote control of an offline ride.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Wattson
|
|
7
|
+
|
|
8
|
+
## 1. Install and inspect
|
|
9
|
+
|
|
10
|
+
Requires Node.js 22 or newer. Install `npm install -g @wattsonclub/wattson-cli`, then run `wattson --help`. Use the commands advertised by the installed version; do not invent MCP-equivalent commands.
|
|
11
|
+
|
|
12
|
+
Human guide: [wattson.club/cli](https://wattson.club/cli). Agent discovery: [llms.txt](https://wattson.club/llms.txt). Full supported command families and copyable payload transformations: [commands](references/commands.md).
|
|
13
|
+
|
|
14
|
+
The default API is `https://api.wattson.club`. Override with `--base-url`, `WATTSON_API_BASE_URL` or legacy `PLANNER_API_BASE_URL` only for an explicitly chosen environment. Confirm `wattson health` succeeds before continuing.
|
|
15
|
+
|
|
16
|
+
## 2. Authenticate
|
|
17
|
+
|
|
18
|
+
Run `wattson auth status` (exit 1 means signed out, including with `--json`). If not signed in:
|
|
19
|
+
|
|
20
|
+
- On the user's own computer: `wattson auth login` opens browser OAuth with a localhost callback.
|
|
21
|
+
- On an SSH host, server, container, or agent runtime: `wattson auth login --remote` prints a verification URL and a short-lived user code and waits for approval. The user opens that URL on their own phone/laptop, signs in, checks the code and explicitly approves. No inbound port or SSH tunnel is needed.
|
|
22
|
+
|
|
23
|
+
Deliver login URLs and codes privately to the requesting user, never in a shared group. Never request their password, copy browser cookies, approve on their behalf, or expose access/refresh tokens. A timeout or denial means not authenticated; start a new login only at the user's request. For an unattended agent, complete the initial approval interactively; both flows request `planner:read planner:write`. Subsequent API requests automatically refresh and retry once on HTTP 401; a failed refresh-token request clears saved login. `--timeout <seconds>` overrides the five-minute login timeout.
|
|
24
|
+
|
|
25
|
+
Verify `wattson auth status` and `wattson --json athlete profile`. `wattson auth logout` attempts server logout, ignores server errors, then removes local credentials. It does not guarantee OAuth-token revocation or logout of other sessions. Tokens are unencrypted in a file with mode `0600` (new parent directory `0700`); JSON auth output omits tokens but includes identity metadata. See the reference for paths and overrides. Keep the credential directory persistent and private for containers; do not bake credentials into an image.
|
|
26
|
+
|
|
27
|
+
## 3. Inspect before changing
|
|
28
|
+
|
|
29
|
+
Use `--json` for machine consumption and check exit status. Login instructions are interactive information, not a successful login result.
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
wattson --json athlete profile
|
|
33
|
+
wattson --json athlete readiness latest
|
|
34
|
+
wattson --json athlete sessions --limit 10
|
|
35
|
+
wattson --json workout get WORKOUT_ID --version 1
|
|
36
|
+
wattson --json workout revisions WORKOUT_ID
|
|
37
|
+
wattson --json session summary SESSION_ID
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Omit athlete IDs to use the authenticated athlete. Do not infer permission to access someone else's athlete ID.
|
|
41
|
+
|
|
42
|
+
## 4. Draft, validate, save
|
|
43
|
+
|
|
44
|
+
Translate natural language into structured inputs. Read [workout building blocks](references/workout-building-blocks.md) for the complete field/primitive reference, exact composition examples, constraints and revision options, and [workout text format](references/workout-text-format.md) for readable previews.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
wattson --json workout draft --objective vo2max --duration-min 20 --execution-mode erg --style-hint "3 hard intervals"
|
|
48
|
+
wattson --json workout validate --input-file validate.json
|
|
49
|
+
wattson --json workout save --input-file save.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Draft output is not a save request: construct the appropriate payload described in [command examples](references/commands.md). A draft alone is not published. Inspect `validation.status`: validation can exit 0 even for `fail`. Fix failures and review warnings before saving; the reference example requires `pass`. FTP-relative values are fractions: `0.55` means 55%, not `55`.
|
|
53
|
+
|
|
54
|
+
Only save when the user's task authorizes adding or updating the workout in their library. After saving, verify the returned workout ID/version with `workout get`. Report “saved to your library, ready for the app to download,” not confirmed device delivery. Revisions require validation and save too.
|
|
55
|
+
|
|
56
|
+
## 5. Respect the offline ride model
|
|
57
|
+
|
|
58
|
+
The rider's app downloads saved workouts and runs the selected ride locally. A suspended/offline app syncs when it returns online. Uploaded rides can then be reviewed with `athlete sessions`, `session summary`, `session telemetry` and `session artifacts`. FIT export returns inline base64, not a downloaded file. Enqueue/retry `session strava-sync` only when the user authorizes Strava publication; acceptance is asynchronous, not delivery confirmation.
|
|
59
|
+
|
|
60
|
+
Use `workout list`, `workout schedule ID --date YYYY-MM-DD`, `workout unschedule ID`, and `workout retire ID` for library management. Strava routes and starred segments can be listed and imported as courses (see reference). The former Today-plan and session load/adapt/complete commands have been removed. Do not synthesize ride completion. The CLI also exposes MCP-equivalent sharing, course discovery, onboarding and research operations. Use the command reference to translate a tool call; preserve its input fields and inspect the same response. A server restriction (such as limited Strava access) applies regardless of interface.
|
|
61
|
+
|
|
62
|
+
Finish by verifying the affected read endpoint and summarizing the result. Distinguish a successful local command from device acknowledgement or Strava delivery.
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Wattson CLI command reference
|
|
2
|
+
|
|
3
|
+
Current offline workout/ride workflow. [Human guide](https://wattson.club/cli) · [Agent discovery](https://wattson.club/llms.txt).
|
|
4
|
+
|
|
5
|
+
## Install and authenticate
|
|
6
|
+
|
|
7
|
+
Requires Node.js 22+. Shell examples use Bash; JSON transformations require `jq`.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @wattsonclub/wattson-cli
|
|
11
|
+
wattson --help
|
|
12
|
+
wattson health
|
|
13
|
+
wattson auth login
|
|
14
|
+
# Alternatively, on SSH/server/container/agent runtime:
|
|
15
|
+
wattson auth login --remote
|
|
16
|
+
wattson --json auth status
|
|
17
|
+
wattson --json athlete profile
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Choose one login flow. Local login uses OAuth authorization code + PKCE and browser callback `http://127.0.0.1:8976/oauth/callback`. Remote login uses device authorization: verification URL and short-lived code appear on stderr; the CLI waits for approval on the user's phone/computer. No inbound port or SSH tunnel is required. Both request `planner:read planner:write`; there is no scope-selection flag. `--timeout SECONDS` overrides the five-minute wait (remote authorization may expire sooner). Denial/timeout is not authentication. Deliver URLs/codes privately to the requester; never approve on their behalf, request passwords, or copy cookies/tokens.
|
|
21
|
+
|
|
22
|
+
API requests refresh on HTTP 401 and retry once, persisting replacement credentials. A failed refresh-token request removes saved state and requires login again. `auth status` checks authenticated bootstrap; signed-out status exits 1, including JSON mode. JSON auth output excludes tokens but includes identity metadata.
|
|
23
|
+
|
|
24
|
+
Credentials are unencrypted JSON, written atomically with file mode `0600`; newly created parent directories use `0700`. Unix default: `$XDG_STATE_HOME/trainer-planner/auth.json` or `~/.local/state/trainer-planner/auth.json`. Windows: `%LOCALAPPDATA%/trainer-planner/auth.json`, falling back under the user's AppData/Local. `WATTSON_AUTH_FILE`, then legacy `PLANNER_CLI_AUTH_FILE`, override the path. Keep it private and persistent; do not print/commit credentials or bake them into images. Stored credentials are matched to the API base URL.
|
|
25
|
+
|
|
26
|
+
`wattson auth logout` attempts `/auth/logout` with saved refresh token and bearer credentials, then deletes the local file even if the server call fails. This is **not** a guarantee of OAuth-token revocation or logout of other sessions.
|
|
27
|
+
|
|
28
|
+
## Global behavior and supported families
|
|
29
|
+
|
|
30
|
+
Use `wattson [--base-url URL] [--json] COMMAND`. API precedence: `--base-url`, `WATTSON_API_BASE_URL`, legacy `PLANNER_API_BASE_URL`, default `https://api.wattson.club`. Override only for an intentionally selected environment. Omit optional athlete IDs for the signed-in athlete; explicit IDs are not permission to access others.
|
|
31
|
+
|
|
32
|
+
`--json` returns the API response, not a universal wrapper. Errors go to stderr; check exit codes. Successful transport for `workout validate` can exit 0 with `validation.status: "fail"`.
|
|
33
|
+
|
|
34
|
+
| Family | Supported commands |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| Auth | `auth login [--remote] [--timeout SECONDS]`, `auth status`, `auth logout` |
|
|
37
|
+
| Service | `health` |
|
|
38
|
+
| Athlete | `athlete profile [athleteId]`, `athlete readiness latest [athleteId] [--as-of ISO]`, `athlete sessions [athleteId] [--from DATE] [--to DATE] [--limit N]` |
|
|
39
|
+
| Recommendation | `recommend daily [athleteId] --available-time-min N [--date DATE] [--prefer-objective OBJECTIVE] [--hard-constraint TEXT ...]` |
|
|
40
|
+
| Authoring | `workout draft`, `workout revise`, `workout validate`, `workout save` (below) |
|
|
41
|
+
| Workout reads | `workout get ID [--version N]`, `workout revisions ID`, `workout runtime-plan ID --version N` |
|
|
42
|
+
| Ride reads/exports | `session summary ID`, `session telemetry ID`, `session artifacts ID`, `session fit ID` |
|
|
43
|
+
| External publication | `session strava-sync ID` (authorized, asynchronous) |
|
|
44
|
+
| Library/calendar | `workout list [athleteId] [--limit N]`, `workout schedule ID --date YYYY-MM-DD`, `workout unschedule ID`, `workout retire ID` |
|
|
45
|
+
| Courses/discovery/sharing/research | See the full MCP mapping below; structured operations accept `--input-file PATH` or `--input-json JSON`. |
|
|
46
|
+
|
|
47
|
+
The CLI covers the current MCP action and research tools. Strava account connection remains in the app, not in either tool surface. Strava availability depends on server access mode. Course imports return a course profile; they do not save or schedule a workout.
|
|
48
|
+
|
|
49
|
+
## Inspect, draft, validate, save, verify
|
|
50
|
+
|
|
51
|
+
Read profile/readiness before choosing targets. Recommendations are advice, not saved workouts.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
wattson --json athlete profile
|
|
55
|
+
wattson --json athlete readiness latest
|
|
56
|
+
wattson --json recommend daily --available-time-min 20 --prefer-objective vo2max
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Run in a private working directory, signed in, for a request authorizing library creation. This sequence stops on errors and requires validation `pass` before constructing the save request. Review the draft and validation issues before the save step.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
set -euo pipefail
|
|
63
|
+
umask 077
|
|
64
|
+
wattson --json workout draft --objective vo2max --duration-min 20 --execution-mode erg --style-hint "3 hard intervals" > draft.json
|
|
65
|
+
# Draft output: {workout, validationPreview?}. Validate input: {workout}.
|
|
66
|
+
jq -e '{workout: .workout} | select(.workout != null)' draft.json > validate.json
|
|
67
|
+
wattson --json workout validate --input-file validate.json > validation.json
|
|
68
|
+
jq -e '.validation.status == "pass"' validation.json >/dev/null
|
|
69
|
+
# Validation output has no workout. Preserve the original definition.
|
|
70
|
+
jq -e '{workout: .workout, expectedValidationStatus: "pass"}' validate.json > save.json
|
|
71
|
+
wattson --json workout save --input-file save.json > saved.json
|
|
72
|
+
workout_id=$(jq -er '.workoutId' saved.json)
|
|
73
|
+
workout_version=$(jq -er '.version' saved.json)
|
|
74
|
+
wattson --json workout get "$workout_id" --version "$workout_version"
|
|
75
|
+
wattson --json workout runtime-plan "$workout_id" --version "$workout_version"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For `warn`, review the issues and deliberately use the observed expected status only if acceptable; for `fail`, fix and revalidate. Never merely relabel a workout as validated. Save recomputes validation: `expectedValidationStatus` is a conflict guard. Passing saves persist as `validated` even if input status was `draft`. Save returns `{workoutId, version, status}`, not `{workout}`.
|
|
79
|
+
|
|
80
|
+
Draft flags also support repeatable `--execution-mode` and `--style-hint`, `--max-pct-ftp`, and `--readiness-snapshot-id`. Structured draft/revise/validate/save input uses **one** of `--input-file` or `--input-json`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
wattson --json workout draft --input-json '{"objective":"vo2max","durationMin":20,"constraints":{"allowedExecutionModes":["erg"],"maxPctFtp":1.2},"context":{"styleHints":["3 hard intervals"]}}'
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Signed-in structured drafts may omit `athleteId`. FTP values are fractions: `1.2` = 120%, `0.55` = 55%. See [building blocks](workout-building-blocks.md) and [workout text](workout-text-format.md). Preserve returned IDs, version, attribution, athlete context and blocks; don't invent a partial workout definition.
|
|
87
|
+
|
|
88
|
+
### Revise a saved version
|
|
89
|
+
|
|
90
|
+
Using `saved.json` above, only for an authorized edit (retain `set -euo pipefail`):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
jq '{patch: {workoutId: .workoutId, baseVersion: .version, preserve: ["objective", "interval_structure"], changes: {intensityMultiplier: 0.95}, reason: "Rider requested a slightly easier version."}}' saved.json > revise.json
|
|
94
|
+
wattson --json workout revise --input-file revise.json > revised.json
|
|
95
|
+
jq -e '{workout: .workout} | select(.workout != null)' revised.json > validate.json
|
|
96
|
+
wattson --json workout validate --input-file validate.json > validation.json
|
|
97
|
+
jq -e '.validation.status == "pass"' validation.json >/dev/null
|
|
98
|
+
jq --slurpfile prior saved.json '{workout: .workout, expectedValidationStatus: "pass", expectedLatestVersion: $prior[0].version}' validate.json > save.json
|
|
99
|
+
wattson --json workout save --input-file save.json > revised-saved.json
|
|
100
|
+
wattson --json workout get "$(jq -er '.workoutId' revised-saved.json)" --version "$(jq -er '.version' revised-saved.json)"
|
|
101
|
+
wattson --json workout revisions "$(jq -er '.workoutId' revised-saved.json)"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`revise` returns `{workout, diff}`; it does not save. `expectedLatestVersion` guards concurrent edits; on conflict, fetch latest and reconsider. Other patch changes: `newTitle`, `newObjective`, `durationDeltaSec`, `addCadenceFocus`, `removeLastInterval`, `switchToRecovery`. Translate natural language into structured intent.
|
|
105
|
+
|
|
106
|
+
## Offline app and uploaded rides
|
|
107
|
+
|
|
108
|
+
Report **saved to your library, ready for the app to download**. The app downloads workouts; the rider selects and executes them locally. A suspended/offline app syncs when online again. CLI success is not device acknowledgement, ride start or completion. Never fabricate a session to make a workflow look finished.
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
wattson --json athlete sessions --limit 10
|
|
112
|
+
# Replace SESSION_ID with a real uploaded session ID.
|
|
113
|
+
wattson --json session summary SESSION_ID
|
|
114
|
+
wattson --json session telemetry SESSION_ID
|
|
115
|
+
wattson --json session artifacts SESSION_ID
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Telemetry can be `{ "telemetry": null }` when not persisted. Artifacts returns metadata without inline FIT bytes. Treat ride/health data as private; retrieve/export within the user's request.
|
|
119
|
+
|
|
120
|
+
### FIT export
|
|
121
|
+
|
|
122
|
+
`session fit` returns `fitFile` with inline `contentBase64`, filename, MIME type, byte count and SHA-256. It does not write a FIT file. If export is requested:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
wattson --json session fit SESSION_ID > session-fit.json
|
|
126
|
+
node --input-type=module <<'NODE'
|
|
127
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
128
|
+
import { createHash } from 'node:crypto';
|
|
129
|
+
const { fitFile } = JSON.parse(readFileSync('session-fit.json', 'utf8'));
|
|
130
|
+
const bytes = Buffer.from(fitFile.contentBase64, 'base64');
|
|
131
|
+
if (bytes.length !== fitFile.sizeBytes || createHash('sha256').update(bytes).digest('hex') !== fitFile.checksumSha256.toLowerCase()) {
|
|
132
|
+
throw new Error('FIT size/checksum mismatch');
|
|
133
|
+
}
|
|
134
|
+
writeFileSync('ride.fit', bytes, { mode: 0o600, flag: 'wx' });
|
|
135
|
+
NODE
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Strava publication/retry — only when authorized
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
wattson --json session strava-sync SESSION_ID
|
|
142
|
+
wattson --json session summary SESSION_ID
|
|
143
|
+
wattson --json session artifacts SESSION_ID
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This enqueues/retries an asynchronous backend operation (HTTP 202). It requires the relevant Strava connection; the CLI has no account-connect command. Inspect `session.externalSync.strava` on later session summaries for status, activity URL or errors. Report pending until the backend confirms delivery; FIT export or HTTP 202 is not proof of Strava publication. Avoid tight polling.
|
|
147
|
+
|
|
148
|
+
## Library calendar and courses
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
wattson --json workout list --limit 20
|
|
152
|
+
wattson workout schedule WORKOUT_ID --date 2026-11-13
|
|
153
|
+
wattson workout unschedule WORKOUT_ID
|
|
154
|
+
wattson workout retire WORKOUT_ID
|
|
155
|
+
wattson strava routes --limit 20
|
|
156
|
+
wattson strava starred-segments --limit 20
|
|
157
|
+
wattson course import-strava-route --input-json '{"route":"123456"}'
|
|
158
|
+
wattson course import-strava-segment --input-json '{"segment":"629046"}'
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Scheduling sets the library workout's calendar date, not a legacy plan slot or remote start. Unscheduling clears that date; retirement removes the workout from the downloadable library. Verify with `workout get` and `workout list`. Course imports also accept `effortPctFtp` as a fraction.
|
|
162
|
+
|
|
163
|
+
## Removed commands
|
|
164
|
+
|
|
165
|
+
`plan current`, `plan schedule`, `runtime-plan today`, `session load-workout`, `session adapt`, and `session complete` are no longer CLI commands. Their backend compatibility routes are not the current app workflow. Use library scheduling and uploaded-ride reads instead; do not synthesize a ride completion.
|
|
166
|
+
|
|
167
|
+
Finish with an affected read endpoint; distinguish server persistence, app synchronization, recorded riding and external publication.
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
## MCP and CLI interchangeability
|
|
171
|
+
|
|
172
|
+
Use the same authenticated account and API environment for equivalent results. The CLI calls the same backend through the typed client; it does not require an MCP server process. Local/internal athlete-ID inputs do not grant access to other accounts. Server/provider access restrictions still apply.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
wattson --json tool list
|
|
176
|
+
wattson --json tool schema draft_workout
|
|
177
|
+
wattson --json tool schema validate_workout
|
|
178
|
+
wattson --json tool schema generate_terrain_course
|
|
179
|
+
# Same payload as the MCP tool, same result data:
|
|
180
|
+
wattson --json tool draft_workout --input-json '{"objective":"endurance","durationMin":30}'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`tool TOOL_NAME --input-json JSON` (or `--input-file PATH`) accepts the corresponding MCP input envelope. `tool schema TOOL_NAME` describes fields, types, defaults and constraints; invocation also enforces contract refinements. Inspect the installed version rather than guessing a flag. The normal CLI commands remain available for humans.
|
|
184
|
+
|
|
185
|
+
| MCP tool | CLI command |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| `list_saved_workouts` | `workout list` |
|
|
188
|
+
| `health` | `health` |
|
|
189
|
+
| `get_athlete_profile` | `athlete profile` |
|
|
190
|
+
| `get_readiness_snapshot` | `athlete readiness latest` |
|
|
191
|
+
| `get_recent_sessions` | `athlete sessions` |
|
|
192
|
+
| `get_saved_workout` | `workout get` |
|
|
193
|
+
| `get_workout_runtime_plan` | `workout runtime-plan` |
|
|
194
|
+
| `list_saved_workout_revisions` | `workout revisions` |
|
|
195
|
+
| `summarize_session` | `session summary` |
|
|
196
|
+
| `get_session_telemetry` | `session telemetry` |
|
|
197
|
+
| `get_session_artifacts` | `session artifacts` |
|
|
198
|
+
| `get_session_fit_export` | `session fit` |
|
|
199
|
+
| `lookup_climb` | `course lookup` |
|
|
200
|
+
| `find_my_strava_segments` | `strava find-segments` |
|
|
201
|
+
| `import_strava_segment` | `course import-strava-segment` |
|
|
202
|
+
| `import_gpx_course` | `course import-gpx` |
|
|
203
|
+
| `generate_terrain_course` | `course generate-terrain` |
|
|
204
|
+
| `import_strava_activity_course` | `course import-strava-activity` |
|
|
205
|
+
| `build_road_course` | `course build-road` |
|
|
206
|
+
| `import_climb_page` | `course import-climb-page` |
|
|
207
|
+
| `get_my_climb_history` | `course history` |
|
|
208
|
+
| `explore_strava_segments` | `strava explore` |
|
|
209
|
+
| `get_my_strava_segment_efforts` | `strava segment-efforts` |
|
|
210
|
+
| `list_my_strava_starred_segments` | `strava starred-segments` |
|
|
211
|
+
| `list_my_favourite_strava_climbs` | `strava favourite-climbs` |
|
|
212
|
+
| `recommend_first_workout` | `recommend first` |
|
|
213
|
+
| `list_my_strava_routes` | `strava routes` |
|
|
214
|
+
| `import_strava_route` | `course import-strava-route` |
|
|
215
|
+
| `draft_workout` | `workout draft` |
|
|
216
|
+
| `revise_workout` | `workout revise` |
|
|
217
|
+
| `validate_workout` | `workout validate` |
|
|
218
|
+
| `save_workout` | `workout save` |
|
|
219
|
+
| `schedule_saved_workout` | `workout schedule` |
|
|
220
|
+
| `retire_saved_workout` | `workout retire` |
|
|
221
|
+
| `trigger_session_strava_sync` | `session strava-sync` |
|
|
222
|
+
| `create_workout_share` | `share create` |
|
|
223
|
+
| `preview_workout_share` | `share preview` |
|
|
224
|
+
| `import_workout_share` | `share import` |
|
|
225
|
+
| `search` | `research search` |
|
|
226
|
+
| `fetch` | `research fetch` |
|
|
227
|
+
|
|
228
|
+
For new course/discovery/sharing/recommendation commands, schema field names map to kebab-case flags (`effortPctFtp` → `--effort-pct-ftp`). Nested fields use dots (`--answers.ideal-minutes 30`); objects/arrays can be JSON. Booleans take explicit `true`/`false`. Do not combine `--input-json`/`--input-file` with field flags. Existing convenience commands keep their documented flags (for example, `workout get --version`); use generic `tool` invocation for a literal MCP payload.
|
|
229
|
+
|
|
230
|
+
### Sharing: create, preview, import
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
wattson --json share create --input-json '{"workoutId":"WORKOUT_ID","workoutVersion":1}' > share.json
|
|
234
|
+
share_id=$(jq -er '.shareId' share.json)
|
|
235
|
+
wattson --json share preview "$share_id" > preview.json
|
|
236
|
+
# Only when the user wants to add the shared workout to their own library:
|
|
237
|
+
wattson --json share import "$share_id" > imported.json
|
|
238
|
+
wattson --json workout list
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Creation returns `{shareId,url}` for an owned, saved revision. Share IDs are UUIDs, not arbitrary URLs. Sharing exposes a sanitized template (title, objective, blocks, constraints), not the owner's profile, rationale, schedule or ride history. Block instructions are shared: don't put private notes there if sharing the workout. Anyone with the link can access the public preview. Authenticated preview returns `{item}` with recipient-adjusted artifacts and does **not** save. Import returns `{item,alreadyImported}`; repeated imports may reuse an existing copy. It does not start or schedule a ride.
|
|
242
|
+
|
|
243
|
+
### All course sources and discovery
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
wattson --json course lookup "Ventoux" --limit 3
|
|
247
|
+
wattson --json course generate-terrain --input-json '{"distanceM":5000,"averageGradePct":5,"shape":"hairpins","seed":7}'
|
|
248
|
+
wattson --json course import-gpx --gpx-file route.gpx --name "My climb"
|
|
249
|
+
wattson --json course build-road --input-json '{"start":{"place":"Bédoin, France"},"end":{"place":"Mont Ventoux, France"}}'
|
|
250
|
+
wattson --json course import-climb-page --input-json '{"url":"https://climbfinder.com/en/climbs/mont-ventoux-bedoin"}'
|
|
251
|
+
wattson --json course history --limit 20
|
|
252
|
+
wattson --json strava find-segments "Collserola" --limit 5
|
|
253
|
+
wattson --json strava explore --input-json '{"place":"Girona","radiusKm":10}'
|
|
254
|
+
wattson --json strava segment-efforts "629046" --limit 10
|
|
255
|
+
wattson --json strava favourite-climbs --limit 3 --recent-rides 6
|
|
256
|
+
wattson --json course import-strava-activity --input-json '{"activity":"123456","startDistanceM":1000,"endDistanceM":6000}'
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Replace example Strava IDs with real accessible items. Course sources return profiles; compose a `climb` block from the returned `course`, allow grade execution, then validate/save the workout. Lookup returns a `climbs` array instead of one top-level `course`. GPX takes exactly one of text or a public GPX URL; `--gpx-file` reads local text. Strava activity imports are limited to the rider's own rides. Use `tool schema` for every optional field, bound and default; the [authoring reference](workout-building-blocks.md) explains course embedding, pacing estimates and runtime completion.
|
|
260
|
+
|
|
261
|
+
Limited Strava mode still permits segment import, name matching against starred segments, and ride upload/retry; it restricts other Strava reads. Changing interfaces does not bypass that policy. Lookup, GPX, terrain, road and supported climb pages are alternatives without those Strava reads.
|
|
262
|
+
|
|
263
|
+
### First-workout recommendations
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
wattson --json recommend first --input-json '{"answers":{"idealMinutes":30,"maxMinutes":45,"goal":"fitness","freshness":"normal"},"useStrava":false}' > first.json
|
|
267
|
+
jq '{workout:.draft.workout}' first.json > validate.json
|
|
268
|
+
wattson --json workout validate --input-file validate.json
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
This returns a draft and rationale, not a saved workout. Its definition is at `.draft.workout`, unlike `workout draft`'s `.workout`. Continue the same reviewed validate/save flow above. Use `tool schema recommend_first_workout` for questionnaire choices and all optional answers. Unknown FTP stays omitted; never invent one. `recommend daily` is a separate legacy advisory helper, not this onboarding operation or a saved plan.
|
|
272
|
+
|
|
273
|
+
### Research search and fetch
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
wattson --json research search "threshold"
|
|
277
|
+
wattson --json research fetch "DOCUMENT_ID_FROM_SEARCH"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
These use the same profile/saved-workout/uploaded-ride corpus, ranking and document handles as MCP research. They are not web search. Fetch a returned handle rather than constructing IDs. The output may contain the signed-in athlete's private training data.
|