Prepare and persist TODAY'S pre-workout / training-readiness brief — the daily "should I train today?" call. It reads the board's deterministic FORM SCORE (0–100, with its hrv / sleep / resting-HR / load breakdown), folds in last night's sleep + this morning's metrics + recent training load + the athlete profile + today's PLANNED session, then YOU author a short brief — readiness (ready / caution / rest), the recommended session (the plan, adjusted to recovery), the warnings, the green lights...
Scanned 9/2/2026
Install to Claude Code
npx -y skills add philipyaz/cos --skill fitness-pre-workout-brief --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Fitness Pre Workout Brief?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/philipyaz-fitness-pre-workout-brief)More formats (shields.io, HTML) on the badges page.
---
name: fitness-pre-workout-brief
description: >
Prepare and persist TODAY'S pre-workout / training-readiness brief — the daily
"should I train today?" call. It reads the board's deterministic FORM SCORE (0–100,
with its hrv / sleep / resting-HR / load breakdown), folds in last night's sleep +
this morning's metrics + recent training load + the athlete profile + today's PLANNED
session, then YOU author a short brief — readiness (ready / caution / rest), the
recommended session (the plan, adjusted to recovery), the warnings, the green lights,
and a one-liner — and `save_pre_workout_brief` it (upserted by today's date). Always
not-medical-advice framed. Use when the user says "should I train today", "am I ready
to train", "am I recovered", "pre-workout brief", "training brief", "what should I do
today", "what's on for today", "how's my readiness", or otherwise asks whether to
train, go easier, or rest. It does NOT make the weekly plan (fitness-training-plan
owns that) — it reads today's recovery and gives the go / hold-back call.
---
# Pre-workout brief (today's go / hold-back call)
This skill is the **intelligence** that turns *"should I train today?"* into a persisted
**pre-workout brief** on the board. It runs **only** through the **`fitness`** MCP — never
`bash`/`curl` (Cowork's sandbox blocks outbound HTTP; the tools exist for exactly this).
`/fitness/pre-workout-brief` is the **read** twin: a history feed (latest-by-default,
page-back) over the saved briefs; the human glances at it, **you** author and persist the
brief.
**The board is a state machine; YOU are the intelligence.** There is **no board-side LLM** —
the page's Generate action hands off to **you**, not to a server-side coach. The one number
you do **not** invent is the **form score**: the board **computes it deterministically**
(`get_form_score`) and you **read + interpret** it — you never recompute it. Everything else
(the readiness call, the session adjustment, the warnings, the green lights, the one-liner)
is **your** judgement, then you `save_pre_workout_brief` it.
> **Scope.** This skill is the **daily** brief only. The **weekly training plan**
> (`fitness-training-plan`), the **weekly review** (`fitness-weekly-review`), the
> **profile** (`fitness-athlete-profile`), and **correlations** (`fitness-correlations`)
> are their own focused skills — defer there for *"make me a plan for the week"*, *"how was
> my training this week"*, *"set my profile"*. Here you read today's recovery + the day's
> planned session and give the **go / easier / rest** call.
> **Gate — the add-on must be ENABLED.** The WRITE (`save_pre_workout_brief`) 404s ("Not
> found — the fitness add-on may be disabled.") when the Fitness add-on is disabled; the
> READS (`get_form_score`, `get_daily_summary`, `list_health_data`, `get_athlete_profile`,
> `list_coaching_artifacts`) always work. If the save comes back **404**, the add-on is off —
> tell the user to enable it from the board's **/addons** catalog (toggle on), then retry.
> You don't enable the add-on yourself.
> **NOT MEDICAL ADVICE — say it.** A brief is an **informational estimate, not medical
> advice.** A "go easy / rest" read on low HRV or poor sleep is a **conservative training
> default**, not clinical judgement. **Defer to a professional** (physician,
> physiotherapist, qualified coach) for any injury, pain, illness, chest pain or abnormal
> symptom, pregnancy, or a user under 18 — recommend they consult one and **don't** push hard
> training. Carry that framing in your own words.
---
## STEP 0 — Read the mode switch (always first)
Read `config/auto-sync.json` → `{ "autoSync": <bool> }` (default **ON / auto** if the file
or key is missing). State the mode once. A pre-workout brief is **one low-stakes write**
(`save_pre_workout_brief`, upserted by today's date — re-saving the same day overwrites, it
does not stack) — so **just do it in either mode**. The conversational check that
`fitness-coach` applies to bulk/destructive writes does not apply here; there's nothing bulk
about a single day's brief. **There is no pending/propose queue** — the save lands directly.
---
## STEP 1 — Make sure today's overnight data is ingested
The brief leans on **last night's sleep** and **this morning's HRV / resting HR** — that's
exactly the recovery signal. If the user just mentioned numbers that aren't on the board yet
(*"slept badly, HRV was 41"*), ingest them first via `fitness-health-data`
(`push_health_data`, canonical taxonomy) — a brief built on stale data is misleading. If
today's data is already in (the HAE shortcut usually posts it), proceed.
---
## STEP 1.5 — Close out yesterday (the daily reconciliation)
**Do this AFTER STEP 1's ingest, not before** — the close-out's proof reads today's
`db.healthEntries`, so reconciling before yesterday's workout is ingested means asking about a
session the watch already proved.
- `list_coaching_artifacts({ kind: "training_plan", limit: 1 })` → `get_coaching_artifact({ id })`
→ read **`reconciliation`** (its `unresolvedDays`). When today's brief targets a named other
day, still reconcile against **today**.
- Any `unresolvedDays.days[]` entry with **`provenDone: true`** → `set_plan_day_outcome(artifact_id,
date, "done")` **silently** — a same-date workout already proves it happened. One line in the
brief's report, no question asked.
- Any **remaining `unresolvedDays`** → fold **one** question into the brief's opening (e.g.
*"Yesterday's strength session — done, skipped, or move it?"*). Answers write through
`set_plan_day_outcome`. **Never guess — an unanswered day simply stays `planned`.**
- **Reorganise today (propose, never auto-move).** When an unresolved-then-answered *move*, or
today's own recovery read, argues for it, **propose** pulling the missed session into today
(or another day this week), or pushing today's session back. **Never relocate without an
explicit yes, in any mode** — this skill never auto-moves a session the way a calendar
auto-scheduler would. On a yes:
1. `set_plan_day_outcome(old_artifact_id, old_date, "moved", moved_to: <new date>)`.
2. Re-save the week (or the target week) via `save_training_plan` with the session placed on
its new date — **never include `status`, `movedTo`, or `eventId` keys in the days you
send**; the board carries them forward from the old day. **Keep the old date's day entry**
in what you send (the board carries its `moved` status + calendar receipt forward by date;
dropping the entry loses both), and keep **one entry per date**: a session pulled onto a
date that already has one is MERGED into that single entry (or the existing session is
pushed to another free day) — the board rejects two entries on one date (400).
3. `push_plan_to_calendar` for the affected week (ops#17's idempotent path) so the calendar
reflects the move. **Read the user's REAL calendar yourself first** — this skill does not
inherit that instruction from `fitness-training-plan`'s STEP 8 (a Cowork bundle is
per-skill; text living in another skill's file does not exist at THIS skill's runtime), so
it is restated here: read the real calendar for the affected date(s), collect **only**
`{date, start, end}` busy times — never a title or attendee — and pass them as
`busy_windows` on the push. Cos uses `busy_windows` for that one call only and **never
stores or syncs** it.
Relay any `skipped` result the push reports, same as the weekly skill does — and when the
moved day's own result comes back `resolved` **with an `eventId`**, its original session is
still on the calendar: tell the user and offer to remove it via the `calendar` MCP's delete
tool (the board never deletes it).
- **A clean day adds nothing.** Nothing unresolved and nothing worth proposing to move →
**no extra output** in the brief — no "all clear" paragraph. The brief simply starts at
STEP 1 of the procedure below.
---
## PROCEDURE — FETCH → GENERATE → PERSIST
`<today>` is today's date as `YYYY-MM-DD` unless the user names another day.
### 1. FETCH today's readiness — the form score (the deterministic anchor)
`get_form_score({ date: <today> })` → `{ date, score (0–100), level, color,
breakdown: { hrv, sleep, resting_hr, load }, recommendation }`. The board computed this —
**read it, do not recompute it.** Note the **`score`** (you'll persist it verbatim), the
sub-scores in **`breakdown`** (each 0–100, 50 = neutral / no data — they tell you *why* the
score is what it is), the **`level`** (`good` ≥75 / `moderate` ≥50 / `low` ≥30 /
`insufficient` <30), and the board's own **`recommendation`** string. If a breakdown
sub-score is ~50, that signal is **missing** (e.g. no HRV logged) — say the brief is built on
partial data, don't read a flat 50 as "average recovery".
### 2. FETCH the context (three reads)
- **`get_daily_summary({ date: <today> })`** — last night's sleep (hours + stages), this
morning's metrics (HRV, resting HR, steps), and (soft-dep) the day's nutrition + calorie
balance. This is the human-readable colour behind the score.
- **`list_health_data({ type: "workout", from: <48h ago ISO>, to: <today end> })`** — recent
training **load**: did they already do a hard/long session in the last day or two? Back-to-
back hard days is a warning even when the score is decent.
- **`get_athlete_profile({})`** — the training FOCUS (goal=sport/event), days/week, **sports[]**,
equipment, max session minutes. The recommended session must respect these (a fallback session
comes from `sports[]`). **If it returns no profile**, tell the user to set it first (point at the
`fitness-athlete-profile` skill / the **/fitness** page) — a brief without a focus is weak — but
you can still give a recovery-only read from the score.
- **`get_body_profile({})` + `get_body_status({})`** (body MCP) — the **trainingStatus**
(novice|intermediate|advanced — how hard to push) and current **weight**; the body goal (fat loss
vs build vs maintain) from **`get_body_objective({})`**'s free-text `goalText`. These moved off the
athlete profile in v14 — read them here when the session call depends on the body goal / experience.
### 3. FETCH today's PLANNED session
`list_coaching_artifacts({ kind: "training_plan", limit: 1 })` → the latest plan; in its
`days[]` find the entry whose date is **`<today>`** (plans key by ISO week, days carry a
date). That planned session is what the brief **confirms or adjusts**. If there's no plan, or
no entry for today, fall back to a sensible session from the profile's `sports[]` (or a rest
day if recovery is poor) and say there was no planned session.
Read today's day `status` (from STEP 1.5's fetch, or absent ≡ `planned`) before treating it as
live: a day already **`status: "moved"`** is NOT today's session anymore — it relocated
elsewhere; follow its `movedTo` and brief on recovery only (there is no training decision left
to make for today from that original entry). A day already **`status: "done"`** means today's
training question is already answered — the brief becomes **recovery-only** (no "should I
train" call to make; just report readiness).
### 4. GENERATE the brief (your judgement)
Compose the artifact from what you read. Map **readiness** off the form score **and** the
sleep signal (the board's `recommendation` is your steer):
- **`ready`** — score **≥ 70** and good sleep (and no fresh hard-load / warning). Train as
planned.
- **`caution`** — score **40–70**, or average/short sleep, or a notable warning. Train, but
**easier** — drop intensity/duration, swap a hard session for an easy/aerobic one.
- **`rest`** — score **< 40**, or poor sleep, or a clear over-reach signal. Recovery day —
rest, mobility, or a very easy flush.
Then build the rest:
- **`recommended_session`** — `{ sport, duration_min, intensity, description }`. Start from
**today's planned session** (STEP 3) and **adjust it to recovery**: `ready` → keep it;
`caution` → reduce intensity/volume (e.g. tempo → steady, 90 → 60 min); `rest` → a recovery
option (easy spin / walk / mobility / yoga) or an explicit rest. `sport` must come from the
profile's **`sports[]`** (or the plan); respect `maxSessionMinutes`. Use a clear `intensity`
word (`recovery` / `easy` / `steady` / `moderate` / `hard`).
- **`warnings[]`** — the negative signals: short/poor sleep (call the hours), low HRV vs
baseline, elevated resting HR, **high recent load** (back-to-back hard days from STEP 2),
low overall score, missing data. Empty array if none.
- **`green_lights[]`** — the positives: good/long sleep, HRV at/above baseline, resting HR at
baseline, fresh legs (rest yesterday), a strong score. Empty array if none.
- **`one_liner`** — one short, plain-language motivating-or-cautionary line (e.g. *"Green
light — legs are fresh, hit the planned tempo."* / *"Amber — sleep was short, keep it easy
and aerobic today."* / *"Recovery day — HRV's down and you trained hard yesterday; rest and
come back stronger."*).
### 5. PERSIST — `save_pre_workout_brief`
```
save_pre_workout_brief({
date: <today>, // YYYY-MM-DD — UPSERT key (re-saving today overwrites)
readiness: "ready" | "caution" | "rest",
form_score: <the score from get_form_score>, // verbatim — do NOT recompute
recommended_session: { sport, duration_min, intensity, description },
warnings: [ ... ],
green_lights: [ ... ],
one_liner: "..."
})
```
`readiness` **must** be exactly one of `ready | caution | rest` (the board rejects anything
else — it does not repair a malformed body). `form_score` is the number you read from
`get_form_score` — passing your own recomputation is a bug. Validate your own JSON before
sending.
### 6. TELL the user
Report the call in plain language: the **readiness** + the **form score** (and the one or two
breakdown signals that drove it), the **recommended session** (and how you adjusted it off
the plan), the top **warnings** / **green lights**, and the **one-liner**. **Carry the
not-medical-advice framing** — a "go easy / rest" read is a conservative default, and any
pain / illness / abnormal symptom means **stop and consult a professional**, not push
through. Note that the brief is saved and visible on the **/fitness/pre-workout-brief** feed
(latest-by-default; re-saving today updates it in place).
---
## Worked example
*"Should I train today?"* (auto mode), today = `2026-06-17`:
1. `get_form_score({ date: "2026-06-17" })` → `{ score: 48, level: "moderate", breakdown:
{ hrv: 44, sleep: 38, resting_hr: 55, load: 60 }, recommendation: "Insufficient sleep.
Favor a light session or rest." }`.
2. `get_daily_summary({ date: "2026-06-17" })` → slept 5h40 (short), HRV 41 (below baseline);
`list_health_data({ type: "workout", from: "2026-06-15T00:00:00Z", to: "2026-06-17T23:59:59Z" })`
→ a hard 75-min ride yesterday; `get_athlete_profile({})` → focus olympic_triathlon,
sports running/cycling/swimming, max 90 min; `get_body_profile({})` → trainingStatus intermediate.
3. `list_coaching_artifacts({ kind: "training_plan", limit: 1 })` → today's planned day = a
60-min tempo run.
4. GENERATE → **readiness `caution`** (score 48, sleep sub-score 38 = poor, hard ride
yesterday). recommended_session = swap the tempo for **`{ sport: "running", duration_min:
40, intensity: "easy", description: "Easy aerobic run, zone 2 — skip the tempo today" }`**.
warnings = `["Short sleep (5h40)", "HRV 41 below baseline", "Hard 75-min ride yesterday"]`.
green_lights = `["Decent recent training load — no overtraining"]`. one_liner = *"Amber —
sleep was short and HRV's down, so keep it easy and aerobic; save the tempo for tomorrow."*
5. `save_pre_workout_brief({ date: "2026-06-17", readiness: "caution", form_score: 48,
recommended_session: {…}, warnings: [...], green_lights: [...], one_liner: "..." })`.
6. Tell the user the caution call + the easy-run swap + the not-medical-advice note; point
them at /fitness/pre-workout-brief.
---
## Conventions (guardrails recap)
- **Close out yesterday FIRST** (STEP 1.5, after the overnight-data ingest) — auto-resolve the
proven subset silently, batch the rest into one question, and a clean day adds no extra
output.
- **Never relocate a session without confirmation, in any mode** — propose moving a missed or
today's session, but only act on an explicit yes; never fabricate an outcome (an unanswered
day stays `planned`).
- **`fitness` MCP only, via the tools.** Never `bash`/`curl`. The
**/fitness/pre-workout-brief** page is the read twin (a history feed); you author + persist.
- **Use the board's `form_score` — never recompute it.** `get_form_score` is the
deterministic anchor; you read + interpret its `score` / `breakdown` / `level` /
`recommendation` and persist the `score` **verbatim** in `save_pre_workout_brief`.
- **The board does NOT generate — YOU do.** No board-side LLM; the page's Generate hands off
to you. Never tell the user to "click Generate" — **you** author the brief and `save_*` it.
- **The add-on must be ENABLED for the save.** A disabled add-on 404s the write ("Not found —
the fitness add-on may be disabled.") while reads stay open — tell the user to flip it on at
**/addons**; you don't enable it.
- **Mode (STEP 0):** a brief is **one low-stakes write** — just do it in either mode; no
pending/propose queue, no confirmation needed.
- **Ingest today's overnight data first** (last night's sleep + this morning's HRV /
resting-HR) — a brief on stale data is misleading.
- **Profile required for a strong brief.** No profile → tell the user to set it first
(`fitness-athlete-profile` / **/fitness**); you can still give a recovery-only read from the score.
- **`readiness` ∈ `ready | caution | rest`, exactly.** The board rejects anything else and
does not repair a malformed body — validate your JSON. Upsert key is **today's date** (re-
saving overwrites).
- **NOT MEDICAL ADVICE.** A brief is an informational estimate — **say so**; a "go easy /
rest" read is a conservative default; **defer injuries, illness, abnormal symptoms,
pregnancy, or an under-18 user to a physician / physiotherapist / qualified coach**
(recommend they consult one; don't push hard training).
- **Report** the readiness + form score + driving signals, the (adjusted) recommended
session, the warnings / green lights, the one-liner — and that it's saved on the
/fitness/pre-workout-brief feed.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!