@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.
- package/README.md +85 -18
- package/SETUP.md +559 -0
- package/SKILL_PACK.md +75 -0
- package/analyses/catalog.md +257 -0
- package/analysis-tools/hrv-trend.ts +592 -0
- package/analysis-tools/migrate-structured-capture.ts +234 -0
- package/analysis-tools/race-context.ts +96 -0
- package/analysis-tools/stream-analyze.ts +1008 -0
- package/analysis-tools/tsb-predict.ts +117 -0
- package/capture-handler.ts +301 -0
- package/config.json.example +21 -0
- package/engram-coach-ambient-capture.ts +336 -0
- package/engram-coach-capture-types.ts +185 -0
- package/engram-coach-config.ts +268 -0
- package/engram-coach-domain.ts +7 -2
- package/engram-coach-keys.ts +189 -0
- package/engram-coach-materialization.ts +638 -0
- package/engram-coach-migration.ts +1078 -0
- package/engram-coach-pack.ts +17 -12
- package/engram-coach-presentation.ts +10 -1
- package/engram-coach-reconciliation.ts +305 -2
- package/engram-coach-structured-capture.ts +622 -0
- package/package.json +39 -6
- package/personas/aggressive-monitoring.md +121 -0
- package/personas/aggressive.json +85 -0
- package/personas/conservative-monitoring.md +133 -0
- package/personas/conservative.json +93 -0
- package/personas/polarized-monitoring.md +112 -0
- package/personas/polarized.json +72 -0
- package/personas/volume-monitoring.md +85 -0
- package/personas/volume.json +108 -0
- package/shared/retrieval.md +71 -0
- package/shared/setup.md +207 -0
- package/skills/.gitkeep +0 -0
- package/skills/adapt-plan/SKILL.md +263 -0
- package/skills/block-review/SKILL.md +275 -0
- package/skills/consult/SKILL.md +176 -0
- package/skills/intake/SKILL.md +315 -0
- package/skills/lactate-analyze/SKILL.md +230 -0
- package/skills/lessons-rollup/SKILL.md +196 -0
- package/skills/monitoring-rollup/SKILL.md +208 -0
- package/skills/race-analysis/SKILL.md +219 -0
- package/skills/season-retrospective/SKILL.md +200 -0
- package/skills/set-goal/SKILL.md +297 -0
- package/templates/base.md +55 -0
- package/templates/build-1.md +57 -0
- package/templates/build-2.md +62 -0
- package/templates/race-report.md +51 -0
- package/templates/race-specificity.md +62 -0
- package/templates/season-review.md +40 -0
- package/engram-coach-extractor.ts +0 -295
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lactate-analyze
|
|
3
|
+
description: Query lactate analysis results for an athlete. Use this when you need LT1/LT2/FTP/FTHR values and their confidence intervals for training decisions. Also use when analyzing spot test results or comparing to historical tests.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lactate Analysis
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
This skill provides access to the lactate analysis subsystem for querying threshold values, FTP/FTHR estimates, and spot test analysis. Engram Coach uses this during Orient phase to inform training decisions.
|
|
11
|
+
|
|
12
|
+
## Data Flow
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Prescription YAML (spot test orders)
|
|
16
|
+
│
|
|
17
|
+
▼
|
|
18
|
+
Athlete performs test
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
lactate import (CLI)
|
|
22
|
+
│
|
|
23
|
+
▼
|
|
24
|
+
Analysis Engine (multiple methods + CI)
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
Results stored in JSON
|
|
28
|
+
│
|
|
29
|
+
▼
|
|
30
|
+
lactate query (CLI or API)
|
|
31
|
+
│
|
|
32
|
+
▼
|
|
33
|
+
Engram Coach adapts training
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Import Ramp Test Data
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cd lactate
|
|
42
|
+
npm install
|
|
43
|
+
npm run build
|
|
44
|
+
|
|
45
|
+
# Import a ramp test from CSV
|
|
46
|
+
lactate import -f /path/to/test.csv -t ramp -d 2026-03-01 -s cycling
|
|
47
|
+
|
|
48
|
+
# CSV format:
|
|
49
|
+
# power,heartrate,lactate
|
|
50
|
+
# 150,120,1.2
|
|
51
|
+
# 175,135,1.5
|
|
52
|
+
# 200,150,2.1
|
|
53
|
+
# ...
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Query Latest Analysis
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
lactate query --latest
|
|
60
|
+
lactate query --latest --compare # Compare to previous test
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Query via API (for Engram Coach integration)
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import { createLactateAPI } from './lactate';
|
|
67
|
+
|
|
68
|
+
// Create API instance
|
|
69
|
+
const api = createLactateAPI('athlete-id', '/path/to/data/dir');
|
|
70
|
+
|
|
71
|
+
// Query latest analysis
|
|
72
|
+
const result = await api.query({ compareToPrevious: true });
|
|
73
|
+
|
|
74
|
+
console.log(result.currentAnalysis.lt2.power); // e.g., 235
|
|
75
|
+
console.log(result.currentAnalysis.ftp.value); // e.g., 248
|
|
76
|
+
console.log(result.currentAnalysis.lt2.ci80); // e.g., [228, 242]
|
|
77
|
+
console.log(result.comparison?.interpretation); // "LT2 improved by 10W"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Spot Test Workflow
|
|
81
|
+
|
|
82
|
+
### 1. Coach Orders Spot Test (in Prescription YAML)
|
|
83
|
+
|
|
84
|
+
```yaml
|
|
85
|
+
sessions:
|
|
86
|
+
- week: 3
|
|
87
|
+
day: Thu
|
|
88
|
+
session_name: W3_SweetSpot
|
|
89
|
+
total_duration_min: 120
|
|
90
|
+
intervals:
|
|
91
|
+
- duration_min: 20
|
|
92
|
+
power_low_pct: 88
|
|
93
|
+
power_high_pct: 92
|
|
94
|
+
count: 3
|
|
95
|
+
recovery_min: 8
|
|
96
|
+
spot_tests:
|
|
97
|
+
- interval_ref: 2
|
|
98
|
+
sample_times_min: [10, 20]
|
|
99
|
+
reason: "Verify sweet spot intensity is below LT2"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. Athlete Performs Test and Imports Results
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# After the session, athlete imports spot readings
|
|
106
|
+
lactate import -f spot_readings.csv -t spot -r "W3_SweetSpot-interval2"
|
|
107
|
+
|
|
108
|
+
# CSV format:
|
|
109
|
+
# power,heartrate,lactate
|
|
110
|
+
# 220,155,1.8
|
|
111
|
+
# 225,160,2.1
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 3. Analyze Spot Test
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const spotAnalysis = await api.analyzeSpotTest(
|
|
118
|
+
[
|
|
119
|
+
{ power: 220, heartrate: 155, lactate: 1.8 },
|
|
120
|
+
{ power: 225, heartrate: 160, lactate: 2.1 }
|
|
121
|
+
]
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
console.log(spotAnalysis.trend); // 'improving', 'stable', 'declining'
|
|
125
|
+
console.log(spotAnalysis.comparisonToBaseline.delta); // e.g., -0.5
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Output Format
|
|
129
|
+
|
|
130
|
+
### LactateAnalysis Response
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"athleteId": "default",
|
|
135
|
+
"testId": "abc-123",
|
|
136
|
+
"testType": "ramp",
|
|
137
|
+
"testDate": "2026-03-01",
|
|
138
|
+
"sport": "cycling",
|
|
139
|
+
"lt1": {
|
|
140
|
+
"power": 185,
|
|
141
|
+
"heartrate": 142,
|
|
142
|
+
"lactate": 1.8,
|
|
143
|
+
"ci80": [178, 192],
|
|
144
|
+
"ci95": [170, 198],
|
|
145
|
+
"method": "log-log",
|
|
146
|
+
"methodType": "primary"
|
|
147
|
+
},
|
|
148
|
+
"lt2": {
|
|
149
|
+
"power": 235,
|
|
150
|
+
"heartrate": 165,
|
|
151
|
+
"lactate": 4.2,
|
|
152
|
+
"ci80": [228, 242],
|
|
153
|
+
"ci95": [220, 250],
|
|
154
|
+
"method": "dmax",
|
|
155
|
+
"methodType": "primary"
|
|
156
|
+
},
|
|
157
|
+
"ftp": {
|
|
158
|
+
"value": 248,
|
|
159
|
+
"ci80": [240, 255],
|
|
160
|
+
"ci95": [235, 262],
|
|
161
|
+
"method": "lt2-derived"
|
|
162
|
+
},
|
|
163
|
+
"fthr": {
|
|
164
|
+
"value": 168,
|
|
165
|
+
"ci80": [162, 172],
|
|
166
|
+
"method": "lt2-hr"
|
|
167
|
+
},
|
|
168
|
+
"testQuality": "good",
|
|
169
|
+
"confidence": "high",
|
|
170
|
+
"methodsUsed": ["dmax", "obla_4", "log-log"],
|
|
171
|
+
"dataQualityNotes": []
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Analysis Methods
|
|
176
|
+
|
|
177
|
+
The analyzer runs multiple detection methods and provides confidence intervals:
|
|
178
|
+
|
|
179
|
+
| Method | Best For | Primary Target |
|
|
180
|
+
|--------|----------|----------------|
|
|
181
|
+
| Log-log | LT1 detection | LT1 |
|
|
182
|
+
| Dmax | Full curves | LT2 |
|
|
183
|
+
| Modified Dmax | Noisy data | LT2 |
|
|
184
|
+
| OBLA 4.0 | Fixed threshold | LT2 |
|
|
185
|
+
| OBLA 2.0 | Fixed threshold | LT1 |
|
|
186
|
+
| Baseline+ | Drift correction | LT1 |
|
|
187
|
+
|
|
188
|
+
**Confidence Intervals:**
|
|
189
|
+
- 80% CI: Likely range for training decisions
|
|
190
|
+
- 95% CI: Bounds for conservative planning
|
|
191
|
+
- Wider CI for marginal/poor data quality
|
|
192
|
+
|
|
193
|
+
## Integration Points
|
|
194
|
+
|
|
195
|
+
### During adapt-plan Orient Phase
|
|
196
|
+
|
|
197
|
+
1. Check if lactate data exists: `await api.query()`
|
|
198
|
+
2. If available, incorporate thresholds into signal synthesis:
|
|
199
|
+
- Use LT1 power for upper Z2 boundary
|
|
200
|
+
- Use LT2 power for threshold zone (Z4)
|
|
201
|
+
- Use FTP for training zones
|
|
202
|
+
- Reference confidence intervals for decision uncertainty
|
|
203
|
+
3. If spot tests available, analyze trend
|
|
204
|
+
|
|
205
|
+
### QMD Knowledge Integration
|
|
206
|
+
|
|
207
|
+
After significant analysis results (new baseline test), create a knowledge record:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
{coaching_docs_dir}/lactate/YYYY-MM-DD-ramp-analysis.md
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Include:
|
|
214
|
+
- LT1/LT2 power and HR with CIs
|
|
215
|
+
- FTP/FTHR values
|
|
216
|
+
- Comparison to previous test
|
|
217
|
+
- Methods used
|
|
218
|
+
- Data quality notes
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Error Handling
|
|
223
|
+
|
|
224
|
+
| Scenario | Response |
|
|
225
|
+
|----------|----------|
|
|
226
|
+
| No tests found | Return null, skip lactate analysis in orient |
|
|
227
|
+
| Only 1-2 points | Reduce confidence to medium/low, warn user |
|
|
228
|
+
| LT1 not detected | Use OBLA 2.0 as fallback |
|
|
229
|
+
| LT2 not detected | Use OBLA 4.0 as fallback |
|
|
230
|
+
| CI unavailable | Report point estimate only, note reduced confidence |
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lessons-rollup
|
|
3
|
+
description: Append calibration points to lessons-log.md, then propose claim records and re-render ATHLETE_PROFILE.md and COACH_PROFILE.md through the engram harness rollup gate. Auto-tails block-review, race-analysis, and season-retrospective; can also run standalone for re-curation. Requires config.json configured and a registered harness space.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lessons Rollup
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Rigid four-phase workflow for maintaining the athlete-lifetime learning record. Appends new calibration points to an append-only log, proposes claim records for the changes, and re-renders the `ATHLETE_PROFILE.md` and `COACH_PROFILE.md` working summaries that `adapt-plan`, `consult`, `block-review`, and `season-retrospective` read as reasoning context. Diffing, the approval gate, sequential application, and the qmd refresh/embedding pass belong to the harness; this skill supplies coaching judgment and nothing else.
|
|
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 lessons_rollup {
|
|
18
|
+
"Phase 1: Append to log" [shape=box];
|
|
19
|
+
"Phase 2: Propose candidates" [shape=box];
|
|
20
|
+
"Phase 3: rollup preview" [shape=box];
|
|
21
|
+
"approval_required?" [shape=diamond];
|
|
22
|
+
"Show diff to athlete" [shape=box];
|
|
23
|
+
"Approved?" [shape=diamond];
|
|
24
|
+
"Phase 3: rollup approve" [shape=box];
|
|
25
|
+
"Phase 4: Re-render profiles" [shape=box];
|
|
26
|
+
"Skip write" [shape=box];
|
|
27
|
+
|
|
28
|
+
"Phase 1: Append to log" -> "Phase 2: Propose candidates";
|
|
29
|
+
"Phase 2: Propose candidates" -> "Phase 3: rollup preview";
|
|
30
|
+
"Phase 3: rollup preview" -> "approval_required?";
|
|
31
|
+
"approval_required?" -> "Show diff to athlete" [label="yes"];
|
|
32
|
+
"approval_required?" -> "Phase 3: rollup approve" [label="no (additive)"];
|
|
33
|
+
"Show diff to athlete" -> "Approved?";
|
|
34
|
+
"Approved?" -> "Phase 3: rollup approve" [label="yes"];
|
|
35
|
+
"Approved?" -> "Skip write" [label="no"];
|
|
36
|
+
"Phase 3: rollup approve" -> "Phase 4: Re-render profiles";
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Invocation Modes
|
|
43
|
+
|
|
44
|
+
This skill is called in two modes:
|
|
45
|
+
|
|
46
|
+
**Auto-tail (called by other skills):** Caller passes `--source={tag}` (e.g., `block-review:example-build`, `race:example-endurance-event`, `season:2027-example-season`) and an optional explicit list of bullets to append. Non-additive diffs still gate on approval.
|
|
47
|
+
|
|
48
|
+
**Standalone (manual):** No `--source` flag. Skips Phase 1 (no append), runs Phase 2 only — re-curates the profile from the existing log. Use after manually editing `lessons-log.md` or after a persona change.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
### Pre-Phase Setup _(no user input — run silently)_
|
|
53
|
+
|
|
54
|
+
Follow **`${CLAUDE_PLUGIN_ROOT}/shared/setup.md`** — the shared configuration
|
|
55
|
+
preamble (paths, config, profile, persona, athlete profile).
|
|
56
|
+
|
|
57
|
+
**Optional steps this skill declares:** none — config, persona, and athlete profile only
|
|
58
|
+
|
|
59
|
+
Do not proceed past a stop condition defined there.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
### Phase 1 — Append to log _(skipped in standalone mode)_
|
|
63
|
+
|
|
64
|
+
For each new bullet provided by the caller, append a new entry to `lessons-log.md` in this format:
|
|
65
|
+
|
|
66
|
+
```markdown
|
|
67
|
+
## {YYYY-MM-DD} — {source-tag}
|
|
68
|
+
- {bullet 1}
|
|
69
|
+
- {bullet 2}
|
|
70
|
+
- {bullet 3}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Use today's date. Source tag is the exact value passed in (e.g., `race:gravel-classic-2026`).
|
|
74
|
+
|
|
75
|
+
The append is literal — never rewrite or merge with prior entries. Multiple invocations on the same day under the same source tag append multiple sections (the curation step in Phase 2 dedupes the working profile).
|
|
76
|
+
|
|
77
|
+
Announce: "Appended {N} bullets to lessons-log.md under {source-tag}."
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### Phase 2 — Propose claim candidates
|
|
82
|
+
|
|
83
|
+
Read the entire `lessons-log.md`. The profile is no longer hand-written: it is a
|
|
84
|
+
**rendered artifact** produced from claim records under `{coaching_docs_dir}/claims/`.
|
|
85
|
+
This phase produces *candidates*; the harness owns diffing, approval, and writing.
|
|
86
|
+
|
|
87
|
+
Reason across all log entries to decide what should change:
|
|
88
|
+
|
|
89
|
+
1. **Group by theme:** the space's configured theme vocabulary, read from
|
|
90
|
+
`{coaching_docs_dir}/pack-config.json`. Adding a theme is a configuration change,
|
|
91
|
+
not a prose change.
|
|
92
|
+
|
|
93
|
+
2. **Dedupe with source merging:** when 2+ entries express the same pattern, propose one
|
|
94
|
+
claim carrying every source tag. A `supersede` candidate inherits the retired claim's
|
|
95
|
+
sources automatically — never restate them by hand.
|
|
96
|
+
|
|
97
|
+
3. **Supersede contradicted entries:** when a newer entry contradicts an older one,
|
|
98
|
+
propose `disposition: "supersede"` naming the predecessor. The harness retires the
|
|
99
|
+
predecessor and keeps its trace; there is no `## Retired` section to maintain.
|
|
100
|
+
|
|
101
|
+
4. **Persona-fit is special:** the bridge between data and persona-change decisions.
|
|
102
|
+
Write each as: pattern observed → does it match the active persona's expectations →
|
|
103
|
+
recommendation.
|
|
104
|
+
|
|
105
|
+
Emit one batch file of candidate envelopes:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{ "schema_version": 0, "candidates": [ { "id": "...", "kind": "claim", "disposition": "new" } ] }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### Phase 3 — Review and approve through the harness
|
|
114
|
+
|
|
115
|
+
The diff gate, the additive/non-additive classification, and the approval binding are the
|
|
116
|
+
harness's, not this skill's. Preview the batch:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
engram rollup preview --bullets {batch}.json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Show the athlete the rendered diff. `approval_required: true` means the batch is
|
|
123
|
+
non-additive and needs an explicit yes. On approval, re-supply the same batch file with
|
|
124
|
+
the previewed hash:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
engram rollup approve --bullets {batch}.json --expect {rollup_hash}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Approval is stateless and bound to the plan: if any record changed since the preview, the
|
|
131
|
+
approval is refused as `stale_approval` and nothing is written. A batch is fail-stop, not
|
|
132
|
+
atomic — earlier commits stand, and the response names the stopping candidate and every
|
|
133
|
+
untried one. Re-preview before retrying.
|
|
134
|
+
|
|
135
|
+
Never run `qmd update` or `qmd embed` here. The harness refreshes the bound collection and
|
|
136
|
+
runs exactly one embedding pass after any durable write, scoped to this space. A bare qmd
|
|
137
|
+
command indexes every collection on the machine and is prohibited.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### Phase 4 — Re-render the profiles
|
|
142
|
+
|
|
143
|
+
Both profiles are generated from the same claim records; neither is edited by hand.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
engram render --view athlete-profile --audience athlete \
|
|
147
|
+
--delivery profile-markdown --model orchestrator/manual
|
|
148
|
+
engram render --view athlete-profile --audience coach \
|
|
149
|
+
--delivery profile-markdown --model orchestrator/manual
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Write the athlete render to `{coaching_docs_dir}/ATHLETE_PROFILE.md` and the coach render
|
|
153
|
+
to `{coaching_docs_dir}/COACH_PROFILE.md`.
|
|
154
|
+
|
|
155
|
+
There is no privacy, visibility, or persona-fit split between these renders. The
|
|
156
|
+
presentation pack authorizes `athlete`, `coach`, and `self-coach` identically — every
|
|
157
|
+
active, retrieval-eligible engram-coach record, unfiltered — and projects the same facts,
|
|
158
|
+
uncertainty, actions, and recommendation IDs into all three. `ATHLETE_PROFILE.md` and
|
|
159
|
+
`COACH_PROFILE.md` are the same content under a different title. `self-coach` is that same
|
|
160
|
+
audience again, for an athlete acting as their own coach; this skill does not keep it as a
|
|
161
|
+
standing file, but it renders on demand identically to the other two:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
engram render --view athlete-profile --audience self-coach \
|
|
165
|
+
--delivery profile-markdown --model orchestrator/manual
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
A fourth audience, `clinician`, is the only one that actually filters: monitoring
|
|
169
|
+
captures, lactate tests, and any record (workout adaptations included) carrying a
|
|
170
|
+
health-relevant training signal (HRV, resting HR, lactate threshold, sleep, stress,
|
|
171
|
+
illness, injury). It is rendered on demand rather than kept as a standing file, because a
|
|
172
|
+
doctor-prep summary is episodic:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
engram render --view athlete-profile --audience clinician \
|
|
176
|
+
--delivery profile-markdown --model orchestrator/manual
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The clinician render carries the same facts/uncertainty/actions shape as the other three,
|
|
180
|
+
narrowed to that health-relevant record set. There is no configurable clinical-theme list
|
|
181
|
+
and no dedicated persona-fit field: any authorized persona-fit record is rendered as a
|
|
182
|
+
normal record-derived fact.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Key Constraints
|
|
187
|
+
|
|
188
|
+
| Rule | Detail |
|
|
189
|
+
|------|--------|
|
|
190
|
+
| Append-only log | `lessons-log.md` is never rewritten or pruned by this skill |
|
|
191
|
+
| Source tagging | Every log entry carries `source-tag`; the harness renders a claim's merged sources into the profile, so tags are never typed by hand |
|
|
192
|
+
| Non-additive gate | Enforced by `rollup preview`/`approve`, not by this skill; approval is bound to the previewed plan and refused as `stale_approval` if anything moved |
|
|
193
|
+
| Standalone is read-only on log | Standalone mode skips Phase 1 — no append, only re-curation |
|
|
194
|
+
| Profiles are generated | `ATHLETE_PROFILE.md` and `COACH_PROFILE.md` are rendered artifacts; hand edits are overwritten by the next render. Change a claim record, not the file |
|
|
195
|
+
| Profiles are identical | `ATHLETE_PROFILE.md` and `COACH_PROFILE.md` carry the same record-derived content — the `athlete`, `coach`, and `self-coach` audiences authorize identically, so there is no private-vs-full split to reconcile |
|
|
196
|
+
| qmd is the harness's | Never run `qmd update`/`qmd embed`; a bare invocation indexes every collection on the machine |
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: monitoring-rollup
|
|
3
|
+
description: Capture due monitoring-concern observations as typed Engram records and let the apply pipeline regenerate each concern's monitoring log and Doctor-Prep Summary. Runs in CONTRIBUTION mode (returns state_changes/events to a parent skill's single change set) or STANDALONE mode (its own preview → approval → apply). Requires config.json and a tracking/concerns.yaml registry.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Monitoring Rollup
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Rigid phased workflow for longitudinal tracking of declared **monitoring
|
|
11
|
+
concerns** — chronic symptoms/issues tracked over time so an eventual
|
|
12
|
+
clinician visit is well-armed with data. Observations are captured as
|
|
13
|
+
structured Engram records; each concern's monitoring log and its curated
|
|
14
|
+
Doctor-Prep Summary are **generated compatibility views** that the apply
|
|
15
|
+
pipeline renders deterministically from those records.
|
|
16
|
+
|
|
17
|
+
**Generic:** all athlete-specific declarations live in
|
|
18
|
+
`{coaching_docs_dir}/tracking/concerns.yaml`. Each entry declares at minimum:
|
|
19
|
+
`id`, `active`, `cadence_days`, the concern's `log` view path, `fields`
|
|
20
|
+
(the controlled columns for entries), optional `record_negatives`, and
|
|
21
|
+
optional `escalation_triggers`. This skill contains no concern-specific
|
|
22
|
+
knowledge.
|
|
23
|
+
|
|
24
|
+
**This skill is RIGID — phases execute in exact order. Do not skip, reorder,
|
|
25
|
+
or combine phases.**
|
|
26
|
+
|
|
27
|
+
Monitoring logs and Doctor-Prep Summaries carry the byte-exact warning header
|
|
28
|
+
(`GENERATED FROM ENGRAM ACTIVE RECORDS. DO NOT EDIT DIRECTLY.`) and are never
|
|
29
|
+
edited directly by this skill or any other. The ONLY durable mutation path is
|
|
30
|
+
an approved capture plan applied through the tools.
|
|
31
|
+
|
|
32
|
+
## Invocation Modes
|
|
33
|
+
|
|
34
|
+
Pick exactly one:
|
|
35
|
+
|
|
36
|
+
1. **CONTRIBUTION MODE** — invoked by a parent skill (`consult`,
|
|
37
|
+
`adapt-plan`) during that parent's Phase 3. Read the registry, gather due
|
|
38
|
+
concerns, and **return typed monitoring items only**. Never previews,
|
|
39
|
+
never applies, never writes.
|
|
40
|
+
2. **STANDALONE MODE** — manual invocation (athlete asks to "log monitoring"
|
|
41
|
+
or run a roll-up). Iterate all active concerns regardless of staleness and
|
|
42
|
+
run the full preview → approval → apply protocol itself.
|
|
43
|
+
3. **RE-CURATE** — athlete asks to re-curate after reviewing data. Read-only
|
|
44
|
+
on records: no capture, no new items. Regeneration happens through
|
|
45
|
+
materialization only (see Re-curate below).
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### Pre-Phase Setup _(no user input — run silently)_
|
|
50
|
+
|
|
51
|
+
Follow **`${CLAUDE_PLUGIN_ROOT}/shared/setup.md`** — the shared configuration
|
|
52
|
+
preamble (paths, config, profile, persona, athlete profile).
|
|
53
|
+
|
|
54
|
+
**Optional steps this skill declares:** MONITORING
|
|
55
|
+
|
|
56
|
+
Do not proceed past a stop condition defined there.
|
|
57
|
+
|
|
58
|
+
### Phase 1 — Detect _(all modes except RE-CURATE)_
|
|
59
|
+
|
|
60
|
+
For each ACTIVE concern in the registry, find the most recent observation
|
|
61
|
+
date among its records (or its generated log view) and compute
|
|
62
|
+
`days_since = today − last_date`.
|
|
63
|
+
|
|
64
|
+
Mark a concern **due** when EITHER `days_since ≥ cadence_days`, OR the skill
|
|
65
|
+
is in STANDALONE mode.
|
|
66
|
+
|
|
67
|
+
Announce one line per concern:
|
|
68
|
+
`{name}: last logged {date} ({N}d ago) — {DUE | current}`.
|
|
69
|
+
|
|
70
|
+
If no concern is active or due, CONTRIBUTION MODE returns empty arrays to the
|
|
71
|
+
caller (see below); STANDALONE MODE exits cleanly as a no-op.
|
|
72
|
+
|
|
73
|
+
### Phase 2 — Gather _(skipped in RE-CURATE; one question at a time)_
|
|
74
|
+
|
|
75
|
+
For each **due** concern (STANDALONE: all active), ask `concern.prompt`.
|
|
76
|
+
Capture structured values for `concern.fields`, using the log view's legend
|
|
77
|
+
as the soft vocabulary.
|
|
78
|
+
|
|
79
|
+
Branches:
|
|
80
|
+
- **Nothing to report** and `record_negatives: true` → record a negative
|
|
81
|
+
observation: date = today, status/note = "checked — asymptomatic".
|
|
82
|
+
- **Notable flare** → capture the full row; fold extra detail into the note.
|
|
83
|
+
|
|
84
|
+
**Ask one question at a time. Wait for each answer before asking the next.**
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### Contribution Mode
|
|
89
|
+
|
|
90
|
+
Used by `consult` and `adapt-plan` inside their Phase 3. After Phase 2
|
|
91
|
+
gathering, convert every captured observation into typed items and **return
|
|
92
|
+
them to the caller** — nothing else. This mode never previews, never
|
|
93
|
+
applies, and never writes any file. Return two arrays:
|
|
94
|
+
|
|
95
|
+
1. **Current state — one per due concern/signal pair** (`state_changes`):
|
|
96
|
+
- `entity_type`: `"monitoring"`
|
|
97
|
+
- `key_components`: `{ "concern_id": "<registry id>", "signal": "<field>" }`
|
|
98
|
+
— the pack derives the canonical key `monitoring:<concern-id>:<signal>`
|
|
99
|
+
- `effective_at`: the observation date
|
|
100
|
+
- `statement`: concise current-status sentence
|
|
101
|
+
- `details`: `{ concernId, signal, status, note }`
|
|
102
|
+
|
|
103
|
+
2. **Observation history — one per captured observation** (`events`):
|
|
104
|
+
- `entity_type`: `"monitoring-event"`
|
|
105
|
+
- `effective_at`: the observation's effective time
|
|
106
|
+
- `statement`: what was observed
|
|
107
|
+
- `action_targets`: `[]`
|
|
108
|
+
- `details`: `{ concernId, signal, status?, note?, source, observedAt }`
|
|
109
|
+
where `source` is the caller tag (e.g. `consult:2026-06-17`,
|
|
110
|
+
`adapt:build-1-w3-thu`) and `observedAt` the effective time
|
|
111
|
+
|
|
112
|
+
These are **append-only monitoring events**: they never replace or supersede
|
|
113
|
+
anything. Only the keyed state item participates in supersession.
|
|
114
|
+
|
|
115
|
+
The parent merges both arrays into ITS OWN `StructuredChangeSet` BEFORE its
|
|
116
|
+
Phase 4 preview, so ONE plan hash and ONE approval cover the prescription
|
|
117
|
+
change, the coaching event, and all due monitoring changes together. If no
|
|
118
|
+
concern is active or due, return EMPTY arrays — the parent merges them and
|
|
119
|
+
continues with a single preview; no second preview is ever produced.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### Standalone Mode
|
|
124
|
+
|
|
125
|
+
#### Phase 3 — Preview
|
|
126
|
+
|
|
127
|
+
Assemble the gathered items into one `StructuredChangeSet` using exactly the
|
|
128
|
+
shapes documented under Contribution Mode (same `entity_type`, key
|
|
129
|
+
components, statement, and details contracts). Then call
|
|
130
|
+
`engram_capture_preview` with it.
|
|
131
|
+
|
|
132
|
+
If the preview returns blocked, STOP: Phase 4 cannot proceed until the input
|
|
133
|
+
is corrected and a preview succeeds.
|
|
134
|
+
|
|
135
|
+
#### Phase 4 — Approval _(requires explicit approval)_
|
|
136
|
+
|
|
137
|
+
Present TOGETHER, in one message:
|
|
138
|
+
|
|
139
|
+
1. What was captured — per concern: the observation(s) and the resulting
|
|
140
|
+
current status.
|
|
141
|
+
2. The record plan from the preview: which monitoring states will be created
|
|
142
|
+
or superseded, which events will append.
|
|
143
|
+
3. The generated compatibility view paths that will regenerate (the concern
|
|
144
|
+
logs and the Doctor-Prep Summary).
|
|
145
|
+
4. The exact `plan_hash` from the preview result.
|
|
146
|
+
|
|
147
|
+
Ask for approval. Approval must explicitly cover BOTH the recorded
|
|
148
|
+
observations AND the record/artifact plan identified by that exact
|
|
149
|
+
`plan_hash`.
|
|
150
|
+
|
|
151
|
+
Wait for explicit approval, rejection, or modification. On modification,
|
|
152
|
+
rebuild the change set, re-run `engram_capture_preview`, and present the new
|
|
153
|
+
hash.
|
|
154
|
+
|
|
155
|
+
#### Phase 5 — Apply _(with approved hash)_
|
|
156
|
+
|
|
157
|
+
Call `engram_capture_apply` with ONLY the exact approved `plan_hash`. Never
|
|
158
|
+
edit any file directly — the apply pipeline commits the records, refreshes
|
|
159
|
+
the guarded index, and regenerates every monitoring log view and the
|
|
160
|
+
Doctor-Prep Summary.
|
|
161
|
+
|
|
162
|
+
Outcome handling:
|
|
163
|
+
|
|
164
|
+
- **stale**: the records changed since preview. Return to Phase 3:
|
|
165
|
+
re-run `engram_capture_preview`, present the fresh plan and new
|
|
166
|
+
`plan_hash`, and obtain fresh approval before applying again.
|
|
167
|
+
- **apply failure**: stop. No view is written and none may be edited by
|
|
168
|
+
hand; diagnose and retry through the tools.
|
|
169
|
+
- **committed with stale views**: the records ARE authoritative. Re-calling
|
|
170
|
+
`engram_capture_apply` with the SAME committed `plan_hash` in the same
|
|
171
|
+
session reruns ONLY materialization — it never re-approves or re-applies
|
|
172
|
+
record mutations.
|
|
173
|
+
- **committed clean**: report the applied record IDs and regenerated paths.
|
|
174
|
+
|
|
175
|
+
#### Escalation scan _(both contribution and standalone, after capture)_
|
|
176
|
+
|
|
177
|
+
Evaluate each declared trigger in `escalation_triggers` generically against
|
|
178
|
+
the concern's recent observations: trend triggers flag when a numeric field
|
|
179
|
+
moves adversely across recent points (fewer than three parseable points → no
|
|
180
|
+
flag, never a false alarm); boolean/observed triggers flag when any recent
|
|
181
|
+
observation reports the condition. Surface any MET trigger prominently:
|
|
182
|
+
`⚠ {concern}: {trigger} — consider clinical evaluation.` The scan informs
|
|
183
|
+
the announcement only; the Doctor-Prep Summary itself is rendered
|
|
184
|
+
deterministically from the committed records.
|
|
185
|
+
|
|
186
|
+
### RE-CURATE
|
|
187
|
+
|
|
188
|
+
Read-only on records. There is nothing to hand-edit: views regenerate from
|
|
189
|
+
records on every apply. If views are stale (e.g. a prior apply reported
|
|
190
|
+
stale artifacts), re-run `engram_capture_apply` with that session's last
|
|
191
|
+
committed `plan_hash` — materialization retries idempotently. Never rewrite
|
|
192
|
+
a log or summary by hand.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Key Constraints
|
|
197
|
+
|
|
198
|
+
| Rule | Detail |
|
|
199
|
+
|------|--------|
|
|
200
|
+
| Generic skill | No concern-specific knowledge here; everything is driven by `concerns.yaml` |
|
|
201
|
+
| No-op safety | Absent/empty registry or nothing due → clean no-op; never blocks a calling skill |
|
|
202
|
+
| Contribution mode returns, never writes | Typed `state_changes`/`events` go back to the caller; no preview, no apply, no file writes |
|
|
203
|
+
| One approval | Parent-skill contributions merge into the parent's SINGLE change set — one preview, one `plan_hash` |
|
|
204
|
+
| Keyed state + append-only events | Due signals use `monitoring:<concern-id>:<signal>` for current state plus distinct append-only monitoring events carrying source and effective time |
|
|
205
|
+
| Generated views | Monitoring logs and Doctor-Prep Summaries are regenerated compatibility views; never edited directly |
|
|
206
|
+
| Record negatives | When `record_negatives: true`, "checked — asymptomatic" observations are logged (clinically meaningful) |
|
|
207
|
+
| One question at a time | Phase 2 never batches questions |
|
|
208
|
+
| Stale apply | Always returns to preview for a fresh hash and fresh approval |
|