@isparling/engram-coach 0.1.0 → 0.2.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.
Files changed (51) hide show
  1. package/README.md +85 -18
  2. package/SETUP.md +559 -0
  3. package/SKILL_PACK.md +75 -0
  4. package/analyses/catalog.md +257 -0
  5. package/analysis-tools/hrv-trend.ts +592 -0
  6. package/analysis-tools/migrate-structured-capture.ts +234 -0
  7. package/analysis-tools/race-context.ts +96 -0
  8. package/analysis-tools/stream-analyze.ts +1008 -0
  9. package/analysis-tools/tsb-predict.ts +117 -0
  10. package/capture-handler.ts +301 -0
  11. package/config.json.example +21 -0
  12. package/engram-coach-ambient-capture.ts +336 -0
  13. package/engram-coach-capture-types.ts +185 -0
  14. package/engram-coach-config.ts +268 -0
  15. package/engram-coach-domain.ts +7 -2
  16. package/engram-coach-keys.ts +189 -0
  17. package/engram-coach-materialization.ts +638 -0
  18. package/engram-coach-migration.ts +1078 -0
  19. package/engram-coach-pack.ts +17 -12
  20. package/engram-coach-presentation.ts +10 -1
  21. package/engram-coach-reconciliation.ts +305 -2
  22. package/engram-coach-structured-capture.ts +622 -0
  23. package/package.json +39 -6
  24. package/personas/aggressive-monitoring.md +121 -0
  25. package/personas/aggressive.json +85 -0
  26. package/personas/conservative-monitoring.md +133 -0
  27. package/personas/conservative.json +93 -0
  28. package/personas/polarized-monitoring.md +112 -0
  29. package/personas/polarized.json +72 -0
  30. package/personas/volume-monitoring.md +85 -0
  31. package/personas/volume.json +108 -0
  32. package/shared/retrieval.md +71 -0
  33. package/shared/setup.md +207 -0
  34. package/skills/.gitkeep +0 -0
  35. package/skills/adapt-plan/SKILL.md +263 -0
  36. package/skills/block-review/SKILL.md +275 -0
  37. package/skills/consult/SKILL.md +176 -0
  38. package/skills/intake/SKILL.md +315 -0
  39. package/skills/lactate-analyze/SKILL.md +230 -0
  40. package/skills/lessons-rollup/SKILL.md +196 -0
  41. package/skills/monitoring-rollup/SKILL.md +208 -0
  42. package/skills/race-analysis/SKILL.md +219 -0
  43. package/skills/season-retrospective/SKILL.md +200 -0
  44. package/skills/set-goal/SKILL.md +297 -0
  45. package/templates/base.md +55 -0
  46. package/templates/build-1.md +57 -0
  47. package/templates/build-2.md +62 -0
  48. package/templates/race-report.md +51 -0
  49. package/templates/race-specificity.md +62 -0
  50. package/templates/season-review.md +40 -0
  51. package/engram-coach-extractor.ts +0 -295
