git:20260901.ff0c382 to git:20260905.0c707c7
24 added, 79 removed. Audit B to B.
# claude-code-fitness-hermit
- A fitness/training domain layer for `claude-code-hermit`: skills, subagents, Strava MCP wiring, and routine prompt templates for an autonomous training assistant.
+ A fitness/training domain layer for `claude-code-hermit`: skills, a Strava data subagent, Strava MCP wiring, and routine prompt templates for an autonomous training assistant. A Claude Code plugin, not a standalone project: install from the marketplace (README), then run `/claude-code-fitness-hermit:hatch` in a project where core is already hatched; `hatch` checks the required core version from `.claude-plugin/hermit-meta.json`.
- ## This Repo is a Plugin
+ ## Structure
- This repo is structured as a Claude Code plugin. It is NOT a standalone project — it gets installed into other projects via:
+ - `skills/`: `hatch`, `fitness-brief` (`--morning|--evening|--slot <name>`; owns Strava connectivity, activity sync, RPE binding, and the Run deep-dive), `activity-deep-dive`, `capture-activity-rpe` (auto-triggered from channel replies), `set-rpe`, `weekly-coaching-patterns`, `domain-brainstorm` (operator-invoked only)
+ - `agents/strava-data-cruncher.md`: Haiku bulk-aggregation subagent; owns the per-invocation API-call cap
+ - `state-templates/compiled/routine-*.md`: routine prompt files `hatch` drops into the consumer's `compiled/`; `state-templates/CLAUDE-APPEND.md`: the Fitness Workflow block
+ - `settings.json`: pre-approved permissions for read-class Strava MCP tools and hermit state writes
+ - `docs/knowledge-schema.md`: work-product types, state-file owners and shapes, retention
- ```
- claude plugin marketplace add gtapps/claude-code-hermit
- claude plugin install claude-code-fitness-hermit@claude-code-hermit --scope local
- ```
+ ## Rules
- After install, run `/claude-code-fitness-hermit:hatch` in the target project. The core hermit (`claude-code-hermit` ≥1.2.34) must be installed and hatched first — `hatch` will prompt if it isn't.
+ - Never commit real Strava OAuth credentials; `.env` and `.mcp.json` are gitignored. The hatch skill reads `.env` with the `Read` tool, never `cat`/`grep`/`echo` (`Bash(cat .env*)` is a seeded native deny, and credential values must not land in the transcript).
+ - The MCP server key is `strava` (written to `.mcp.json` by `hatch`, tool IDs `mcp__strava__*`); skill text and `settings.json` matchers depend on that name. Provided by `@r-huijts/strava-mcp-server` via `npx`, unpinned; operators can pin in their own `.mcp.json`.
+ - Every Strava workflow calls `mcp__strava__check-strava-connection` first. Write-class tools (`star-segment`, `connect-strava`, `disconnect-strava`) are denied in `settings.json`; never call them.
+ - No persona, agent name, or sign-off copy ships here; those come from the consumer's `config.json`.
- ## Plugin Structure
+ ## Routines and state
- - `skills/hatch/` — one-time setup wizard namespaced as `/claude-code-fitness-hermit:hatch`
- - `skills/fitness-brief/` — daily morning/evening brief (`/claude-code-fitness-hermit:fitness-brief --morning|--evening|--slot <name>`); owns Strava connectivity, activity sync, RPE binding, and Run deep-dive
- - `skills/activity-deep-dive/` — per-activity coaching analysis (`/claude-code-fitness-hermit:activity-deep-dive`)
- - `skills/capture-activity-rpe/` — auto-triggered RPE capture from channel replies (`/claude-code-fitness-hermit:capture-activity-rpe`)
- - `skills/set-rpe/` — manual RPE entry for any activity (`/claude-code-fitness-hermit:set-rpe`)
- - `skills/weekly-coaching-patterns/` — scheduled cardiac-drift trend check (`/claude-code-fitness-hermit:weekly-coaching-patterns`)
- - `skills/domain-brainstorm/` — on-demand codebase friction brainstorm: reads git churn, last test signal, and README coverage to surface at most 2 `[prefix]`-tagged improvement proposals. Operator-invoked only.
- - `agents/strava-data-cruncher.md` — Haiku bulk-aggregation subagent (`@claude-code-fitness-hermit:strava-data-cruncher`)
- - `state-templates/compiled/routine-*.md` — four routine prompt files dropped into the consumer's `.claude-code-hermit/compiled/` by `hatch`
- - `state-templates/CLAUDE-APPEND.md` — Fitness Workflow block injected into the consumer's `CLAUDE.md` by `hatch`
- - `settings.json` — pre-approved permissions for read-class Strava MCP tools and hermit state writes
- - `docs/knowledge-schema.md` — fitness work-product types and retention rules
- - `.claude-plugin/plugin.json` — plugin manifest
- - `.claude-plugin/hermit-meta.json` — hermit-internal fields (`required_core_version`, `requires`)
+ - The routine prompt files in `state-templates/compiled/` are not invokable skills; `hatch` registers them as `prompt_file:` entries in `config.json.routines` and core's `hermit-routines load` activates them. Renaming a prompt file means updating the registered path.
+ - Routine entries use the no-leading-slash form `"claude-code-fitness-hermit:<skill>"`; `boot_skill` in `hermit-meta.json` uses the leading-slash form. This plugin ships no `boot_skill`.
+ - `raw/` holds ephemeral Strava pulls (aged out by `knowledge.raw_retention_days`), `compiled/` durable outputs (weekly plans and summaries, activity notes; injected at session start within `compiled_budget_chars`), `state/` machine files. Both `raw/` and `compiled/` are flat, per core's storage contract. Owners, shapes, and retention of `strava-last-activity-id.txt`, `strava-weekly-baselines.json`, `activity-notes.json` (durable, keyed by Strava activity ID), and `strava-pending-rpe.json` (written by the evening brief only after a confirmed channel send; consumed once by `capture-activity-rpe` within 24h) are in `docs/knowledge-schema.md`.
+ - `MEMORY.md` (auto-memory) carries the athlete profile, training preferences, and notes.
## Hatch target routing
- `/hatch` Step 1 runs `.claude-code-hermit/bin/hermit-run domain-hatch preflight claude-code-fitness-hermit`; core's `scripts/domain-hatch.ts` owns install-scope detection, target resolution, and stamping `hatch-options.json`. The preflight verdict hands back `target`, `target_file`, `target_default`, and `needs_target_question` — Step 5 only surfaces the Visibility prompt when asked to, records the answer with `domain-hatch ensure-target claude-code-fitness-hermit --target <choice>`, then writes the block with `domain-hatch sync-block claude-code-fitness-hermit`. The skill never reads or writes `hatch-options.json` itself.
-
- ## Core Rules
-
- - Never commit real Strava OAuth credentials — `.env` and `.mcp.json` are gitignored.
- - Never call write-class Strava tools: `star-segment`, `connect-strava`, `disconnect-strava`. Blocked by `settings.json`.
- - Always call `mcp__strava__check-strava-connection` first in any Strava workflow.
- - No persona, no agent name, no sign-off copy. Those belong in the consumer project's `config.json`.
- - Agent references in skill instructions must use the full namespaced form (`claude-code-fitness-hermit:strava-data-cruncher`). Bare names will fail at dispatch.
-
- ## MCP Server `strava`
-
- The Strava MCP server is registered under the key `strava` in `.mcp.json` (written by `hatch`). Tool IDs follow `mcp__strava__*`. The name `strava` is required — skill instructions and settings matchers use it.
-
- Provided by: `@r-huijts/strava-mcp-server` (via `npx`). No version is pinned; operators can pin in their own `.mcp.json` post-hatch.
-
- ## Routines
-
- The four routine prompt files in `state-templates/compiled/` are **not invokable skills** — they are cron-driven prompt files injected via `prompt_file:` entries in `config.json.routines`. The base hermit's `hermit-routines load` command activates them each session.
-
- If you add or modify routine prompts, the corresponding `config.json.routines` entry (registered by `hatch`) must keep the `prompt_file:` path pointing to the right `compiled/routine-*.md` filename.
-
- ## Memory Conventions
+ Core's `scripts/domain-hatch.ts` owns target resolution and `hatch-options.json`. `/hatch` Step 1 runs `.claude-code-hermit/bin/hermit-run domain-hatch preflight claude-code-fitness-hermit`; Step 5 asks the Visibility question only when `needs_target_question` says so, records it with `domain-hatch ensure-target claude-code-fitness-hermit --target <choice>`, and writes the block with `domain-hatch sync-block claude-code-fitness-hermit`.
- - `MEMORY.md` (auto-loaded at session start): athlete profile, training preferences, notes.
- - `.claude-code-hermit/raw/` — ephemeral Strava data pulls (activity-fetch, activity-streams). Aged out per `knowledge.raw_retention_days`.
- - `.claude-code-hermit/compiled/` — durable outputs (weekly plans, weekly summaries, activity notes). Injected at session start within `compiled_budget_chars`.
- - `.claude-code-hermit/state/strava-last-activity-id.txt` — rolling cursor written by `fitness-brief` (evening).
- - `.claude-code-hermit/state/strava-weekly-baselines.json` — rolling load baselines written by `weekly-load-review` and read by `monday-planning`.
- - `.claude-code-hermit/state/activity-notes.json` — subjective RPE and notes keyed by Strava activity ID. Written by `capture-activity-rpe` and `set-rpe`; read by `activity-deep-dive` and `weekly-load-review`. Retained indefinitely (covers multi-year lookback).
- - `.claude-code-hermit/state/strava-pending-rpe.json` — single-record file written by `fitness-brief` (evening) after a successful channel send. Holds the latest synced activity for RPE binding. Deleted by `capture-activity-rpe` on capture; freshness-gated (24h) not pruned.
+ ## Strava API
- Do NOT create subdirectories inside `.claude-code-hermit/raw/` or `.claude-code-hermit/compiled/`. All artifacts are flat per the base hermit's storage contract (`docs/plugin-hermit-storage.md`).
+ - Reference: https://developers.strava.com/docs/reference/ ; OAuth: https://developers.strava.com/docs/authentication/
+ - Rate limits are tight (per 15 minutes and per day; current numbers on the reference page). `strava-data-cruncher` caps calls per invocation for that reason, and `get-all-activities` is paginated, so large histories can hit the limit.
+ - `get-activity-streams` needs explicit `keys` (e.g. `heartrate,velocity_smooth,altitude,cadence`).
+ - HR zone boundaries come from `get-athlete-zones`, never hardcoded thresholds.
## Development
- Test locally against a target project without publishing:
-
- ```
- cd /path/to/target-project
- claude --plugin-dir /path/to/claude-code-fitness-hermit
- ```
-
- Then run `/claude-code-fitness-hermit:hatch` in the target.
-
- **Development constraints:**
-
- - There is no `Bash(*TOKEN*)` substring deny. `Bash(cat .env*)` is a seeded native deny, and credential values must not land in the transcript. The hatch skill reads `.env` via the `Read` tool, never `cat`/`grep`/`echo`.
- - When aligning with a new base hermit version, sweep `skills/`, `agents/`, `state-templates/`, and `docs/` for stale hermit-facing terms. Grep: `grep -rn "stale_term" skills/ agents/ state-templates/ docs/ CLAUDE.md .claude-plugin/`
- - Routine entries in `config.json.routines` use the no-leading-slash form: `"claude-code-fitness-hermit:<skill>"`. `boot_skill` in `hermit-meta.json` uses the leading-slash form: `"/claude-code-fitness-hermit:<skill>"`. This plugin currently ships no `boot_skill`.
-
- ## Strava API References
-
- - API reference: https://developers.strava.com/docs/reference/
- - Rate limits: 100 requests / 15 min, 1000 requests / day. The `strava-data-cruncher` agent caps at 30 calls per invocation.
- - OAuth flow: https://developers.strava.com/docs/authentication/
-
- Known gotchas:
- - `get-all-activities` is paginated; the MCP server handles this but large histories may hit rate limits.
- - `get-activity-streams` requires explicit `keys` (e.g. `heartrate,velocity_smooth,altitude,cadence`). Always specify them.
- - HR zone boundaries come from `get-athlete-zones`, not hardcoded thresholds.
+ `claude --plugin-dir /path/to/claude-code-fitness-hermit` from a target project, then `/claude-code-fitness-hermit:hatch`. Tests: `bash tests/run-all.sh`.