Skip to content

training-sync — three cron passes that turn Garmin's plan into calendar events

A local claude -p run three times a day with a mode-specific prompt from ~/.claude/routines/, prefixed by _shared-facts.md and a CLOCK line. Local because the Garmin MCP is localhost-only; the claude.ai cloud routine (trig_01Ke8GAbB9q1y4J7UXqRhtm2) is disabled and holds the old single-pass design.

Input → Movement → Output

Reads Garmin (coach assignment, sleep onset, body battery) via 127.0.0.1:8000/mcp and the calendar via the Google Calendar connector. Decides placement under the evening-default, earned-mornings policy (constraints live in memory angel-training-schedule-constraints.md). Writes/updates calendar events; an "Early wake" event's start time drives an iPhone Shortcuts automation that toggles one of five pre-made alarms (04:45/05:00/05:15/05:30/05:50).

Why this shape

Evening (21:00) is where a morning session is decided and an actionable bedtime set. Prealarm (03:45) reads the actual sleep onset and cancels an early wake before the alarm fires. Morning (06:10) reconciles today against the authoritative coach assignment and never places anything before 07:00.

Steps

  1. ~/.local/bin/training-sync <mode> sets TZ, picks prompt + deadline (:19-23: evening 23:45, prealarm 04:30, morning 13:00), skips if started after the deadline unless TRAINING_SYNC_FORCE=1 (:33-37).
  2. Waits up to 5 min for Garmin MCP /healthz (:39-45), else exits garmin-down.
  3. Runs claude -p --output-format json --tools "" (built-in tools off) from /var/tmp/claude-headless with --setting-sources project. Garmin comes in via ~/.claude/routines/garmin-mcp.json, and the 150 garmin tools it doesn't use are denied (garmin-unused-tools.txt; regenerate it if the server adds tools). See claude-tooling. On a usage-limit rejection, parses "resets H:MMam", sleeps, retries until the deadline.
  4. Writes .last-output-<mode>.json, last-run-<mode>.json, appends to training-sync.log.

Test by hand in the foreground (background Bash gets killed by the memory supervisor here: it reads free, ~300 MB on this box because qbittorrent + page cache hold ~11 GB reclaimable; dmesg is clean, cron is unaffected). Match adaptive-plan workouts by name + sport + duration; uuids change overnight.

Rules the passes carry (in _shared-facts.md, not here)

  • Swim placement (2026-09-10): weekday swims 11:30-12:30 at Millbrook Exchange Pool (1911 Spring Forest Rd, Raleigh NC 27615) with location + 🚗 title prefix; the Tesla pre-cool reads the personal calendar and fires 11:15 and 12:15. Only swims carry 🚗 from the coach plan.
  • Car-trip tagging (2026-09-10): the passes may prefix 🚗 onto non-managed events matching BARBERSHOP/MARACO/D&D (haircut, Thu 11:30, D&D Luxury Barbershop, 1648 N Market Dr Ste B, Raleigh NC 27609). No other write to non-managed events is allowed. Pre-cool side: projects/tesla-automation.md.
  • Dated overrides in _shared-facts.md: delete the block when its date passes. The race-week override (practice sprint tri, 2026-09-13) was removed 2026-10-19; backup was /tmp/_shared-facts.backup-20261019.md (not kept).

Log

  • 2026-09-04: set up. 2026-09-05: wrapper hardened (usage-limit parse and sleep); a 06:10 morning pass hit the 5-hour session limit (Max 5x, overage off, no API key) because phone/web use consumed the window, since nothing else on the box runs 03:45-06:10. Prompt backups: ~/.claude/routines/backup-2026-09-05/, -09-08/, -09-10/.
  • Race-week Garmin workouts (Tue tempo 1692355492, Sat shakeout 1692392517 + 1692392581, Sun multisport practice 1693043006 with per-section speed/cadence) and the Sandling bike courses: see projects/routes.md.

If you change this

  • Hits: the three prompt files and _shared-facts.md · the deadlines · the phone's Shortcuts automation (event title "Early wake") · the 5-hour usage window shared with interactive use.
  • Does not hit: anything on the array or in the docker stack except garmin-mcp-server.

See

  • Objects: garmin-mcp, claude-tooling
  • Memory: garmin-calendar-morning-routine.md, angel-training-schedule-constraints.md
  • Source: ~/.local/bin/training-sync · ~/.claude/routines/