@@ -0,0 +1,263 @@
1
+ ---
2
+ name: adapt-plan
3
+ description: Use when a key workout has been completed and you need to analyze it against the prescription, gather subjective experience, and adapt the next planned workout. Requires Intervals.icu MCP tools and config.json with coaching_docs_dir and prescriptions_dir configured.
4
+ ---
5
+
6
+ # Adapt Plan
7
+
8
+ ## Overview
9
+
10
+ Rigid five-phase workflow for post-workout analysis and prescription adaptation. Integrates objective execution data with subjective athlete experience and training block context to make evidence-based adjustments to the next workout prescription. All reasoning is recorded as persistent knowledge in the coaching docs directory.
11
+
12
+ **This skill is RIGID — phases execute in exact order. Do not skip, reorder, or combine phases.**
13
+
14
+ ## Workflow
15
+
16
+ ```dot
17
+ digraph adapt_plan {
18
+ "Phase 1: Orient" [shape=box];
19
+ "Phase 2: Gather" [shape=box];
20
+ "Phase 3: Synthesize" [shape=box];
21
+ "Phase 4: Propose" [shape=box];
22
+ "Athlete approves?" [shape=diamond];
23
+ "Phase 5: Apply" [shape=box];
24
+
25
+ "Phase 1: Orient" -> "Phase 2: Gather";
26
+ "Phase 2: Gather" -> "Phase 3: Synthesize";
27
+ "Phase 3: Synthesize" -> "Phase 4: Propose";
28
+ "Phase 4: Propose" -> "Athlete approves?";
29
+ "Athlete approves?" -> "Phase 5: Apply" [label="yes"];
30
+ "Athlete approves?" -> "Phase 4: Propose" [label="revise"];
31
+ }
32
+ ```
33
+
34
+ ---
35
+
36
+ ### Pre-Phase Setup _(no user input — run silently)_
37
+
38
+ Follow **`${CLAUDE_PLUGIN_ROOT}/shared/setup.md`** — the shared configuration
39
+ preamble (paths, config, profile, persona, athlete profile).
40
+
41
+ **Optional steps this skill declares:** PRESCRIPTIONS, SEASON, MCP, MONITORING
42
+
43
+ Do not proceed past a stop condition defined there.
44
+
45
+
46
+ ### Phase 1 — Orient _(no user input)_
47
+
48
+ Read and search silently before asking anything:
49
+
50
+ 1. **Active prescription/plan** — List all YAML files in `prescriptions_dir`. For each file, find the maximum session_date. The active block is the file whose most recent session_date is on or before today. If ambiguous (multiple files with recent sessions), ask: "I found multiple prescription files with recent sessions: [list]. Which block are you currently in?" Read the full prescription file for the active block and the surrounding block context (week number, phase, upcoming sessions).
51
+
52
+ 2. **Execution data** — retrieve completed workout from Intervals.icu MCP tools. Note the prescription vs. actual delta: power targets met/missed, duration completed, interval count, HR behavior, any visible fade or drift. Retrieve HRV and wellness data via Intervals.icu MCP tools (get_wellness). If this call fails or returns no data, continue Phase 1 without HRV context and annotate in the Orient summary: "[HRV data unavailable — MCP wellness tool returned no data. Orient proceeds without HRV context.]"
53
+
54
+ 2b. **Stream analysis** — read the active persona's `analyses` config from the loaded persona JSON. If the persona has no `analyses` field, skip this step entirely and proceed to step 3.
55
+
56
+ For each analysis entry where `enabled` is `true` (or `enabled` is absent, since default is `true`):
57
+ - Check if the current training phase (determined in step 1) matches the analysis's `phases` array. If `phases` is `null` or absent, the analysis runs in all phases. If the current phase is not in the `phases` array, skip this analysis.
58
+ - Consult `${CLAUDE_PLUGIN_ROOT}/analyses/catalog.md` for the analysis's data source and prerequisites.
59
+ - Check data prerequisites against the completed workout from step 2: does the activity have the required data (power, HR, pace)? Does it meet minimum duration requirements? Is it the right session type (e.g., steady-state for decoupling, intervals for execution quality)?
60
+ - Route the analysis to the correct data source using the table below.
61
+ - Classify the result against the persona's configured thresholds for this analysis.
62
+ - Store the result (metric value, classification, any notable details) for use in Phase 3 — Synthesize.
63
+
64
+ **Analysis routing table:**
65
+
66
+ | Analysis Key | Stream-dependent? | Data Source |
67
+ |---|---|---|
68
+ | `aerobic_decoupling` | Yes | `stream-analyze --analyses decoupling` |
69
+ | `hr_recovery_curve` | Yes | `stream-analyze --analyses hr_recovery` |
70
+ | `interval_execution_quality` | Partial | Fade/compliance: `get_activity_intervals` MCP; CV: `stream-analyze --analyses interval_cv` |
71
+ | `time_in_zones` | No | `get_power_histogram` + `get_hr_histogram` MCP |
72
+ | `power_curve_trend` | No | `get_power_curves` MCP |
73
+ | `hr_at_power_trend` | No | MCP tools (compact endpoints) |
74
+ | `resting_hr_trend` | No | `get_wellness` MCP |
75
+ | `hrv_trend` | No | `npx tsx ${CLAUDE_PLUGIN_ROOT}/analysis-analysis-tools/hrv-trend.ts --config {config_path} --date {target_date}` |
76
+
77
+ **`hrv_trend` — dedicated CLI tool:** When `hrv_trend` is enabled in the persona:
78
+ 1. Run: `npx tsx ${CLAUDE_PLUGIN_ROOT}/analysis-analysis-tools/hrv-trend.ts --config {config_path} --date {today_YYYY-MM-DD}`. Pass persona-configured windows if present: `--short-window {short_window_days} --long-window {long_window_days} --metric {metric}`.
79
+ 2. Parse the JSON output. If `classification.label` is `amber-red` or `red`, surface it prominently in the Orient announcement with the full `reasoning` string.
80
+ 3. Store the complete output object as `hrv_trend_result` for use in Phase 3 — Synthesize and Phase 4 — Propose.
81
+ 4. If the tool exits non-zero or the output is malformed, annotate: "[hrv_trend unavailable — {error}. Proceeding without.]" and continue.
82
+
83
+ **Stream-dependent analyses** — batch all applicable stream-dependent analysis keys into a single CLI call rather than calling separately per analysis:
84
+
85
+ 1. Read `intervals_icu` config from `{config_path}`. If the `intervals_icu` block is missing or incomplete, skip all stream-dependent analyses and annotate: "[Stream analyses unavailable — intervals_icu config not found in config.json. See SETUP.md.]"
86
+ 2. Run the CLI tool:
87
+ ```bash
88
+ npx tsx ${CLAUDE_PLUGIN_ROOT}/analysis-analysis-tools/stream-analyze.ts \
89
+ --activity-id {activity_id} \
90
+ --analyses {comma_separated_keys} \
91
+ --config {config_path}
92
+ ```
93
+ Where `{comma_separated_keys}` is the union of all stream-dependent analyses enabled for this session (e.g., `decoupling,hr_recovery,interval_cv`).
94
+ 3. Parse the JSON output. For each analysis in the result, classify against persona thresholds. If an analysis appears in the `errors` field, skip it and annotate: "[{analysis_key} unavailable — {error_message}. Proceeding without.]"
95
+
96
+ **MCP-native analyses** — call the specified MCP tool(s) directly. These endpoints return compact structured data that enters the conversation context efficiently.
97
+
98
+ If the activity lacks required data for an analysis (e.g., no power meter, session too short, no identifiable intervals), skip that analysis silently — it is not applicable to this session type.
99
+
100
+ After processing all applicable analyses, include a brief summary in the Orient announcement: which analyses ran, which were skipped and why, and any results that immediately stand out (e.g., a red-classified result).
101
+
102
+ 2c. **TSB projection** — after retrieving the completed workout's TSS (from step 2), call the TSB prediction tool:
103
+
104
+ ```bash
105
+ npx tsx ${CLAUDE_PLUGIN_ROOT}/analysis-analysis-tools/tsb-predict.ts --ctl {current_ctl} --atl {current_atl} --tss {tss_sequence}
106
+ ```
107
+
108
+ Where `{tss_sequence}` is a comma-separated list of estimated daily TSS values for the upcoming days, derived from:
109
+ - Today's completed session TSS (from step 2, actual value)
110
+ - Upcoming prescribed sessions: estimate TSS from the prescription's power targets and duration. Use the athlete's historical TSS for similar session types as calibration when available.
111
+ - Rest/walk days: use 0 or a small fixed value (30-40) based on typical walk TSS from recent data.
112
+
113
+ Include the projection output in the Orient announcement:
114
+ - Predicted next-morning CTL/ATL/TSB
115
+ - Multi-day trajectory through the end of the current week
116
+ - Flag any day where projected TSB crosses a persona threshold (push/moderate/easy/rest)
117
+
118
+ If the tool is not installed (npm dependencies missing in analysis-tools/), skip this step and annotate: "[TSB projection unavailable — run `npm install` in analysis-tools/.]"
119
+
120
+ 3. **Training block context** — determine current phase (base/build/peak/recovery), position within the week, and upcoming workouts that may be affected by today's adaptation. After identifying the active block from step 1, resolve the block name to a template file name by stripping any date prefix and normalizing to lowercase with hyphens (e.g., "Build 1" → "build-1", "Base" → "base", "Race Specificity" → "race-specificity"). Then read `${CLAUDE_PLUGIN_ROOT}/templates/{block-name}.md` as additional context. This file describes the block's intent, session patterns, weekly structure, and success signals. If the file is missing: continue without it and annotate in the Orient summary: "[Block template {block-name}.md not found — proceeding without block template context.]"
121
+
122
+ 4. **Retrieval — find precedent.** Follow `${CLAUDE_PLUGIN_ROOT}/shared/retrieval.md`.
123
+ Build 2-3 queries from *this session's specifics* — the session type, the numbers
124
+ actually observed, and any anomaly worth explaining — never from this skill's name
125
+ or topic. Cover both levels the policy describes: durable pattern, and session
126
+ precedent. Report honestly when nothing relevant is found.
127
+
128
+ Announce what you found before asking anything. If past decisions are relevant (e.g., "Last time RPE was high on week 2 sub-LT2, we reduced interval count by one"), surface them explicitly.
129
+
130
+ ---
131
+
132
+ ### Phase 2 — Gather _(one question at a time)_
133
+
134
+ Ask only what execution data cannot answer. Adapt to what the data shows — if a specific pattern is visible (e.g., power fade >10% on final interval), ask specifically about that observation rather than generically.
135
+
136
+ Core question domains:
137
+
138
+ 1. **Overall RPE** — rate the full session 1–10
139
+ 2. **Interval progression** — how did intervals feel early vs. late? (effort drift, fade, or build)
140
+ 3. **Physical sensations** — leg heaviness, HR behavior, breathing quality, any discomfort or unusual response
141
+ 4. **Recovery context** — sleep quality the night before, life stress, sense of accumulated fatigue going into the session
142
+ 5. **In-session modifications** — anything deliberately changed in the moment and why
143
+
144
+ **Ask one question at a time. Wait for each answer before asking the next.**
145
+
146
+ ---
147
+
148
+ ### Phase 3 — Synthesize _(shown to athlete)_
149
+
150
+ Reason aloud before proposing anything. Cover:
151
+
152
+ - Prescription vs. execution delta — what happened vs. what was planned
153
+ - Stream analysis results — for each analysis that produced a result in step 2b, state: the metric value, its threshold classification (green/amber/red per persona thresholds), and how it interacts with the existing signal picture (TSB/HRV/CTL). Consult the persona's monitoring.md `## Analysis Interpretation` section for the interpretation framework and coaching voice for each analysis. Higher-weight analyses (as configured in the persona's `analyses` config) receive more reasoning space; lower-weight analyses are mentioned briefly. Analyses that **reinforce** the existing signal picture (e.g., decoupling green while TSB is in push zone) are noted concisely. Analyses that **contradict** the existing signal picture (e.g., decoupling red while TSB is in push zone) are called out explicitly with the specific signal interaction from the monitoring.md — these contradictions are the high-value findings that may change the recommendation.
154
+ - Subjective data weighted against objective data (e.g., low RPE despite power fade → pacing issue, not fitness gap)
155
+ - Training block position — implications differ between early build (accumulate) and peak week (preserve)
156
+ - Upcoming workout demands — does the next session's intensity change the calculus?
157
+ - Relevant patterns from QMD history — call out if this matches a prior situation
158
+ - **HRV trend (when `hrv_trend` fired):** State the statistical position — z_long, percentile, consecutive days below long mean — not just the raw value. Reference the analog lookup: "In N prior instances at or below this value, the median rebound was X days [and prior episodes did/did not show sustained suppression]." This positions the recommendation on the personal distribution rather than an absolute threshold.
159
+
160
+ This phase is **explanatory only**. No changes proposed yet. The athlete can push back on any part of the reasoning before you proceed.
161
+
162
+ Alongside the reasoning above, assemble the typed domain input for this adaptation as a `StructuredChangeSet`. Emit **one state change** containing:
163
+
164
+ - `entity_type: "prescription"` with `key_components` carrying `arc_id` and the durable `session_id` of the NEXT session being adapted
165
+ - the effective date of the change
166
+ - a concise statement of what changes and why
167
+ - the COMPLETE updated prescription session value — never a prose patch. The value must carry every field of the session: `sessionId`, `sessionDate`, `sessionName`, block metadata (`blockName`, `week`, `day`), `order`, `effortZone`, warmup/cooldown power bands, and the full `intervals` array (each with `durationMin`, `powerLowPct`, `powerHighPct`, `count`, `recoveryMin`)
168
+ - the artifact relative path (e.g. `prescriptions/{arc_id}.yaml`)
169
+
170
+ Also emit **one workout-adaptation event** containing:
171
+
172
+ - the completed workout: name, date, and the source activity ID from Intervals.icu
173
+ - the objective deltas — prescription vs. execution metrics gathered in Phase 1 (power targets met/missed, duration completed, fade/drift)
174
+ - the subjective inputs gathered in Phase 2 (RPE, sensations, recovery context, in-session modifications)
175
+ - the approved rationale linking the Phase 3 evidence to the change
176
+ - the stream-analysis results: for each analysis that ran in step 2b, the metric value and its threshold classification (green/amber/red per persona thresholds)
177
+ - the signal interactions noted during Synthesize — how the analyses combined with TSB/HRV/CTL to inform the recommendation
178
+ - `action_targets`: the session IDs the adaptation acts on
179
+ - the compatibility path of the adaptation log (e.g. `coaching/adaptations.md`)
180
+
181
+ If Phase 3 concludes no prescription change is warranted, the change set carries only the workout-adaptation event.
182
+
183
+ **Monitoring contributions (merged BEFORE Phase 4)**
184
+
185
+ Before Phase 4 begins, collect due monitoring contributions so ONE preview
186
+ covers everything:
187
+
188
+ 1. Invoke the `monitoring-rollup` skill in **CONTRIBUTION MODE** with
189
+ `source = adapt:{block}-{week}-{session}` and the session context already
190
+ gathered. It reads `{coaching_docs_dir}/tracking/concerns.yaml`, gathers
191
+ any DUE active concern, and RETURNS typed `state_changes` (keyed
192
+ `monitoring:<concern-id>:<signal>` current state) and append-only
193
+ `events` — it never previews, never applies, and never writes.
194
+ 2. Merge both arrays into THIS change set. The merged change set is what
195
+ Phase 4 previews: one plan hash and one approval cover the prescription
196
+ adaptation, the workout-adaptation event, and all due monitoring changes
197
+ together.
198
+ 3. If no concern is active or due, monitoring-rollup returns EMPTY arrays.
199
+ Merge them and continue — the parent's single preview stands; never
200
+ produce a second preview for monitoring.
201
+
202
+ ---
203
+
204
+
205
+ ### Phase 4 — Propose _(requires explicit approval)_
206
+
207
+ Propose specific changes to the next workout. For each change state explicitly:
208
+
209
+ - **What** changes — interval count, duration, intensity target, rest period, structure
210
+ - **Why** — the specific reasoning from Phase 3 that drives this change
211
+ - **Tradeoffs** — what will have to change (other sessions in the plan, recovery, or anything outside the plan) to support this change.
212
+
213
+ Example format:
214
+
215
+ > "Reduce next sub-LT2 session from 4×12 to 3×12 — RPE 8.5 on the final interval with visible HR drift suggests cumulative fatigue is higher than block average. Week 3 Thursday is a harder session; preserving freshness outweighs hitting volume today."
216
+
217
+ **When `hrv_trend` fired and `hrv_trend_result` is available:** Express HRV gates in baseline-relative terms. Example:
218
+
219
+ > **GO** if tomorrow's HRV ≥ `long_mean − 0.5×long_sd` (≈ {computed value} based on today's baseline)
220
+ > **MODIFIED** if `long_mean − 1.5×long_sd ≤ HRV < long_mean − 0.5×long_sd`
221
+ > **STAND DOWN** if `HRV < long_mean − 1.5×long_sd` OR {consecutive_days_below_long_mean}+ consecutive days below long mean
222
+
223
+ Compute the numeric approximations from `hrv_trend_result.baselines.long_mean` and `hrv_trend_result.baselines.long_sd`. This recalibrates gates automatically as the baseline drifts.
224
+
225
+ **Before presenting anything**, call `engram_capture_preview` with the Phase 3 merged `StructuredChangeSet` — the single preview covers the prescription adaptation, the workout-adaptation event, and any due monitoring contributions as one plan.
226
+
227
+ If the preview returns blocked, STOP: Phase 4 cannot proceed until the input is corrected and a preview succeeds.
228
+
229
+ Present TOGETHER, in one message:
230
+
231
+ 1. The human coaching proposal: for each change, **What** changes, **Why**, and any **Tradeoffs** (including the HRV gates above when they fired).
232
+ 2. The record plan from the preview: which records will be created, refined, superseded, or retired.
233
+ 3. The generated compatibility artifact paths that will regenerate (e.g. `prescriptions/{arc_id}.yaml`, `coaching/adaptations.md`).
234
+ 4. The exact `plan_hash` from the preview result.
235
+
236
+ Ask for approval. Approval must explicitly cover BOTH the coaching action AND the record/artifact plan identified by that exact `plan_hash` — approving the adaptation approves the durable mutation of the same content.
237
+
238
+ Wait for **explicit approval, rejection, or modification**. On modification, rebuild the change set, re-run `engram_capture_preview`, and present the new hash.
239
+
240
+ ---
241
+
242
+ ### Phase 5 — Apply _(with approved hash)_
243
+
244
+ Call `engram_capture_apply` with ONLY the exact `plan_hash` the athlete approved. Never edit any file directly and never invoke indexing tools by hand — every prescription YAML, the adaptation log, and the index are updated by the apply pipeline (records → guarded index refresh → regenerated compatibility views).
245
+
246
+ Outcome handling:
247
+
248
+ - **stale**: the records changed since preview. Return to Phase 4: re-run `engram_capture_preview`, present the fresh record plan and new `plan_hash`, and obtain fresh athlete approval before applying again.
249
+ - **apply failure**: stop Phase 5. No compatibility view is written and none may be edited by hand; diagnose and retry through the tools.
250
+ - **committed with a stale index or stale views**: the records ARE authoritative — report the authoritative record IDs to the athlete together with the materialized paths and the exact retry state: re-calling `engram_capture_apply` with the SAME committed `plan_hash` in the same session reruns only materialization and never re-approves or re-applies the record mutations.
251
+ - **committed clean**: report the applied record IDs and the regenerated compatibility view paths.
252
+
253
+ ---
254
+
255
+ ## Key Constraints
256
+
257
+ | Rule | Detail |
258
+ | -------------------------- | --------------------------------------------------------------------------------------------------- |
259
+ | Rigid phases | Execute in order — no skipping, reordering, or combining |
260
+ | Approval gate | Nothing written until Phase 4 explicitly approved |
261
+ | One question at a time | Phase 2 never batches questions |
262
+ | Reasoning before proposing | Phase 3 must complete before Phase 4 begins |
263
+ | Knowledge compounds | Every adaptation recorded in `{coaching_docs_dir}/{season}/`; future Orient phases benefit from past decisions |
@@ -0,0 +1,275 @@
1
+ ---
2
+ name: block-review
3
+ description: Use at the end of a training block (or retroactively for past blocks) to synthesize block-level metrics and narrative into a SUMMARY.md. Requires Intervals.icu MCP tools and config.json with coaching_docs_dir and prescriptions_dir configured.
4
+ ---
5
+
6
+ # Block Review
7
+
8
+ ## Overview
9
+
10
+ Rigid four-phase workflow for end-of-block synthesis. Combines MCP-derived fitness metrics with QMD-retrieved narrative excerpts and athlete reflection to produce a `SUMMARY.md` document — the canonical block-level reference for all future Orient phases. Works at block boundaries and retroactively for past blocks.
11
+
12
+ **This skill is RIGID — phases execute in exact order. Do not skip, reorder, or combine phases.**
13
+
14
+ ## Workflow
15
+
16
+ ```dot
17
+ digraph block_review {
18
+ "Phase 1: Orient" [shape=box];
19
+ "Phase 2: Gather" [shape=box];
20
+ "Phase 3: Draft" [shape=box];
21
+ "Athlete approves?" [shape=diamond];
22
+ "Phase 4: Write" [shape=box];
23
+
24
+ "Phase 1: Orient" -> "Phase 2: Gather";
25
+ "Phase 2: Gather" -> "Phase 3: Draft";
26
+ "Phase 3: Draft" -> "Athlete approves?";
27
+ "Athlete approves?" -> "Phase 4: Write" [label="yes"];
28
+ "Athlete approves?" -> "Phase 3: Draft" [label="revise"];
29
+ }
30
+ ```
31
+
32
+ ---
33
+
34
+ ### Pre-Phase Setup _(no user input — run silently)_
35
+
36
+ Follow **`${CLAUDE_PLUGIN_ROOT}/shared/setup.md`** — the shared configuration
37
+ preamble (paths, config, profile, persona, athlete profile).
38
+
39
+ **Optional steps this skill declares:** SEASON, MCP
40
+
41
+ Do not proceed past a stop condition defined there.
42
+
43
+
44
+ ### Phase 1 — Orient _(no user input)_
45
+
46
+ Pull all data silently, then announce findings before asking anything.
47
+
48
+ **MCP calls** — all scoped to the block date window:
49
+
50
+ 1. `get_wellness_data(days_back={block_duration_days + 1})` — CTL/ATL/TSB, HRV rMSSD,
51
+ RHR per day across the full block. Scope to dates between `block_start` and `block_end`.
52
+
53
+ 2. `get_recent_activities(days_back={block_duration_days + 1}, limit=50)` — per-session
54
+ TSS, activity name, type, date. Filter to dates within the block window.
55
+
56
+ 3. `get_power_curves(days_back=28)` and `get_power_curves(days_back=90)` — power at
57
+ persona-configured durations for block vs. 90-day baseline comparison.
58
+ If these calls return an API error (known recurring issue), skip and annotate:
59
+ "[Power curve data unavailable — MCP API error. Proceeding without power curve section.]"
60
+
61
+ **Compute and extract from MCP data:**
62
+
63
+ - **CTL trajectory:** value at `block_start`, value at `block_end`, peak value and date,
64
+ delta (end minus start), peak ramp rate (largest single-day CTL increase)
65
+ - **ATL trajectory:** peak value and date, value at `block_end`
66
+ - **TSB trajectory:** lowest point and date, value at `block_end`
67
+ - **HRV rMSSD:** block average (mean of all daily readings), first-week average vs.
68
+ last-week average (trend direction), lowest reading and date
69
+ - **RHR:** block average, first-week average vs. last-week average (trend direction)
70
+ - **Volume by week:** sum TSS per calendar week within the block window
71
+ - **Power curve:** % change at persona-configured durations
72
+ (block 28-day best vs. 90-day best; positive = improving, negative = declining)
73
+
74
+ **QMD queries** — narrative and decision context:
75
+
76
+ ```bash
77
+ qmd query "{block_name} key session progression"
78
+ qmd query "{block_name} adaptation decisions"
79
+ qmd vsearch "{block_name}"
80
+
81
+ Follow `${CLAUDE_PLUGIN_ROOT}/shared/retrieval.md` when constructing these — parameterize with the specifics below, and add queries for whatever this particular block actually raises.
82
+ ```
83
+
84
+ Extract from QMD results:
85
+ - Key session metric progressions (power/HR/RPE across W1→W2→W3 for each key
86
+ session type: threshold intervals, over-under intervals, long ride)
87
+ - Notable adaptation decisions and their reasoning
88
+ - Patterns flagged in "Patterns for Future Orient Phases" sections
89
+
90
+ **Announce** what was found. Cover:
91
+ - Block dates, duration, total TSS
92
+ - CTL trajectory summary (start → end, delta, peak ramp rate)
93
+ - HRV and RHR trend direction over the block
94
+ - Key session progressions surfaced by QMD
95
+ - Power curve trend if available
96
+ - Any data gaps (missing HRV days, power curve API errors, etc.)
97
+ - Any immediately notable findings (e.g., highest ramp rate of the training year,
98
+ HRV suppression pattern, power curve decline despite CTL growth)
99
+
100
+ ---
101
+
102
+ ### Phase 2 — Gather _(one question at a time)_
103
+
104
+ Ask exactly three questions, in order. Wait for each answer before asking the next.
105
+
106
+ 1. **Block surprise:** "Looking at the block as a whole — what surprised you most,
107
+ positively or negatively?"
108
+
109
+ 2. **Forward confidence:** "What's your confidence going into [next block name]?
110
+ What feels strongest, and what feels like the biggest unknown?"
111
+
112
+ 3. **Off-record context:** "Is there anything that happened during this block —
113
+ training or life — that the adaptation records might not fully capture?"
114
+
115
+ ---
116
+
117
+ ### Phase 3 — Draft _(shown to athlete)_
118
+
119
+ Present the complete `SUMMARY.md` content as a draft. The athlete can request
120
+ changes before anything is written. Iterate until explicitly approved.
121
+
122
+ **Explicit report conclusions:** alongside the narrative sections, distill
123
+ the block's atomic, explicitly approved conclusions — facts that bear on
124
+ existing keyed state (thresholds, persona signals, monitoring concerns).
125
+ Each conclusion is recorded as an entry of the `report_claims` array in
126
+ the structured change set (`StructuredReportClaim`) with ALL of:
127
+ - `entity_type`: `block-conclusion`
128
+ - `key_components`: the exact canonical state entity it bears on
129
+ (`entity_type` plus its durable identity components)
130
+ - `effective_at`: the effective time of the conclusion
131
+ - `statement`: one-sentence human-readable claim
132
+ - `source_document`: the relative path of the `SUMMARY.md` this conclusion
133
+ comes from
134
+ - `details`: the structured value of the conclusion
135
+
136
+ Narrative stays in the document; only these atomic conclusions become
137
+ records.
138
+
139
+ **Record preview — one combined approval:** alongside the full `SUMMARY.md`
140
+ draft, call `engram_capture_preview({ change_set })` with the change set
141
+ containing those `report_claims`. Show the complete report AND the record
142
+ preview (the exact plan hash, each record's role/classification) together.
143
+ The athlete approves BOTH under ONE approval; the approved plan hash is
144
+ bound to this exact content. Iterate until explicitly approved. If the
145
+ preview is blocked, fix the change set and re-preview — this phase cannot
146
+ complete without a ready plan hash.
147
+
148
+ **Document structure:**
149
+
150
+ ```markdown
151
+ # {Block Display Name} — Block Summary
152
+ **Dates:** {block_start} → {block_end}
153
+ **Persona:** {active_persona display name}
154
+ **Block goal:** {one sentence from template, or inferred from block name if template missing}
155
+
156
+ ## Fitness Metrics
157
+ | Metric | Block Start | Block End | Change |
158
+ |--------|------------|-----------|--------|
159
+ | CTL | | | |
160
+ | ATL (peak) | {date} | | |
161
+ | TSB (low point) | {date} | | |
162
+ | HRV rMSSD (block avg) | — | — | {first week avg} → {last week avg} |
163
+ | RHR (block avg) | — | — | {first week avg} → {last week avg} |
164
+ | Peak ramp rate | — | — | {value} TSS/day |
165
+
166
+ ## Volume
167
+ | Week | Actual TSS | Key sessions completed |
168
+ |------|-----------|----------------------|
169
+ | W1 | | |
170
+ | W2 | | |
171
+ | W3 | | |
172
+ | Total | | |
173
+
174
+ ## Key Session Progressions
175
+ {One table per key session type present in the block}
176
+
177
+ Example for threshold intervals:
178
+ | | W1 | W2 | W3 |
179
+ |---|---|---|---|
180
+ | Structure | 3×10min | 3×12min | 4×12min |
181
+ | Avg power | | | |
182
+ | Avg HR | | | |
183
+ | RPE | | | |
184
+ | Notes | | | |
185
+
186
+ ## Power Curve
187
+ {Skip section if data unavailable — annotate why}
188
+ | Duration | Block best | vs. 90-day best | Trend |
189
+ |----------|-----------|-----------------|-------|
190
+ | 20min (1200s) | | | |
191
+ | 60min (3600s) | | | |
192
+
193
+ ## Block Assessment
194
+ Narrative: how block goals (from template) compare to actual outcomes.
195
+ What the data says worked. What the data says didn't. How the block's
196
+ execution compared to the template's "signals this block should produce."
197
+ Reference the active persona's stated decision signals — the volume policy
198
+ prioritizes CTL trajectory, while the conservative policy weights freshness and HRV more heavily.
199
+
200
+ ## Athlete Perspective
201
+ Narrative from Phase 2 Gather — surprises (positive and negative),
202
+ qualitative feel of the block, what the athlete would do differently.
203
+ Written in the athlete's voice, not paraphrased into coaching language.
204
+
205
+ ## Calibration Points for Future Blocks
206
+ Bullet list of concrete, queryable facts discovered during the block:
207
+ - Session ceilings (e.g., "surge ceiling: 2 full + partial third at 5+ hours")
208
+ - Recovery patterns (e.g., "big Saturday → 72hr to rebound to HRV 40+")
209
+ - Fueling discoveries
210
+ - Equipment notes
211
+ - External stress interaction patterns
212
+ - Anything flagged in individual adaptation records under "Patterns for Future Orient Phases"
213
+
214
+ ## Entering {Next Block Name}
215
+ Confidence level (from Gather). Specific watchpoints for the first week
216
+ of the next block based on how this one ended — what to monitor, what
217
+ the first key session should confirm, and what would trigger a reassessment.
218
+ ```
219
+
220
+ ---
221
+
222
+ ### Phase 4 — Write _(with approval)_
223
+
224
+ Write, in this exact order:
225
+
226
+ **1. Block summary document — FIRST**
227
+
228
+ Write `{coaching_docs_dir}/{season}/{block}/SUMMARY.md` with the approved
229
+ content. Create the directory if it does not exist:
230
+ ```bash
231
+ mkdir -p {coaching_docs_dir}/{season}/{block}/
232
+ ```
233
+
234
+ This is the authoritative canonical block summary — it is never regenerated
235
+ from records. **If this write fails for any reason, STOP: do not apply any
236
+ records; report the failure to the athlete.**
237
+
238
+ **2. Apply the approved capture plan**
239
+
240
+ Only after the document write succeeded, call
241
+ `engram_capture_apply({ plan_hash })` with the exact plan hash approved in
242
+ Phase 3.
243
+ - `status: "stale"` → the pending preview was discarded; return to Phase 3,
244
+ re-preview, and get fresh approval.
245
+ - Report any index or compatibility-view staleness from the result to the
246
+ athlete (records remain authoritative either way); a stale index refresh
247
+ is retried via the guarded mechanism, never by editing generated views.
248
+
249
+ **3. Auto-tail lessons-rollup — only after BOTH succeed**
250
+
251
+ Invoke the `lessons-rollup` skill ONLY after BOTH the `SUMMARY.md` write AND
252
+ the report claims apply succeeded:
253
+ - `--source=block-review:{normalized-block-name}`
254
+ - The bullets from the just-written SUMMARY.md's
255
+ `## Calibration Points for Future Blocks` section as the append list.
256
+
257
+ The rollup keeps its own harness-backed claim gate; the report is never
258
+ reconstructed from the captured claims. Non-additive diffs gate on athlete
259
+ approval before writing.
260
+
261
+ ---
262
+
263
+ ## Key Constraints
264
+
265
+ | Rule | Detail |
266
+ |------|--------|
267
+ | Rigid phases | Execute in order — no skipping, reordering, or combining |
268
+ | Approval gate | Nothing written until Phase 3 draft explicitly approved — report text and capture plan approved together under one approval |
269
+ | One question at a time | Phase 2 never batches questions |
270
+ | No full file reads | MCP for metrics, QMD for narrative — no prescription YAML reads beyond frontmatter, no full adaptation record reads |
271
+ | Retroactive-safe | Works on past blocks; block date window comes from prescription YAML frontmatter, not "today" |
272
+ | Data gaps are acceptable | Missing power curves, HRV gaps, or QMD misses are annotated and the skill continues — a partial summary is better than no summary |
273
+ | Canonical report first | Phase 4 writes `SUMMARY.md` FIRST; a failed document write stops before any record apply |
274
+ | Explicit conclusions only | Only the atomic `report_claims` from the approved change set become records; narrative stays in the document |
275
+ | Auto-tail rollup | lessons-rollup runs only after BOTH the document write and claims apply succeed |