paicer 0.1.0__tar.gz
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.
- paicer-0.1.0/.claude/commands/paicer/create-plan.md +53 -0
- paicer-0.1.0/.claude/commands/paicer/review-progress.md +58 -0
- paicer-0.1.0/.claude/skills/plan-authoring.md +177 -0
- paicer-0.1.0/.env.example +18 -0
- paicer-0.1.0/.github/workflows/publish.yml +37 -0
- paicer-0.1.0/.gitignore +38 -0
- paicer-0.1.0/.python-version +1 -0
- paicer-0.1.0/CHANGELOG.md +58 -0
- paicer-0.1.0/CLAUDE.md +42 -0
- paicer-0.1.0/LICENSE +21 -0
- paicer-0.1.0/Makefile +52 -0
- paicer-0.1.0/PKG-INFO +56 -0
- paicer-0.1.0/README.md +43 -0
- paicer-0.1.0/docs/garmin-api.md +150 -0
- paicer-0.1.0/docs/rgactive_16_week_triathlon_training plan.pdf +0 -0
- paicer-0.1.0/docs/superpowers/specs/2026-05-24-pypi-packaging-design.md +136 -0
- paicer-0.1.0/examples/hm-tri-combo.yaml +3306 -0
- paicer-0.1.0/examples/reference-imperial.yaml +291 -0
- paicer-0.1.0/examples/reference-metric.yaml +288 -0
- paicer-0.1.0/pyproject.toml +29 -0
- paicer-0.1.0/src/paicer/__init__.py +6 -0
- paicer-0.1.0/src/paicer/cli.py +70 -0
- paicer-0.1.0/src/paicer/config.py +52 -0
- paicer-0.1.0/src/paicer/formatters/__init__.py +1 -0
- paicer-0.1.0/src/paicer/formatters/base.py +16 -0
- paicer-0.1.0/src/paicer/formatters/html.py +298 -0
- paicer-0.1.0/src/paicer/formatters/markdown.py +162 -0
- paicer-0.1.0/src/paicer/integrations/__init__.py +1 -0
- paicer-0.1.0/src/paicer/integrations/base.py +41 -0
- paicer-0.1.0/src/paicer/integrations/garmin.py +277 -0
- paicer-0.1.0/src/paicer/plan_utils.py +198 -0
- paicer-0.1.0/src/paicer/render.py +18 -0
- paicer-0.1.0/src/paicer/review_data.py +299 -0
- paicer-0.1.0/src/paicer/sync.py +133 -0
- paicer-0.1.0/tests/__init__.py +0 -0
- paicer-0.1.0/tests/test_cli.py +90 -0
- paicer-0.1.0/tests/test_config.py +50 -0
- paicer-0.1.0/tests/test_package.py +3 -0
- paicer-0.1.0/uv.lock +652 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Create or Edit Training Plan
|
|
2
|
+
|
|
3
|
+
Help the user create a new training plan or modify an existing one.
|
|
4
|
+
|
|
5
|
+
**Invoke the `plan-authoring` skill** for YAML structure, unit conventions, Garmin patterns, and periodization principles.
|
|
6
|
+
|
|
7
|
+
## First-Time Setup
|
|
8
|
+
|
|
9
|
+
No setup file needed — paicer saves config to `~/.paicer/config` automatically on first run.
|
|
10
|
+
|
|
11
|
+
## Creating a New Plan
|
|
12
|
+
|
|
13
|
+
Interview the user **one question at a time**. Wait for each answer before asking the next.
|
|
14
|
+
|
|
15
|
+
1. What are you training for? (race distance, goal date, first time?)
|
|
16
|
+
2. Current fitness? (recent volume, longest recent run/ride, recent races?)
|
|
17
|
+
3. How many days per week, and which days?
|
|
18
|
+
4. What sports? (running only, triathlon, cycling?)
|
|
19
|
+
5. Equipment? (Garmin watch model, power meter, pool access?)
|
|
20
|
+
6. Current easy pace? (Adapt to their sport. Calculate race paces from any race results — don't ask them to do the math.)
|
|
21
|
+
|
|
22
|
+
If they have a Garmin watch: tell them to run `paicer sync w1` after the plan is ready — it will prompt for credentials on first use. Do NOT ask for credentials directly.
|
|
23
|
+
|
|
24
|
+
## Plan Length and Start Date
|
|
25
|
+
|
|
26
|
+
Calculate weeks until race day, then recommend:
|
|
27
|
+
|
|
28
|
+
- Standard lengths: 8, 10, 12, 16, 20 weeks (pick longest that fits)
|
|
29
|
+
- Minimum: 8 weeks for 5K/10K, 12 for half marathon, 16 for marathon/triathlon
|
|
30
|
+
- `start_date` should be a Monday, counting back from race day
|
|
31
|
+
- More time than needed? Start later, don't pad.
|
|
32
|
+
|
|
33
|
+
Present: "You have N weeks until race day. I'd recommend an X-week plan starting [date]." Always confirm with the user.
|
|
34
|
+
|
|
35
|
+
## Building the Plan
|
|
36
|
+
|
|
37
|
+
1. Read the appropriate reference plan: `examples/reference-metric.yaml` or `examples/reference-imperial.yaml`
|
|
38
|
+
2. Create plan file in `plans/`
|
|
39
|
+
3. Design phase structure (Base -> Build -> Peak -> Taper)
|
|
40
|
+
4. Build week-by-week with progressive volume
|
|
41
|
+
5. Add Garmin structures with YAML comments in user's unit system
|
|
42
|
+
6. Create YAML anchors for reusable sessions (swim, track)
|
|
43
|
+
7. Preview: `paicer render --plan plans/new-plan.yaml` (saves plan path to config, fails loudly if YAML is invalid)
|
|
44
|
+
8. Offer first week sync: `paicer sync w1`
|
|
45
|
+
11. If Garmin set up: suggest `/paicer:review-progress` after first week of training
|
|
46
|
+
|
|
47
|
+
## Modifying an Existing Plan
|
|
48
|
+
|
|
49
|
+
1. Read plan path from `~/.paicer/config` (key: `plan`)
|
|
50
|
+
2. Back up: `cp plans/my-plan.yaml plans/my-plan.backup.yaml`
|
|
51
|
+
3. Make edits, preserving sequential numbering and naming conventions
|
|
52
|
+
4. Preview: `paicer render` to confirm the YAML is valid
|
|
53
|
+
5. If Garmin workouts changed, remind user to re-sync affected weeks
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Training Plan Weekly Review
|
|
2
|
+
|
|
3
|
+
Compare last week's Garmin activities against the plan and discuss adjustments.
|
|
4
|
+
|
|
5
|
+
**Invoke the `plan-authoring` skill** for unit conventions and pace conversion reference.
|
|
6
|
+
|
|
7
|
+
## Steps
|
|
8
|
+
|
|
9
|
+
Read `units` from `~/.paicer/config` (default: `metric`). Present all values in the user's preferred system.
|
|
10
|
+
|
|
11
|
+
1. Read `plan` path from `~/.paicer/config`, then read the plan YAML using Read tool (do NOT write scripts to parse YAML).
|
|
12
|
+
2. Pull review data:
|
|
13
|
+
```
|
|
14
|
+
uv run python -m paicer.review_data <plan_path> # most recently completed week
|
|
15
|
+
uv run python -m paicer.review_data <plan_path> 3 # specific week number
|
|
16
|
+
```
|
|
17
|
+
3. Match activities by `activityName` against `W{week_num}: {name}` (prefixed format from Garmin upload). Do NOT match by date — users often shift days.
|
|
18
|
+
4. Analyze using the `intervals` array — NOT overall activity averages. Each interval has `type` (INTERVAL_WARMUP, INTERVAL_ACTIVE, INTERVAL_RECOVERY, INTERVAL_COOLDOWN), `paceSecPerKm`, `averageHR`, `averagePower`, `distance`, `duration`.
|
|
19
|
+
- **Structured workouts (tempo, intervals):** Compare INTERVAL_ACTIVE entries against targets. Overall average is misleading (includes warmup/cooldown).
|
|
20
|
+
- **Easy runs:** May only have INTERVAL_ACTIVE or no intervals. Use overall average.
|
|
21
|
+
- **Elevation context:** Check `elevationGain`/`elevationLoss` on every activity. Hilly runs raise HR at the same effort — don't flag elevated HR without accounting for elevation. Mention gain when it's notable (>5 m/km).
|
|
22
|
+
- **Running with pace targets:** compare each INTERVAL_ACTIVE pace vs planned, note HR
|
|
23
|
+
- **Running with HR targets:** compare INTERVAL_ACTIVE HR vs target zone
|
|
24
|
+
- **Cycling with power targets:** compare INTERVAL_ACTIVE power vs target zone
|
|
25
|
+
- **Swimming:** completion check (did the session happen?)
|
|
26
|
+
- **Distance:** actual vs planned
|
|
27
|
+
- **HR time in zones** (`hrTimeInZones`): Use to verify easy runs stayed in Zone 1–2. If zone 3+ time exceeds ~10% of duration on an easy run, flag it (accounting for elevation). For tempo/interval workouts, zone distribution confirms effort matched intent.
|
|
28
|
+
- **Aerobic training effect** (`aerobicTrainingEffect`): 1–5 scale. Easy runs should be 2.0–3.0 ("maintaining"). Tempo/intervals 3.0–4.0 ("improving"). Long runs 3.0–4.5. Flag if an easy run scores >3.5 (too hard) or a key session scores <2.5 (too easy). Useful as a weekly load summary — sum or average across sessions to gauge overall training stress.
|
|
29
|
+
- **Training status** (`trainingStatus`): Included at top level of review data. Report:
|
|
30
|
+
- **Acute-to-chronic ratio**: optimal 0.8–1.5. Below 0.8 = detraining. Above 1.5 = overreaching risk. If above 1.3, note it as something to watch.
|
|
31
|
+
- **Load balance feedback**: Garmin's own assessment (e.g., ABOVE_TARGETS, WITHIN_TARGETS). If above targets, discuss whether next week should be lighter.
|
|
32
|
+
- **VO2max trend**: note if it changed from previous review.
|
|
33
|
+
- **Training status phrase**: e.g., PRODUCTIVE, MAINTAINING, OVERREACHING. Flag non-productive states.
|
|
34
|
+
5. For unmatched workouts: check for other activities that might be the same workout done under a different name. Ask user to confirm before using.
|
|
35
|
+
6. Flag mismatches: HR too high/low at target pace, missed workouts, distance deviations.
|
|
36
|
+
7. Present findings conversationally. Discuss adjustments.
|
|
37
|
+
8. If pace adjustments agreed, update `targetValueOne`/`targetValueTwo` and descriptions in YAML.
|
|
38
|
+
9. Add review entry:
|
|
39
|
+
```yaml
|
|
40
|
+
reviews:
|
|
41
|
+
- week: N
|
|
42
|
+
date: "YYYY-MM-DD"
|
|
43
|
+
notes: "Summary"
|
|
44
|
+
adjustments:
|
|
45
|
+
- "Description of each change"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Notes content:** stick to training-relevant facts — pace, HR, power, distance, elevation, completion vs plan, perceived effort, weather if it affected execution, illness/injury that affected sessions. Allergies are fine to mention if they affected training. **Skip lifestyle context** like alcohol consumption, social events, work stress, or other personal details that are not training data — even when the user mentions them in chat. The plan log is a training record, not a journal.
|
|
49
|
+
|
|
50
|
+
10. Run `paicer render` to confirm the YAML is valid after edits.
|
|
51
|
+
|
|
52
|
+
## Race Week (special handling)
|
|
53
|
+
|
|
54
|
+
When the upcoming week contains a race, the standard review flow still applies — but **race-week conversations must lead with the HR ceiling rule, not with fueling/kit/course details.** See the "Race Strategy and Execution Priorities" section of the `plan-authoring` skill for the priority order.
|
|
55
|
+
|
|
56
|
+
The single highest-leverage piece of race-day advice is: *"Stay below the HR ceiling until the release km. Then push."* If that gets buried under gel timing, breakfast composition, and kit selection conversations, the user loses the race in execution even when training is fit. Make it the headline of every race-week message.
|
|
57
|
+
|
|
58
|
+
If the race workout has a `race_strategy:` field, surface its `one_liner` prominently in every race-week conversation.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-authoring
|
|
3
|
+
description: Use when creating, editing, or reviewing training plan YAML - covers structure rules, unit conventions, Garmin patterns, workout types, and periodization principles
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Plan Authoring
|
|
7
|
+
|
|
8
|
+
Reference for writing correct training plan YAML. Used by `/paicer:create-plan`, `/paicer:review-progress`, and ad-hoc plan edits.
|
|
9
|
+
|
|
10
|
+
## Unit System
|
|
11
|
+
|
|
12
|
+
Read `UNITS` from `.env` (default: `metric`). Use for all text fields (`name`, `description`) and YAML comments on Garmin values.
|
|
13
|
+
|
|
14
|
+
Garmin steps always use metric (meters, sec/km). Add comments in the user's system: `endConditionValue: 6437 # 4 mi`.
|
|
15
|
+
|
|
16
|
+
**Imperial conventions** — use clean round numbers, not conversions:
|
|
17
|
+
- Runs: 3, 4, 5, 6, 8, 10, 13, 16, 20 miles
|
|
18
|
+
- Bikes: 10, 15, 20, 25, 40 miles
|
|
19
|
+
- Paces: round to nearest :15 (7:30, 7:45, 8:00/mi)
|
|
20
|
+
- Swim: yards for US pools (200, 500, 1000 yds)
|
|
21
|
+
- Track: stays in meters (400m tracks are universal)
|
|
22
|
+
|
|
23
|
+
## YAML Structure Rules
|
|
24
|
+
|
|
25
|
+
- Single `start_date` — all dates calculated from it
|
|
26
|
+
- Day numbers = 1-based positions in `training_days`, not weekday names
|
|
27
|
+
- Days must be sequential within a week (1, 2, 3... no gaps except same-day pairs)
|
|
28
|
+
- Non-optional workouts must not exceed `training_days` slots
|
|
29
|
+
- Week/day numbers sequential within their parent
|
|
30
|
+
- `name`: descriptive with distance/workout info (e.g., "Easy 8km", "Tempo 3x8min"). Week prefix added at Garmin sync time.
|
|
31
|
+
|
|
32
|
+
## Workout Types
|
|
33
|
+
|
|
34
|
+
| Type | Garmin Sport | Notes |
|
|
35
|
+
|------|-------------|-------|
|
|
36
|
+
| `run` | running (1) | HR zone for easy, pace targets for tempo/intervals |
|
|
37
|
+
| `track` | running (1) | Reusable via YAML anchors |
|
|
38
|
+
| `bike` | cycling (2) | See cycling target rules below |
|
|
39
|
+
| `swim` | swimming (4) | Lap-button cue cards with `description` per step |
|
|
40
|
+
| `multisport` | multi_sport (10) | `garmin.legs`, each with `sport` + `steps` |
|
|
41
|
+
| `race` | — | Race day entry, typically `skip_garmin: true` |
|
|
42
|
+
|
|
43
|
+
## Flags
|
|
44
|
+
|
|
45
|
+
- **`optional: true`** — shows as "Optional:" in docs, doesn't count against training_days. If it has a `garmin:` section, uploads to library without scheduling. Doesn't override `skip_garmin`.
|
|
46
|
+
- **`skip_garmin: true`** — no Garmin upload at all.
|
|
47
|
+
|
|
48
|
+
## Cycling Target Rules
|
|
49
|
+
|
|
50
|
+
Garmin evaluates power zone targets against 3-second average power. On undulating outdoor terrain, this causes constant out-of-zone alerts regardless of actual effort — and the visual deviation banners obscure the data screens you actually want to see. The Garmin Connect API does not support configuring a longer averaging window.
|
|
51
|
+
|
|
52
|
+
Power is still the right measurement for hard cycling intervals when a power meter is present. The fix is to keep the structured workout shape but stop letting Garmin enforce target zones on the bike. The user paces by feel + lap-average power on the data screen, and gets clean post-ride power data for analysis.
|
|
53
|
+
|
|
54
|
+
**Use `heart.rate.zone` for:**
|
|
55
|
+
- All steady-state / endurance cycling (single-interval rides at zone 2–3)
|
|
56
|
+
- Warmup and cooldown steps in steady rides
|
|
57
|
+
- Brick workout bike legs that are steady-state at Z2/Z3
|
|
58
|
+
|
|
59
|
+
**Use `no.target` with `description` for:**
|
|
60
|
+
- Any step that would otherwise have a `power.zone` target (threshold, VO2, surge intervals, hard brick blocks)
|
|
61
|
+
- Warmup/cooldown of structured power workouts (so the entire workout is banner-free, not just the work intervals)
|
|
62
|
+
|
|
63
|
+
**Description format (Fenix/Edge display fits ~30–40 chars cleanly):**
|
|
64
|
+
```
|
|
65
|
+
"<duration> @ Z<n> (RPE <n>)"
|
|
66
|
+
```
|
|
67
|
+
Examples: `"5 km @ Z2 (RPE 5)"`, `"6 min @ Z3 (RPE 6)"`, `"1 min @ Z5 (RPE 9)"`.
|
|
68
|
+
|
|
69
|
+
Don't include explicit watt numbers — FTP changes over time and the zone label remains correct as long as zones are kept current. The user reads the description, glances at lap power, paces accordingly. Recorded power data still supports post-ride analysis; what's lost is real-time zone enforcement (which was never reliable outdoors anyway).
|
|
70
|
+
|
|
71
|
+
**Why HR works for steady cycling:** HR naturally smooths terrain-induced fluctuations. On a hilly loop, power spikes uphill and drops downhill, but HR stays in zone if effort is consistent. Same logic as running easy runs with HR targets. HR-targeted bike steps don't trigger banner spam because heart rate physiologically lags terrain.
|
|
72
|
+
|
|
73
|
+
**Roadmap:** for users without a power meter, the right pattern is to use `heart.rate.zone` targets across all bike steps including hard intervals. Plan generation should detect power-meter availability and pick the appropriate target type. Not yet implemented — current plans assume a power meter for the bike.
|
|
74
|
+
|
|
75
|
+
## Garmin Step Patterns
|
|
76
|
+
|
|
77
|
+
Read `examples/reference-metric.yaml` (or `reference-imperial.yaml`) for working examples of every pattern. Read `docs/garmin-api.md` for complete API reference.
|
|
78
|
+
|
|
79
|
+
**Common patterns:**
|
|
80
|
+
- Easy run: single `interval` step + `heart.rate.zone` zone 2
|
|
81
|
+
- Steady bike: single `interval` step + `heart.rate.zone` zone 2–3
|
|
82
|
+
- Bike intervals: `warmup` (HR zone) + `repeat` group (HR recovery + power work) + `cooldown` (HR zone)
|
|
83
|
+
- Tempo: `warmup` + `repeat` group (work + recovery) + `cooldown`
|
|
84
|
+
- Swim: `lap.button` + `description` per step, `rest` steps between sections
|
|
85
|
+
- Multisport: `garmin.legs` array, each leg has `sport` + `steps`
|
|
86
|
+
- Reusable sessions: YAML anchors in `swim_sessions:` / `track_sessions:` blocks
|
|
87
|
+
|
|
88
|
+
## Periodization Principles
|
|
89
|
+
|
|
90
|
+
- **Progressive overload:** +5-10% volume/week, recovery week every 3-4 weeks
|
|
91
|
+
- **Polarized intensity:** ~80% easy (RPE 4-5), ~20% hard (RPE 7-9), minimal grey zone
|
|
92
|
+
- **Specificity:** Training mirrors race demands as plan progresses
|
|
93
|
+
- **Taper:** 2-3 weeks before race, -30-50% volume, maintain intensity
|
|
94
|
+
- **Rest sequencing:** Rest day after long/hard sessions. Easy before hard, rest after hard/long.
|
|
95
|
+
- **Phase structure:** Base (aerobic) -> Build (race-specific) -> Peak (sharpening) -> Taper
|
|
96
|
+
|
|
97
|
+
## Race Strategy and Execution Priorities
|
|
98
|
+
|
|
99
|
+
**Race outcome is determined more by execution discipline than by training. Race-day decisions are not equal weight.** When advising on race week, lead with the single rule that decides 80% of the outcome: **HR ceiling discipline**.
|
|
100
|
+
|
|
101
|
+
### Priority order (by impact on finishing time)
|
|
102
|
+
|
|
103
|
+
1. **HR ceiling discipline** (saves or costs 5–15 min) — set a hard cap below LTHR, hold it religiously until the release km, push only in the final stretch
|
|
104
|
+
2. **Pacing strategy first 5 km** (saves or costs 3–8 min — tied to #1) — let people pass you, ignore corral pressure, run by HR not by feel
|
|
105
|
+
3. **Fueling** (saves or costs 2–5 min in late race) — gel timing aligned with aid stations, tested in training
|
|
106
|
+
4. **Kit / chafe management** (saves or costs 1–3 min from comfort) — singlet, socks, shorts all tested
|
|
107
|
+
5. **Hydration** (saves or costs 1–2 min) — sip at every aid station from km 8+, pour on head if warm
|
|
108
|
+
6. **Carb load** (saves or costs 1–2 min) — single solid carb-load day before race for HM, longer for marathon
|
|
109
|
+
7. **Sleep** (background factor) — bank sleep Wed/Thu; Friday night sleep matters less than people think
|
|
110
|
+
8. **Course strategy details** (saves or costs <1 min in good conditions) — useful color, not the main lever
|
|
111
|
+
|
|
112
|
+
### HR ceiling rule (the headline)
|
|
113
|
+
|
|
114
|
+
- **HM:** HR cap ≈ LTHR − 9 to −12 bpm. Hold until km 16 (last 5 km). Then lift cap, push by feel.
|
|
115
|
+
- **Marathon:** HR cap ≈ LTHR − 16 to −20 bpm. Hold until km 32 (last 10 km). Lift cap, but stay below LTHR until last 5 km.
|
|
116
|
+
- **10K:** HR cap ≈ LTHR − 3 to −5 bpm. Hold until km 7, push.
|
|
117
|
+
- **5K:** HR cap doesn't really apply — run by feel.
|
|
118
|
+
|
|
119
|
+
Race-day HR for the same pace typically runs 5–8 bpm higher than training HR. Plan for this. The training-day "5:00/km at HR 168" becomes race-day "5:00/km at HR 173–176."
|
|
120
|
+
|
|
121
|
+
**Time-to-failure at intensities near threshold:**
|
|
122
|
+
- At LTHR: ~60 minutes sustainable
|
|
123
|
+
- LTHR + 5 bpm: ~30 minutes
|
|
124
|
+
- LTHR + 10 bpm: ~10 minutes
|
|
125
|
+
|
|
126
|
+
This is why HM at threshold = bonk-by-km-15. Run 5+ bpm below threshold and time-to-failure extends to 3+ hours.
|
|
127
|
+
|
|
128
|
+
### `race_strategy` YAML field
|
|
129
|
+
|
|
130
|
+
For any `race` type workout, include a `race_strategy:` block. Renderers display this prominently for race week:
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
- day: 6
|
|
134
|
+
type: "race"
|
|
135
|
+
name: "RACE: Brooklyn Half Marathon"
|
|
136
|
+
skip_garmin: true
|
|
137
|
+
description: "Race description, course notes, etc."
|
|
138
|
+
race_strategy:
|
|
139
|
+
hr_cap: 165
|
|
140
|
+
cap_release_km: 16
|
|
141
|
+
one_liner: "Stay below HR 165 until km 16. Then push."
|
|
142
|
+
notes: |
|
|
143
|
+
Hilly first 5 km (Prospect Park). Don't chase corral pace.
|
|
144
|
+
Race-day HR runs 5-8 bpm above training HR — recalibrate in moment.
|
|
145
|
+
Fueling: 2 SiS gels at aid stations after km 5 and km 14.
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Required fields:**
|
|
149
|
+
- `hr_cap` (int): the HR ceiling for the body of the race
|
|
150
|
+
- `cap_release_km` (int): km marker where the ceiling lifts
|
|
151
|
+
- `one_liner` (str): the one rule to remember on race day
|
|
152
|
+
|
|
153
|
+
**Optional fields:**
|
|
154
|
+
- `notes` (str): course-specific context (hills, weather, fueling reminders)
|
|
155
|
+
- `target_time` (str): for context, not for pacing — e.g., `"1:45"`
|
|
156
|
+
- `target_pace` (str): goal pace if HR cap allows — e.g., `"5:05/km"` (HR governs, not pace)
|
|
157
|
+
|
|
158
|
+
### What NOT to lead with in race-week conversations
|
|
159
|
+
|
|
160
|
+
These are real considerations but should never displace the HR ceiling rule:
|
|
161
|
+
- Gel brand/timing minutiae
|
|
162
|
+
- Carb load gram counts
|
|
163
|
+
- Breakfast composition
|
|
164
|
+
- Kit selection
|
|
165
|
+
- Course-guide course-by-course narrative
|
|
166
|
+
|
|
167
|
+
Cover them, but make the HR rule the headline of every race-week conversation.
|
|
168
|
+
|
|
169
|
+
## Pace Conversion
|
|
170
|
+
|
|
171
|
+
Garmin pace values are sec/km. Convert: `5:25/km = 325 sec/km`.
|
|
172
|
+
|
|
173
|
+
To min/mi: multiply sec/km by 1.60934. Example: 325 sec/km = 523 sec/mi = 8:43/mi.
|
|
174
|
+
|
|
175
|
+
## Validation
|
|
176
|
+
|
|
177
|
+
Always run `make test` after changes. It validates YAML syntax, Python, and plan structure (day ranges, training_days counts).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Unit system (metric or imperial). Also sets paper format (a4 or letter).
|
|
2
|
+
UNITS=metric
|
|
3
|
+
|
|
4
|
+
# Plan file (set after running /paicer:create-plan)
|
|
5
|
+
# PLAN=plans/my-plan.yaml
|
|
6
|
+
|
|
7
|
+
# Override paper format if your printer doesn't match your unit system.
|
|
8
|
+
# FORMAT=letter
|
|
9
|
+
|
|
10
|
+
# Pool swim distance tracking:
|
|
11
|
+
# auto — watch measures distance via stroke detection (needs good form)
|
|
12
|
+
# drill — each segment is a drill; you enter distance after each lap button press
|
|
13
|
+
# SWIM_TRACKING=auto
|
|
14
|
+
|
|
15
|
+
# Workout integration (uncomment if using Garmin)
|
|
16
|
+
# WORKOUT_INTEGRATION=garmin
|
|
17
|
+
# GARMIN_EMAIL=your-email@example.com
|
|
18
|
+
# GARMIN_PASSWORD=your-password-here
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Verify tag matches pyproject.toml version
|
|
18
|
+
run: |
|
|
19
|
+
TAG="${{ github.event.release.tag_name }}"
|
|
20
|
+
VERSION=$(grep '^version' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
|
|
21
|
+
if [ "$TAG" != "$VERSION" ]; then
|
|
22
|
+
echo "Release tag '$TAG' does not match pyproject.toml version '$VERSION'"
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
|
|
30
|
+
- name: Install build tools
|
|
31
|
+
run: pip install hatchling build
|
|
32
|
+
|
|
33
|
+
- name: Build package
|
|
34
|
+
run: python -m build
|
|
35
|
+
|
|
36
|
+
- name: Publish to PyPI
|
|
37
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
paicer-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
|
|
8
|
+
# Virtual environments
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
ENV/
|
|
12
|
+
|
|
13
|
+
# Generated files
|
|
14
|
+
output/
|
|
15
|
+
|
|
16
|
+
# User plans (generated by /paicer:create-plan)
|
|
17
|
+
plans/
|
|
18
|
+
|
|
19
|
+
# Env files
|
|
20
|
+
.env
|
|
21
|
+
|
|
22
|
+
# Garmin tokens
|
|
23
|
+
.garmin_tokens
|
|
24
|
+
|
|
25
|
+
# yaks data directory
|
|
26
|
+
.yaks
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
*~
|
|
35
|
+
|
|
36
|
+
# OS
|
|
37
|
+
.DS_Store
|
|
38
|
+
Thumbs.db
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2026-03-15
|
|
4
|
+
|
|
5
|
+
- Add training status to review data (VO2max, load balance, acute-to-chronic ratio)
|
|
6
|
+
- Add HR time in zones and aerobic training effect to review data
|
|
7
|
+
- Add elevation gain/loss to review data and skill
|
|
8
|
+
- Update review skill to interpret all new metrics
|
|
9
|
+
- Fix inaccurate distance totals in tempo workout descriptions
|
|
10
|
+
- Smooth long run progression (12 → 14 → 15 → 17 → 16 → 18 → 19 → 18 → 20 → 19 → 16 → Race)
|
|
11
|
+
- Add strides to W4, W5, W8, W10, W11 (every non-race week now has strides)
|
|
12
|
+
- Add introductory comment to hm-tri-combo.yaml example
|
|
13
|
+
|
|
14
|
+
## 2026-03-14
|
|
15
|
+
|
|
16
|
+
- Fix advanced example plan (hm-tri-combo): remove duplicate workouts, correct step ordering
|
|
17
|
+
|
|
18
|
+
## 2026-03-12
|
|
19
|
+
|
|
20
|
+
- Fix plan formatting across all example plans (descriptions, date displays, en dashes)
|
|
21
|
+
|
|
22
|
+
## 2026-03-11
|
|
23
|
+
|
|
24
|
+
- Extract plan-authoring knowledge into shared skill (used by both create-plan and review-progress)
|
|
25
|
+
- Rename commands to `paicer/create-plan` and `paicer/review-progress`
|
|
26
|
+
- Fix hm-tri phase 1 training day assignments
|
|
27
|
+
|
|
28
|
+
## 2026-03-10
|
|
29
|
+
|
|
30
|
+
- Add imperial unit system support (pace in min/mile, paper format switches to letter)
|
|
31
|
+
- Add optional workout support (`skip_garmin: true` for strength/rest days)
|
|
32
|
+
- Add sport labels (emoji in HTML, text in Markdown) and plan validation
|
|
33
|
+
- Add imperial reference example plan
|
|
34
|
+
- Update README
|
|
35
|
+
|
|
36
|
+
## 2026-03-08
|
|
37
|
+
|
|
38
|
+
- Add coaching commands: `/paicer:create-plan` and `/paicer:review-progress`
|
|
39
|
+
- Add `review_data.py` for pulling Garmin activity data by plan week
|
|
40
|
+
- Add Garmin API reference docs
|
|
41
|
+
- Add CLAUDE.md project instructions
|
|
42
|
+
- Move plans to `examples/` directory
|
|
43
|
+
|
|
44
|
+
## 2026-03-04
|
|
45
|
+
|
|
46
|
+
- Add multisport (brick) workout support for Garmin
|
|
47
|
+
- Add track session support with reusable YAML anchors
|
|
48
|
+
|
|
49
|
+
## 2026-03-03
|
|
50
|
+
|
|
51
|
+
- Add cycling and swimming workout types
|
|
52
|
+
- Expand hm-tri-combo plan with full Phase 2 (swim/bike integration)
|
|
53
|
+
|
|
54
|
+
## 2026-02-22
|
|
55
|
+
|
|
56
|
+
- Initial release: YAML plan parser, Markdown/HTML renderers, Garmin workout sync
|
|
57
|
+
- Run-only support with tempo, interval, and easy run structures
|
|
58
|
+
- Scope filtering (phase, week, day)
|
paicer-0.1.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Paicer
|
|
2
|
+
|
|
3
|
+
Training plan tool: YAML plan → Garmin workouts + Markdown/HTML documents.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/
|
|
9
|
+
render_plan.py — YAML → Markdown/HTML (entry point)
|
|
10
|
+
generate_workouts.py — YAML → Garmin workouts with filtering
|
|
11
|
+
plan_utils.py — Date calculation, YAML loading, plan validation, sport maps
|
|
12
|
+
formatters/ — Base class + MarkdownFormatter + HTMLFormatter
|
|
13
|
+
integrations/ — Base class + GarminIntegration
|
|
14
|
+
examples/ — Example training plans
|
|
15
|
+
plans/ — User plans (gitignored, created by /paicer:create-plan)
|
|
16
|
+
output/ — Generated documents (gitignored)
|
|
17
|
+
docs/ — Garmin API reference, other docs
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Commands
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
make markdown # Generate Markdown
|
|
24
|
+
make html # Generate HTML (A4 for metric, letter for imperial)
|
|
25
|
+
make workouts SCOPE=w7 # Sync week 7 to Garmin
|
|
26
|
+
make workouts SCOPE=w7d2 # Sync week 7 day 2
|
|
27
|
+
make workouts SCOPE=p2 # Sync phase 2
|
|
28
|
+
make workouts SCOPE=all # Sync everything
|
|
29
|
+
make test # Validate YAML, Python, and plan structure
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Plan path is set in `.env` as `PLAN=plans/your-plan.yaml`.
|
|
33
|
+
|
|
34
|
+
Set `UNITS=metric` or `UNITS=imperial` in `.env` to control the unit system used when creating or editing plans. Garmin steps always use metric internally. Text fields (`name`, `description`) and YAML comments use the preferred system.
|
|
35
|
+
|
|
36
|
+
## Plan Authoring
|
|
37
|
+
|
|
38
|
+
Invoke the `plan-authoring` skill for YAML structure rules, workout types, Garmin patterns, unit conventions, and periodization principles.
|
|
39
|
+
|
|
40
|
+
Reference plans: `examples/reference-metric.yaml` and `examples/reference-imperial.yaml` demonstrate every pattern in a minimal 2-week plan.
|
|
41
|
+
|
|
42
|
+
Garmin API: `docs/garmin-api.md` for step types, end conditions, target types, pace conversions.
|
paicer-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tome Cvitan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
paicer-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
.PHONY: install test workouts markdown html all clean
|
|
2
|
+
|
|
3
|
+
-include .env
|
|
4
|
+
export
|
|
5
|
+
|
|
6
|
+
UNITS ?= metric
|
|
7
|
+
FORMAT ?= $(if $(filter imperial,$(UNITS)),letter,a4)
|
|
8
|
+
SCHEDULE ?= 1
|
|
9
|
+
|
|
10
|
+
define check_plan
|
|
11
|
+
@if [ -z "$(PLAN)" ]; then \
|
|
12
|
+
echo "No plan set. Set PLAN in .env or run /paicer:create-plan"; \
|
|
13
|
+
exit 1; \
|
|
14
|
+
fi
|
|
15
|
+
@if [ ! -f "$(PLAN)" ]; then \
|
|
16
|
+
echo "Plan file not found: $(PLAN)"; \
|
|
17
|
+
exit 1; \
|
|
18
|
+
fi
|
|
19
|
+
endef
|
|
20
|
+
|
|
21
|
+
install:
|
|
22
|
+
uv sync
|
|
23
|
+
|
|
24
|
+
test:
|
|
25
|
+
$(check_plan)
|
|
26
|
+
@echo "Running tests..."
|
|
27
|
+
@uv run pytest -v
|
|
28
|
+
@echo "Validating plan..."
|
|
29
|
+
@uv run paicer render --plan $(PLAN) > /dev/null
|
|
30
|
+
@echo "✅ Plan valid"
|
|
31
|
+
|
|
32
|
+
workouts:
|
|
33
|
+
$(check_plan)
|
|
34
|
+
@uv run paicer sync $(SCOPE) --plan $(PLAN) $(if $(filter 0,$(SCHEDULE)),--no-schedule)
|
|
35
|
+
|
|
36
|
+
markdown:
|
|
37
|
+
$(check_plan)
|
|
38
|
+
@mkdir -p output
|
|
39
|
+
@uv run paicer render --plan $(PLAN) > output/training_plan.md
|
|
40
|
+
@echo "Created output/training_plan.md"
|
|
41
|
+
|
|
42
|
+
html:
|
|
43
|
+
$(check_plan)
|
|
44
|
+
@mkdir -p output
|
|
45
|
+
@uv run paicer render --html --format=$(FORMAT) --plan $(PLAN) > output/training_plan.html
|
|
46
|
+
@echo "Created output/training_plan.html ($(FORMAT))"
|
|
47
|
+
|
|
48
|
+
all: markdown html
|
|
49
|
+
|
|
50
|
+
clean:
|
|
51
|
+
trash output/
|
|
52
|
+
trash __pycache__
|
paicer-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: paicer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Training plan tool: YAML to Garmin workouts and readable documents
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: click>=8.0
|
|
8
|
+
Requires-Dist: garminconnect<0.3.0,>=0.2.40
|
|
9
|
+
Requires-Dist: keyring>=24.0
|
|
10
|
+
Requires-Dist: markdown>=3.10.2
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# p**ai**cer
|
|
15
|
+
|
|
16
|
+
AI-powered training plan manager. Provide your race goals, schedule, and fitness level to create a plan, with structured workouts that can be synced to your Garmin watch. After each training week, run the progress review command to pull your Garmin activity and training status data, compare it against the plan, and adjust targets based on how your body is responding.
|
|
17
|
+
|
|
18
|
+
**Disclaimer:** This tool is not a substitute for professional coaching or medical advice. Always listen to your body and consult a qualified professional for health or injury concerns.
|
|
19
|
+
|
|
20
|
+
## Get Started
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
git clone https://github.com/cvitan/paicer && cd paicer
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Open the project in Claude Code and run `/paicer:create-plan` to create a YAML-based training plan through a guided conversation. It handles setup, configuration, and walks you through the process.
|
|
27
|
+
|
|
28
|
+
After each week of training, run `/paicer:review-progress` to review your plan progress and make any tweaks if needed. The review will also be appended to your plan for future reference.
|
|
29
|
+
|
|
30
|
+
### Plan output options
|
|
31
|
+
- **Markdown**
|
|
32
|
+
- **HTML** — set up to print 1 wk/page
|
|
33
|
+
- **Garmin** — sync scheduled structured workouts
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
make markdown # Generate Markdown
|
|
39
|
+
make html # Generate HTML (A4 for metric, letter for imperial)
|
|
40
|
+
make workouts SCOPE=w7 # Sync week 7 to Garmin
|
|
41
|
+
make workouts SCOPE=w7d2 # Sync specific workout
|
|
42
|
+
make workouts SCOPE=p2 # Sync entire phase
|
|
43
|
+
make test # Validate plan
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Supported Sports
|
|
47
|
+
|
|
48
|
+
Running, cycling, swimming (pool and open water), track sessions, and multisport/brick workouts (bike + run with transition tracking). Requires a Garmin watch — multisport needs a compatible model (Fenix, Forerunner 570/970, Enduro).
|
|
49
|
+
|
|
50
|
+
## Roadmap
|
|
51
|
+
|
|
52
|
+
1. **Strava activity enrichment**
|
|
53
|
+
2. **Zwift Integrations**
|
|
54
|
+
3. **Additional Formats** - PDF, iCal, JSON, CSV export
|
|
55
|
+
4. **HR-zone fallback for cycling** - generate bike workouts with `heart.rate.zone` targets for users without a power meter (current plans assume one)
|
|
56
|
+
5. **Ad-hoc activity data tool** - extend `src/review_data.py` or add `src/activity_data.py` with `--activity-id`, `--latest N`, `--from-date/--to-date` flags so single-activity / cross-week queries don't require throwaway scripts. Expose `get_activity_typed_splits` as the primary intervals fetch.
|
paicer-0.1.0/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# p**ai**cer
|
|
2
|
+
|
|
3
|
+
AI-powered training plan manager. Provide your race goals, schedule, and fitness level to create a plan, with structured workouts that can be synced to your Garmin watch. After each training week, run the progress review command to pull your Garmin activity and training status data, compare it against the plan, and adjust targets based on how your body is responding.
|
|
4
|
+
|
|
5
|
+
**Disclaimer:** This tool is not a substitute for professional coaching or medical advice. Always listen to your body and consult a qualified professional for health or injury concerns.
|
|
6
|
+
|
|
7
|
+
## Get Started
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/cvitan/paicer && cd paicer
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Open the project in Claude Code and run `/paicer:create-plan` to create a YAML-based training plan through a guided conversation. It handles setup, configuration, and walks you through the process.
|
|
14
|
+
|
|
15
|
+
After each week of training, run `/paicer:review-progress` to review your plan progress and make any tweaks if needed. The review will also be appended to your plan for future reference.
|
|
16
|
+
|
|
17
|
+
### Plan output options
|
|
18
|
+
- **Markdown**
|
|
19
|
+
- **HTML** — set up to print 1 wk/page
|
|
20
|
+
- **Garmin** — sync scheduled structured workouts
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
make markdown # Generate Markdown
|
|
26
|
+
make html # Generate HTML (A4 for metric, letter for imperial)
|
|
27
|
+
make workouts SCOPE=w7 # Sync week 7 to Garmin
|
|
28
|
+
make workouts SCOPE=w7d2 # Sync specific workout
|
|
29
|
+
make workouts SCOPE=p2 # Sync entire phase
|
|
30
|
+
make test # Validate plan
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Supported Sports
|
|
34
|
+
|
|
35
|
+
Running, cycling, swimming (pool and open water), track sessions, and multisport/brick workouts (bike + run with transition tracking). Requires a Garmin watch — multisport needs a compatible model (Fenix, Forerunner 570/970, Enduro).
|
|
36
|
+
|
|
37
|
+
## Roadmap
|
|
38
|
+
|
|
39
|
+
1. **Strava activity enrichment**
|
|
40
|
+
2. **Zwift Integrations**
|
|
41
|
+
3. **Additional Formats** - PDF, iCal, JSON, CSV export
|
|
42
|
+
4. **HR-zone fallback for cycling** - generate bike workouts with `heart.rate.zone` targets for users without a power meter (current plans assume one)
|
|
43
|
+
5. **Ad-hoc activity data tool** - extend `src/review_data.py` or add `src/activity_data.py` with `--activity-id`, `--latest N`, `--from-date/--to-date` flags so single-activity / cross-week queries don't require throwaway scripts. Expose `get_activity_typed_splits` as the primary intervals fetch.
|