@vitness/fds-skill 0.1.0

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.
@@ -0,0 +1,409 @@
1
+ # FDS AI Enrichment Guide
2
+
3
+ ## Overview
4
+
5
+ AI enrichment fills gaps when source data lacks fields required by FDS. This guide covers when, how, and what to enrich.
6
+
7
+ ---
8
+
9
+ ## Enrichment Decision Matrix
10
+
11
+ | Source Has | FDS Requires | Action |
12
+ |------------|--------------|--------|
13
+ | `name` | `canonical.name` | Direct map (titleCase) |
14
+ | `name` | `canonical.slug` | Transform (slugify) |
15
+ | - | `canonical.description` | **AI Enrich** |
16
+ | - | `canonical.aliases` | **AI Enrich** |
17
+ | `bodyPart` + `target` | `classification.*` | **AI Enrich** (5 fields) |
18
+ | `target` | `targets.primary` | Registry lookup + AI fallback |
19
+ | `equipment` | `equipment.required` | Registry lookup + AI fallback |
20
+ | - | `metrics.primary` | **AI Enrich** |
21
+ | `gifUrl` | `media` | Transform (toMediaArray) |
22
+ | - | `metadata.*` | Auto-generate |
23
+
24
+ ---
25
+
26
+ ## Field-Specific Enrichment
27
+
28
+ ### 1. canonical.description
29
+
30
+ **When to enrich:** Always when missing
31
+
32
+ **Context needed:**
33
+ - `name` (required)
34
+ - `bodyPart` or `target` (helpful)
35
+ - `equipment` (helpful)
36
+ - `classification` if already determined (helpful)
37
+
38
+ **Output format:**
39
+ ```json
40
+ {
41
+ "description": "1-3 sentence description of the exercise"
42
+ }
43
+ ```
44
+
45
+ **Quality criteria:**
46
+ - 50-150 words
47
+ - Mentions target muscles
48
+ - Explains movement or purpose
49
+ - Suitable for general audience
50
+ - No form instructions (those go in separate field)
51
+
52
+ ### 2. canonical.aliases
53
+
54
+ **When to enrich:** When missing and name has common variations
55
+
56
+ **Context needed:**
57
+ - `name` (required)
58
+
59
+ **Output format:**
60
+ ```json
61
+ {
62
+ "aliases": ["variation 1", "variation 2"]
63
+ }
64
+ ```
65
+
66
+ **Guidelines:**
67
+ - Include common abbreviations (DB, BB, KB)
68
+ - Include regional variations (push-up vs press-up)
69
+ - Include equipment-less name if applicable
70
+ - Max 5 aliases
71
+ - Don't include the main name
72
+
73
+ ### 3. classification (All 5 Required Fields)
74
+
75
+ **When to enrich:** Always when any field missing
76
+
77
+ **Context needed:**
78
+ - `name` (required)
79
+ - `bodyPart` (very helpful)
80
+ - `target` muscle (very helpful)
81
+ - `equipment` (helpful)
82
+
83
+ **Output format:**
84
+ ```json
85
+ {
86
+ "exerciseType": "strength",
87
+ "movement": "push-horizontal",
88
+ "mechanics": "compound",
89
+ "force": "push",
90
+ "level": "intermediate"
91
+ }
92
+ ```
93
+
94
+ **Decision logic:**
95
+
96
+ #### exerciseType
97
+ ```
98
+ Is it primarily for building strength/muscle? → "strength"
99
+ Is it for cardiovascular endurance? → "cardio"
100
+ Is it for flexibility/range of motion? → "mobility"
101
+ Is it explosive/jumping? → "plyometric"
102
+ Is it for stability/proprioception? → "balance"
103
+ ```
104
+
105
+ #### movement (See SKILL.md for full decision tree)
106
+ Key patterns:
107
+ - Squats, leg press → `squat`
108
+ - Deadlifts, hip hinges → `hinge`
109
+ - Lunges, split squats → `lunge`
110
+ - Bench press, push-ups → `push-horizontal`
111
+ - Overhead press → `push-vertical`
112
+ - Rows → `pull-horizontal`
113
+ - Pull-ups, pulldowns → `pull-vertical`
114
+ - Farmer walks → `carry`
115
+ - Planks, dead bugs → `core-anti-extension`
116
+ - Pallof press → `core-anti-rotation`
117
+ - Russian twists → `rotation`
118
+ - Running, cycling → `locomotion`
119
+ - Curls, extensions → `isolation`
120
+
121
+ #### mechanics
122
+ ```
123
+ Multiple joints moving? → "compound"
124
+ Single joint moving? → "isolation"
125
+ ```
126
+
127
+ #### force
128
+ ```
129
+ Pushing away from body? → "push"
130
+ Pulling toward body? → "pull"
131
+ Holding position? → "static"
132
+ Both/alternating? → "mixed"
133
+ ```
134
+
135
+ #### level
136
+ ```
137
+ Simple technique, low strength needed? → "beginner"
138
+ Moderate technique or strength? → "intermediate"
139
+ Complex technique or high strength? → "advanced"
140
+ ```
141
+
142
+ ### 4. metrics.primary (and secondary)
143
+
144
+ **When to enrich:** Always when missing
145
+
146
+ **Context needed:**
147
+ - `name` (required)
148
+ - `classification.exerciseType` (very helpful)
149
+ - `classification.movement` (helpful)
150
+
151
+ **Output format:**
152
+ ```json
153
+ {
154
+ "primary": { "type": "reps", "unit": "count" },
155
+ "secondary": [
156
+ { "type": "weight", "unit": "kg" }
157
+ ]
158
+ }
159
+ ```
160
+
161
+ **Decision logic:**
162
+ ```
163
+ Strength exercise (rep-based)?
164
+ → primary: reps/count
165
+ → secondary: weight/kg (if weighted)
166
+
167
+ Timed hold (plank, wall sit)?
168
+ → primary: duration/s
169
+
170
+ Distance cardio (run, row)?
171
+ → primary: distance/km
172
+ → secondary: duration/min, pace/min_per_km
173
+
174
+ Time-based cardio (bike, elliptical)?
175
+ → primary: duration/min
176
+ → secondary: heartRate/bpm, calories/kcal
177
+
178
+ Plyometric?
179
+ → primary: reps/count
180
+ → secondary: height/cm (if jumping)
181
+ ```
182
+
183
+ ### 5. targets.primary (Registry Lookup Fallback)
184
+
185
+ **When to enrich:** When registry lookup fails
186
+
187
+ **Context needed:**
188
+ - `name` (required)
189
+ - `bodyPart` (helpful)
190
+ - Source `target` value (required - this is what failed lookup)
191
+
192
+ **Task:** Map the source muscle name to the closest FDS muscle
193
+
194
+ **Output format:**
195
+ ```json
196
+ {
197
+ "muscleId": "c3d4e5f6-3333-4000-8000-000000000022",
198
+ "muscleName": "Rectus Abdominis",
199
+ "muscleSlug": "rectus-abdominis",
200
+ "categoryId": "a1b2c3d4-1111-4000-8000-000000000004"
201
+ }
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Enrichment Prompts
207
+
208
+ ### System Prompt (All Enrichments)
209
+
210
+ ```
211
+ You are an expert exercise physiologist and fitness data specialist with comprehensive knowledge of:
212
+ - Exercise biomechanics and movement patterns
213
+ - Muscle anatomy and function
214
+ - Exercise classification systems
215
+ - The FDS (Fitness Data Standard) specification
216
+
217
+ Your responses must be:
218
+ 1. Accurate and evidence-based
219
+ 2. Consistent with FDS schema requirements
220
+ 3. Formatted as valid JSON
221
+ 4. Concise but complete
222
+ ```
223
+
224
+ ### Classification Prompt
225
+
226
+ ```
227
+ Classify this exercise according to FDS v1.0.0:
228
+
229
+ Exercise: {{name}}
230
+ Body Part: {{bodyPart}}
231
+ Target Muscle: {{target}}
232
+ Equipment: {{equipment}}
233
+
234
+ Required fields (use EXACT enum values):
235
+ - exerciseType: strength | cardio | mobility | plyometric | balance
236
+ - movement: squat | hinge | lunge | push-horizontal | push-vertical | pull-horizontal | pull-vertical | carry | core-anti-extension | core-anti-rotation | rotation | locomotion | isolation | other
237
+ - mechanics: compound | isolation
238
+ - force: push | pull | static | mixed
239
+ - level: beginner | intermediate | advanced
240
+
241
+ Respond with JSON only:
242
+ {
243
+ "exerciseType": "...",
244
+ "movement": "...",
245
+ "mechanics": "...",
246
+ "force": "...",
247
+ "level": "..."
248
+ }
249
+ ```
250
+
251
+ ### Description Prompt
252
+
253
+ ```
254
+ Write a concise description for this exercise:
255
+
256
+ Exercise: {{name}}
257
+ Target: {{target}}
258
+ Equipment: {{equipment}}
259
+ Type: {{exerciseType}}
260
+ Movement: {{movement}}
261
+
262
+ Requirements:
263
+ - 1-3 sentences (50-150 words)
264
+ - Mention primary muscles targeted
265
+ - Explain purpose/benefit
266
+ - No form instructions
267
+ - Suitable for general fitness audience
268
+
269
+ Respond with JSON only:
270
+ {
271
+ "description": "..."
272
+ }
273
+ ```
274
+
275
+ ### Metrics Prompt
276
+
277
+ ```
278
+ Determine appropriate tracking metrics for this exercise:
279
+
280
+ Exercise: {{name}}
281
+ Type: {{exerciseType}}
282
+ Movement: {{movement}}
283
+
284
+ Valid metric types: reps, weight, duration, distance, speed, pace, power, heartRate, steps, calories, height, tempo, rpe
285
+
286
+ Valid units:
287
+ - count (reps, tempo, rpe)
288
+ - kg, lb (weight)
289
+ - s, min (duration)
290
+ - m, km, mi (distance)
291
+ - m_s, km_h (speed)
292
+ - min_per_km, min_per_mi (pace)
293
+ - W (power)
294
+ - bpm (heartRate)
295
+ - kcal (calories)
296
+ - cm, in (height)
297
+
298
+ Respond with JSON only:
299
+ {
300
+ "primary": { "type": "...", "unit": "..." },
301
+ "secondary": [{ "type": "...", "unit": "..." }]
302
+ }
303
+ ```
304
+
305
+ ---
306
+
307
+ ## Enrichment Configuration
308
+
309
+ ### Full Enrichment (Default)
310
+
311
+ ```json
312
+ {
313
+ "enrichment": {
314
+ "enabled": true,
315
+ "defaultFields": "all"
316
+ }
317
+ }
318
+ ```
319
+
320
+ ### Selective Enrichment
321
+
322
+ ```json
323
+ {
324
+ "enrichment": {
325
+ "enabled": true,
326
+ "defaultFields": ["classification", "metrics"],
327
+ "skipFields": ["canonical.description"]
328
+ }
329
+ }
330
+ ```
331
+
332
+ ### Field-Level Override
333
+
334
+ ```json
335
+ {
336
+ "mappings": {
337
+ "canonical.description": {
338
+ "enrichment": {
339
+ "enabled": false
340
+ }
341
+ },
342
+ "classification": {
343
+ "enrichment": {
344
+ "enabled": true,
345
+ "when": "always"
346
+ }
347
+ }
348
+ }
349
+ }
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Rate Limiting & Batching
355
+
356
+ ### Recommended Settings
357
+
358
+ ```json
359
+ {
360
+ "enrichment": {
361
+ "options": {
362
+ "temperature": 0.3,
363
+ "maxRetries": 3,
364
+ "rateLimit": {
365
+ "requestsPerMinute": 60
366
+ }
367
+ },
368
+ "batch": {
369
+ "enabled": true,
370
+ "concurrency": 5,
371
+ "chunkSize": 10
372
+ }
373
+ }
374
+ }
375
+ ```
376
+
377
+ ### Cost Optimization
378
+
379
+ 1. **Batch similar fields together** - One AI call for classification (5 fields) vs 5 separate calls
380
+ 2. **Use registry lookups first** - Only fall back to AI when lookup fails
381
+ 3. **Cache enrichment results** - Same exercise name → same classification
382
+ 4. **Use appropriate model** - Claude 3.5 Sonnet for quality, Claude 3 Haiku for speed/cost
383
+
384
+ ---
385
+
386
+ ## Validation
387
+
388
+ All AI-generated content should be validated against FDS schema:
389
+
390
+ ```typescript
391
+ const result = await enrichmentEngine.enrich(data, mappings, context);
392
+
393
+ // Validate each enriched field
394
+ for (const [field, value] of Object.entries(result.data)) {
395
+ const isValid = validator.validateField(field, value);
396
+ if (!isValid) {
397
+ console.warn(`AI generated invalid value for ${field}, using fallback`);
398
+ }
399
+ }
400
+ ```
401
+
402
+ ### Common Validation Issues
403
+
404
+ | Field | Issue | Solution |
405
+ |-------|-------|----------|
406
+ | `movement` | Invalid enum value | Re-prompt with explicit enum list |
407
+ | `level` | Mixed case | Normalize to lowercase |
408
+ | `metrics.unit` | Wrong pairing | Validate type+unit combinations |
409
+ | `description` | Too long | Truncate or re-prompt |