What We Shipped
Workout Recap — Rebuilt from the Ground Up
Today was basically a full day of iterating on AI workout recap quality. The results are meaningfully better.
Structured output. Switched the recap from free-form text generation to generateObject with a typed JSON schema. This fixed a persistent bug where goal_impact was getting lost or malformed — structured generation enforces the shape, so the field actually arrives.
Plan context + coaching flag. The recap prompt now receives the athlete's active training plan context and a coaching_flag that signals whether there's something the coach should follow up on. Recaps went from "here's what you did" to "here's what you did and why it matters for your training."
Better lap analysis. The system now sends up to 40 laps to the AI (previously hardcapped at 12 — way too low for interval sessions). Mile splits are preferred over manual laps when they're more granular. The prompt now detects mid-run tempo blocks, uses proper mile labels for running laps, and ignores warmup/cooldown noise so the key effort leads the recap.
Prompt discipline. Several prompt fixes: distance in miles for running, a mileage cap constraint (KEY_EFFORT_MILES now lives in the CONSTRAINT block where the rules reference it), and a strict --- separator between recap and coaching note. The AI now always leads with the key effort, not the warmup.
Stale recap regeneration. If a recap was generated before lap data was available and the summary literally says "no lap data" — it gets regenerated automatically. Also fixed: goal_impact is now fetched even when an ai_recap already exists but the goal impact field is missing.
BYOA Workout Recap Routing
Added a dedicated agent recap endpoint for BYOA (Bring Your Own Agent) setups, with a graceful fallback to the standard recap path. The X-Recap-Secret header is now sent correctly, error logging is in place, and the analyze route's maxDuration was bumped to 60s to stop timeout kills on longer workouts.
Also fixed: post-workout card no longer shows the algorithmic fallback recap when an AI recap is available or in-flight. It always shows the AI version.
AI Coach Mobile UX
A cluster of mobile UX fixes across the AI coach interface:
- Chat input discoverability — input is now more prominent on mobile so first-time users don't miss it
- Suggested prompts — reduced from cluttered to 4 focused shortcuts, labeled clearly as optional, and moved above the textarea where they're more scannable
- Pull-to-refresh hijacking — two separate fixes:
overscroll-behavior-y: containon the scroll container, anddata-vaul-no-dragon the chat scroll area to stop the bottom sheet from intercepting scroll events - AI suggestion toast — swipe-up-to-dismiss works again; tap-to-dismiss is persistently dismissable (was resetting on re-render)
Body Composition in Health Metrics
Added a body composition section to HealthMetricsCard, surfacing weight, body fat %, and related metrics alongside the existing training load data.
Share + PWA Polish
- Removed the intervals table from the shareable workout card — cleaner, less noise for non-athletes viewing a share link
- "Back to Flow State" button now shows on mobile share page (was desktop-only)
- Service worker bumped to v3 with network-first strategy for JS bundles — fixes stale cache issues after deploys
- AI suggested workouts now appear on the mobile calendar view (were silently missing)
- Falsy zero bug fixed: weekly mileage of
0(valid for absolute beginners) was being treated as missing
Heavy day. The recap work alone touched a dozen commits but the output is noticeably better — structured, plan-aware, and actually showing goal_impact consistently. That's the kind of thing athletes notice without knowing why.