From claude-code-fitness-hermit
One-time setup wizard for the claude-code-fitness-hermit plugin. Configures Strava MCP credentials, drops routine prompt templates, and wires routines into config.json.
How this skill is triggered — by the user, by Claude, or both
Slash command
/claude-code-fitness-hermit:hatchThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Idempotent setup wizard for the fitness plugin. Run **after** `/claude-code-hermit:hatch` has already been completed.
Idempotent setup wizard for the fitness plugin. Run after /claude-code-hermit:hatch has already been completed.
Read .claude-code-hermit/config.json.
If the file does not exist or _hermit_versions["claude-code-hermit"] is absent or empty:
"The base hermit is not set up in this project yet. Run
/claude-code-hermit:hatchfirst, then return here."
Use AskUserQuestion: "Would you like to run /claude-code-hermit:hatch now? (yes / no)"
claude-code-hermit:hatch):
.claude-code-hermit/state/hatch-resume.json with { "skill": "claude-code-fitness-hermit:hatch" }./claude-code-fitness-hermit:hatch.)"/claude-code-hermit:hatch via the Skill tool — terminal action, stop after the call.If _hermit_versions["claude-code-hermit"] is present but the version string is earlier than 1.0.26 (compare major.minor.patch numerically), warn:
"Base hermit version is {version}; this plugin requires ≥1.0.26. Run
/claude-code-hermit:hermit-evolveto upgrade, then re-run this hatch."
Stop.
Read _hermit_versions["claude-code-fitness-hermit"] from .claude-code-hermit/config.json.
Read version from ${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json.
If the versions match, say:
"claude-code-fitness-hermit {version} is already installed. Skip to Step 8 to re-verify the installation, or reply 'full' to re-run the full wizard."
Use AskUserQuestion: "(verify / full)"
If absent or stale: continue from Step 3.
IMPORTANT: Do NOT use grep, cat, echo, or any Bash command to read .env. Three of the four required variables contain the literal string TOKEN in their name, which triggers the base hermit's deny-patterns hook on any Bash command argument. Use the Read tool only.
Tell the operator:
"This plugin needs four Strava OAuth credentials in
.env. If you haven't done this yet:
cp .env.example .env(or copy the file manually)- Open
.envand fill in all four values from your Strava developer app:
STRAVA_CLIENT_ID— numeric app IDSTRAVA_CLIENT_SECRET— app secretSTRAVA_ACCESS_TOKEN— initial access tokenSTRAVA_REFRESH_TOKEN— refresh tokenSee https://developers.strava.com/docs/authentication/ to create a Strava app if you haven't. Reply 'done' when the file is filled in, or 'abort' to stop."
Use AskUserQuestion: "(done / abort)"
Use the Read tool to read .env. Parse each line of the form KEY=VALUE. Verify that all four of these keys are present and their values are not empty and not replace_me:
STRAVA_CLIENT_IDSTRAVA_CLIENT_SECRETSTRAVA_ACCESS_TOKENSTRAVA_REFRESH_TOKENIf any value is missing or still set to replace_me, report which ones and loop back to the AskUserQuestion above. Do not proceed until all four are valid.
Step 4.0 — Detect an ambient Strava MCP server. The operator may already run a Strava MCP server (user-scoped, or configured by another tool). Run claude mcp list (Bash) and scan for a server that talks to Strava — a name containing strava, or an entry whose command/args reference a Strava MCP package (e.g. strava-mcp-server).
AskUserQuestion (header: "Strava MCP"): Reuse the existing <name> server (recommended — no duplicate) / Install the bundled @r-huijts/strava-mcp-server.
.mcp.json write entirely. Record which server key the skills should target (if it is not strava, note in the final report that skill/settings matchers assume the key strava, so the operator should either rename their server to strava or accept that the fitness skills call mcp__strava__*). Continue to Step 5.This is a local reuse-vs-install choice only — do not attempt to reconcile or edit the operator's other MCP configs.
Using the four values you parsed from .env in Step 3 (held in working context — do not re-read .env), write the Strava MCP server entry into the project's .mcp.json.
Do not embed ${VAR} placeholders — substitute literal values. Claude Code passes MCP env blocks as literal environment variables to the child process; it does not expand shell variable syntax.
Read the project root .mcp.json (use the Read tool; treat as { "mcpServers": {} } if the file does not exist).
Check if a strava key already exists under mcpServers:
${...} placeholders → rewrite just the strava entry with literal values.The strava entry shape:
{
"strava": {
"command": "npx",
"args": ["-y", "@r-huijts/strava-mcp-server"],
"env": {
"STRAVA_CLIENT_ID": "<literal STRAVA_CLIENT_ID from .env>",
"STRAVA_CLIENT_SECRET": "<literal STRAVA_CLIENT_SECRET from .env>",
"STRAVA_ACCESS_TOKEN": "<literal STRAVA_ACCESS_TOKEN from .env>",
"STRAVA_REFRESH_TOKEN": "<literal STRAVA_REFRESH_TOKEN from .env>"
}
}
}
Write the updated .mcp.json using the Write tool.
Add .mcp.json and .env to .gitignore if not already present. Read the project .gitignore, check for each entry; append any that are missing on new lines using Edit.
Copy the four routine prompt templates from the plugin's state-templates/compiled/ into the consumer's .claude-code-hermit/compiled/.
For each of the four files:
${CLAUDE_PLUGIN_ROOT}/state-templates/compiled/routine-strava-sync.md${CLAUDE_PLUGIN_ROOT}/state-templates/compiled/routine-strava-health-check.md${CLAUDE_PLUGIN_ROOT}/state-templates/compiled/routine-weekly-load-review.md${CLAUDE_PLUGIN_ROOT}/state-templates/compiled/routine-monday-planning.mdRead the source file (using Read tool), then check if the destination exists (.claude-code-hermit/compiled/<filename>):
✓ dropped <filename>.⊘ skipped <filename> (already present).Resolve target file: Read .claude-code-hermit/state/hatch-options.json. Use the "target" field:
"local" → target_file = CLAUDE.local.md
"committed" or absent → target_file = CLAUDE.md
If the file doesn't exist (no hatch-options.json yet — operator's core hermit predates 1.1.1): detect core_install_scope from claude plugin list --json using the same precedence rules as core hatch Step 1.5 item 2 (filter entries where plugin name is claude-code-hermit and enabled == true; precedence local > project (both require projectPath == project root) > user (any projectPath) > null; map project → committed, local/user/null → local). Ask with AskUserQuestion (header: "Visibility") — scope-derived default at position 0 with (recommended): .local files (gitignored — operator-personal) / Committed files (shared with teammates). Write the canonical 5-field schema to .claude-code-hermit/state/hatch-options.json:
{
"target": "<choice>",
"core_install_scope": "<project|local|user|null>",
"stamped_at": "<current ISO 8601 timestamp with timezone offset>",
"stamped_by": "claude-code-fitness-hermit:hatch",
"version": "<current fitness-hermit plugin version from ${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json>"
}
Read target_file. Search for the opening marker <!-- claude-code-fitness-hermit: Fitness Workflow -->. The matching closing marker is <!-- /claude-code-fitness-hermit: Fitness Workflow -->.
target_file does not exist (greenfield CLAUDE.local.md is common) → treat as marker-absent and proceed to the append branch; Edit will create the file.${CLAUDE_PLUGIN_ROOT}/state-templates/CLAUDE-APPEND.md to target_file using Edit.hermit-evolve handles block replacement on upgrade).Stray-block migration (block stranded in the non-target file after a target flip) is handled one-shot by the Upgrade Instructions in this version's CHANGELOG entry, executed by hermit-evolve Step 7. Hatch itself stays focused on target-aware setup.
Read .claude-code-hermit/knowledge-schema.md.
Check if activity-streams: is present in the file. This string only appears in the Raw Captures section, which is the last thing written — so its presence means both blocks were fully written on a prior run.
If absent, append the following block under ## Work Products (create the section header if the base schema only has a template stub):
- weekly-plan: weekly training structure suggestion (7-day breakdown). Triggered by monday-planning routine (Mon 09:30). location: compiled/weekly-plan-<YYYY-MM-DD>.md
- weekly-summary: week-over-week training load review. Triggered by weekly-load-review routine (Sun 18:00). location: compiled/weekly-summary-<YYYY-MM-DD>.md
- recovery-assessment: recovery indicators from recent activity data. Triggered by operator request or strava-sync flag. location: compiled/recovery-assessment-<YYYY-MM-DD>.md
- fitness-snapshot: current fitness state snapshot. Triggered by operator request. location: compiled/fitness-snapshot-<YYYY-MM-DD>.md
- activity-note: per-activity coaching analysis. Triggered by activity-deep-dive skill. location: compiled/activity-<id>-<YYYY-MM-DD>.md
And under ## Raw Captures (create if absent):
- activity-fetch: raw activity list from Strava. Feeds weekly-plan, weekly-summary, recovery-assessment. Retention: 3 days. location: raw/activity-fetch-<date>.json
- activity-streams: HR/pace/power time-series for a specific activity. Feeds recovery-assessment, activity-note, fitness-snapshot. Retention: 7 days. location: raw/activity-streams-<id>-<date>.json
If already present: skip (idempotent).
Use Edit to make the changes.
Use the config.json content already loaded in Step 1. (Do not re-read the file.)
Set _hermit_versions["claude-code-fitness-hermit"] to the plugin version retrieved in Step 2.
If the key already exists: update the value. If absent: add it alongside the existing _hermit_versions["claude-code-hermit"] entry.
In the routines array, check for each of these four IDs. For any that are absent, add the entry. For any that are present (by id), skip (do not clobber existing operator edits).
{
"id": "strava-sync",
"schedule": "30 21 * * *",
"skill": "claude-code-hermit:session-start",
"enabled": true,
"run_during_waiting": true,
"prompt_file": "compiled/routine-strava-sync.md"
},
{
"id": "strava-health-check",
"schedule": "5 8 * * *",
"skill": "claude-code-hermit:session-start",
"enabled": true,
"run_during_waiting": true,
"prompt_file": "compiled/routine-strava-health-check.md"
},
{
"id": "weekly-load-review",
"schedule": "0 18 * * 0",
"skill": "claude-code-hermit:session-start",
"enabled": true,
"run_during_waiting": true,
"prompt_file": "compiled/routine-weekly-load-review.md"
},
{
"id": "monday-planning",
"schedule": "30 9 * * 1",
"skill": "claude-code-hermit:session-start",
"enabled": true,
"run_during_waiting": true,
"prompt_file": "compiled/routine-monday-planning.md"
}
In config.scheduled_checks, check for an entry with id: "weekly-coaching-patterns". If absent, append it. If present (by id), skip — do not clobber existing operator edits.
{"id": "weekly-coaching-patterns", "plugin": "claude-code-fitness-hermit", "skill": "claude-code-fitness-hermit:weekly-coaching-patterns", "enabled": true, "trigger": "interval", "interval_days": 7}
No prompt needed — this is a read-only analysis. The core daily scheduled-checks routine picks it up; interval_days: 7 gates cadence. Findings surface as proposals automatically via the existing pipeline.
Write the updated config.json using Write tool (full file replacement to ensure valid JSON).
Run bun ${CLAUDE_PLUGIN_ROOT}/scripts/automode-env.ts .claude/settings.local.json — always .claude/settings.local.json, regardless of hatch_target: Claude Code's auto-mode classifier reads autoMode config only from local/user scope, never a committed project .claude/settings.json. This names www.strava.com as a trusted external service, so the classifier stops treating the nightly strava-sync routine's read-only fetches as unrecognized outbound calls. Additive and idempotent; safe to re-run on every hatch. No prompt needed.
Print a structured summary:
claude-code-fitness-hermit {version} setup complete.
Installation summary:
✓ Prerequisite: claude-code-hermit {base_version} confirmed
✓ .env: all four Strava credentials present
✓ .mcp.json: strava server entry written (or was already present)
✓ .gitignore: .mcp.json and .env covered
✓ Routine prompts: {N}/4 dropped, {M}/4 already present
✓ CLAUDE.md: Fitness Workflow block injected (or was already present)
✓ knowledge-schema.md: fitness types added (or were already present)
✓ config.json: _hermit_versions stamped, {K}/4 routines added, weekly-coaching-patterns check registered
Manual steps remaining:
- Restart Claude Code so the `strava` MCP server loads from .mcp.json
- Approve the `strava` server when prompted on first use
- Run /mcp to confirm `strava` is connected
- Verify connectivity: call mcp__strava__check-strava-connection
Go always-on (recommended):
- Docker: /claude-code-hermit:docker-setup
Builds the container and walks you through channel pairing in one go.
- Bare tmux: .claude-code-hermit/bin/hermit-start
For channels (Discord/Telegram) with tmux, run
/claude-code-hermit:channel-setup first.
Prefer to test interactively first? After restarting, run:
/claude-code-hermit:hermit-routines load
— activates the four fitness routines in the current Claude session.
The always-on runtime activates routines automatically — the interactive
steps are only for a test drive before handing over to the runtime.
Installed skills:
/claude-code-fitness-hermit:activity-deep-dive — per-activity coaching analysis
/claude-code-fitness-hermit:weekly-coaching-patterns — weekly cardiac-drift trend check (scheduled, interval_days: 7)
Installed subagent:
@claude-code-fitness-hermit:strava-data-cruncher — bulk Strava data aggregation (Haiku)
Security reminder: .env and .mcp.json contain real Strava credentials. Both are gitignored — verify before any git push.
Read by /claude-code-hermit:docker-security when the operator enables LAN containment + DNS policy. Each entry is surfaced as a per-entry confirmation prompt; nothing here is auto-applied.
server=/strava.com/... matches both www.strava.com (web) and api.strava.com (API) via dnsmasq's subdomain-match semantics. The Strava MCP server (@r-huijts/strava-mcp-server via npx) also needs npmjs.org, but that's already in the wizard's seed allowlist for npm/plugin installs.
(none — Strava is a cloud service)
npx claudepluginhub p/gtapps-claude-code-fitness-hermit-plugins-claude-code-fitness-hermitSets up Home Assistant access for this project, configuring HA connection and the official Home Assistant MCP Server integration.
Initializes and repairs Harness project configuration: CLAUDE.md, Plans.md, hooks, sync, CI/CD, Codex CLI, memory setup, agent config, and mirror sync.
Generates .mcp.json and .claude/settings.json to configure MCP servers, tokens, and tool permissions for agent-flow pipeline. Supports CLI flags for tracker type, instance URL, and source control remote.