WhatsApp Bridge
Moves messages in and out. Doesn't read them.
- Receives & batches your messages into turns
- Sends the coach's replies, chunk by chunk
- Sends blue ticks the moment we receive you
Three quiet components doing different jobs, talking through a shared event bus. No magic, no black box, just careful engineering held together by a coaching agent that knows what to say.
You can read this in 10 minutes. The diagrams do most of the talking.
Each component does one thing well. None of them call each other directly, they leave little notes on a shared message board (the "event bus") and the right component picks them up. This is what keeps the system simple to reason about.
Moves messages in and out. Doesn't read them.
The coach. Reads everything, decides what to say.
Connects Strava, remembers every ride.
Every event has a unique ID, gets persisted before it fires, and can be replayed. Components never call each other directly. That means a slow response, a deploy, or a crash in one section doesn't bring the others down, work just resumes from the last event when things come back.
14 seconds, 9 stages, 3 components. Most of it is invisible to you, that's the point. Read this once and you'll see how everything else in this guide fits together.
Tap-and-hold in WhatsApp, say what's on your mind, release. "Knees a bit cranky after yesterday, should I still ride today?" The voice note goes off to Meta's servers like any other WhatsApp message.
The bridge sees the voice note via its always-on WhatsApp connection. It downloads the audio, saves it, and sends you a blue tick. The blue tick fires regardless of whether the coach replies, that's a promise about acknowledgement, not response.
Maybe you fire off three quick messages in a row. The bridge batches them into one logical "turn", it waits 10 seconds of silence (or 45 seconds total) before deciding you're done. That way the coach replies to your whole thought, not each sentence.
Before the coach reads anything, your voice note gets transcribed (Deepgram). The coach only ever sees text, but it knows it came from voice, which can soften the tone of the reply.
Your athlete card (FTP, goals, schedule). Last 30 rides, formatted as compact text blocks. Current rollup metrics. Your current training plan. Relevant memories. Recent conversation. All of it, on a tray, ready for the LLM.
Claude reads the whole tray and decides what to do. It might call a tool, check the weather, generate a chart, query a specific past ride. It might decide to react with an emoji and say nothing. It might write three messages.
Text? Image? Document? Just a 👊 reaction? Or silence? Each option is on the table. For your knees question: a calm two-message reply prescribing recovery, with a check-in if symptoms persist.
The bridge sends each chunk with a small natural pause between them (1.5s) so they don't all land in the same heartbeat. If a new message arrives from you mid-delivery, the bridge stops, your new message takes priority.
After the conversation closes, a smaller, faster model reviews what happened and extracts anything worth remembering. "Sensitive knees in cold weather", that goes into memory. The next time you mention knees, the coach already knows.
"You sent a voice note. We saved it, transcribed it, gave the coach everything it needed to know about you, the coach decided how to reply, and we delivered the reply in your chat. The whole round trip is under 15 seconds, and the coach remembers your cranky knees forever."
The Bridge is the only part of the system that ever touches WhatsApp. Everything inbound comes through it, everything outbound goes out through it. It's deliberately stupid, it never reads your messages or decides what to say. Its job is reliability.
Text, voice, image, location, document.
Stored in our database. Media files pulled and saved.
Immediately. Not a promise to reply, a promise we received it.
10s of no new messages (or 45s max). Lets you finish your thought.
Bundle everything into one turn.ready event. Coach takes it from here.
If you fire off three quick messages ("Hey" / "Quick one" / "Should I ride today?"), we wait until you stop. Then the coach sees all three as a single thought and replies once, properly. You don't get a fragmented conversation where the coach answers before you've finished asking.
The coach might send four messages, an image, and a GPX file. The bridge sends them in order, one at a time, with a small pause between each, so they don't all land in the same heartbeat and feel robotic.
| Type | What it is | How we handle it |
|---|---|---|
| 💬Text | Standard messages. | Passed through as-is. |
| 🎙️Voice notes | Hold-to-record messages. | Downloaded, transcribed before the coach sees them. |
| 🖼️Images | Photos and screenshots. | Downloaded. The coach reads them with vision. |
| 📍Locations | Pin drops. | Coordinates extracted. Used for routes and weather. |
| 📄Documents | PDFs and GPX route files. | Downloaded. GPX summarised. PDFs read as text. |
| 🎞️Video | Recorded clips. | Acknowledged honestly, not processed. |
| 👍Reactions | Emoji on a message. | Logged. Doesn't trigger a reply. |
The data layer connects Strava, stores every ride in a tidy shape, and computes the rollup metrics the coach uses to talk about your training. It doesn't coach. It doesn't decide what to do. It's a librarian.
Power meter? Heart rate strap? Just a phone? It doesn't matter. We figure out what you've got and the coach calibrates how confidently it speaks.
What every Strava ride has.
Load score is estimated from duration and elevation.
Most cyclists who track training.
Load score uses hrTSS, more accurate than estimation.
Riders training to numbers.
Load score is true TSS, comparable to anything you've seen before.
We pick your tier from the dominant data type across your last 8 weeks of rides. If you use power on one bike and not the other, you can still be Tier 3. If your HR strap is dying, we drop you to Tier 1 for those rides, never zero, never faked.
You tap the OAuth link the coach sends. Strava asks if it's OK to share. We get tokens, save them.
We pull the last 6 months of rides, page by page. Rate-limited, resumable, idempotent. You'll see backfill progress in chat.
Strava pings us when you upload a ride. We fetch the details, normalise, and emit an activity event for the coach.
Webhooks fail silently more often than they should. Once a day per athlete we poll for anything the webhook missed.
A single comparable number per ride, TSS, hrTSS, or estimated, so we can talk about "a hard week" with one consistent yardstick.
Hours, distance, elevation gained, always available, even on Tier 1.
Total stress for the week. Comparable week-to-week within your own data.
This week's load ÷ trailing 4-week average. Tells the coach if you're ramping, holding, or tapering.
Sessions per week over the last 4 weeks. Often a better predictor than load.
Which days you ride, how long, what time of day. Inferred from history, not asked at setup.
"If we don't know your FTP, we don't make one up. TSS just isn't computed. The agent sees its absence and talks accordingly. We'd rather show less than show a wrong number."
We cluster your outdoor ride starts over the last 8 weeks. The biggest cluster wins. That's your home base, used by the coach for route generation and weather lookups.
If your rides start from too many different places (you travel), home base is just absent, and the coach can ask you directly.
Every webhook delivery is deduped. Activity persistence is upsert by Strava activity ID. Backfill resumes from the last successful page. Replaying the same event never doubles anything up.
That's why we can be relaxed about retries. Worst case, you waste a few API calls. Worst case is fine.
The agent is the only part of the system that makes coaching decisions. It's an LLM that, on every turn, sits down at a well-organised desk, reads everything laid out for it, then decides how to reply. There is no rules engine. There is no decision tree. Just context, reasoning, and a small set of tools.
Before the LLM reasons about anything, the agent assembles a tray of context from every available source. Nothing is sent in raw, everything is shaped into compact text the model can read fast.
Who you are, goals, FTP, weight, availability, timezone, notes you've shared.
Your last ~30 rides, each formatted as compact text, date, type, duration, HR, power, load.
Weekly volume, weekly load, load trend, consistency. The shape of your training right now.
Where you are in your training, phase, week, today's session and the reason it exists.
Things the coach remembered: "sensitive knees in cold", "hates the turbo", "target weight 72kg".
The last few exchanges. Enough for continuity, not the whole archive.
Your most recent turn, text, transcribed voice, image descriptions, location.
The agent can do things, not just say things. Each tool is a well-defined action with predictable inputs and outputs.
Recall, search, save, update what matters about you.
Pull recent rides, a specific activity, segment history.
Build, read, adjust the training plan at any of 4 levels.
Read and update your profile, goals, FTP, weight.
Forecast for a date and your home base.
Generate cycling routes. Google Maps link, image, or GPX.
Deterministic charts of your real numbers, no model hallucination.
Visuals for plans, summaries, illustrations.
Look up event details, race entries, coaching references.
Plans are detailed near-term, directional long-term. That mirrors how human coaches work, and means your plan adapts week-by-week instead of being a rigid 16-week template.
The whole programme toward a goal. Worked backwards from your event date.
A training block with a single focus. Base → Build → Peak → Transition, always in that order.
A microcycle. Either a loading week (progressive stress) or a recovery week.
A single workout, type, duration, intensity, structure, and why it exists in the plan.
Tuesday, Sweet Spot ×3
15 min easy → 3×15 min at 88-93% FTP, 5 min easy between → 10 min cool-down.
Purpose: build aerobic ceiling without taxing the legs for Thursday's threshold session.
This week and next are filled in session-by-session. The coach generates them based on how you're actually responding.
Future phases are described in shape, "6 weeks of base, then 8 weeks of build", not pre-filled. They get detailed when their time comes.
The coach picks the format that fits the moment. Sometimes silence is the right answer.
Chunked for WhatsApp readability. The default response.
Charts, plan calendars, or illustrative visuals.
GPX files. PDFs of plans. Bike-computer-ready.
An emoji on your message. No text. Acknowledgement without noise.
Text + image, or text + document.
A deliberate non-reply. The blue tick still fires.
After every conversation, a smaller, faster model reviews the exchange and extracts anything worth remembering, preferences, constraints, things you've shared about yourself.
These memories are typed (preference / constraint / fact / context), bi-temporal (we know when something became true and when it changed), and audited. The next conversation pulls the relevant ones in via vector search.
The agent doesn't just wait for you. It can message proactively based on three kinds of triggers:
You finished a ride. The coach might react with 👊, or write a debrief, or stay silent.
Your load trend crossed a threshold worth mentioning, ramping too fast, or backing off when you shouldn't be.
Morning brief on a key training day. Reminder before a planned session.
"Proactive but never noisy. If you tell it to message less, it remembers."
Everything we've described in the last three sections talks through the same shared message board. Each event has a name, a shape, and a single producer. Multiple consumers can react to the same event. Replays are safe.
Inbound messages and delivery feedback.
Connection state and ride activity.
Commands to send messages.
Read-only queries.
Each event ID is derived from its content. Replay-safe by design.
Events are stored before they fire. Crashes can't lose state.
Processing the same event twice produces the same result, not double-work.
A new consumer can listen to an existing event without touching the producer.
You don't need to know any of this to ride well, and you don't need to know any of this to use Coach Cadence. But if you're curious, here's the working vocabulary.
That's the whole machine.
Three quiet components. One shared message board. An LLM that reads everything before it replies, and a small set of tools so it can act, not just talk. That's it.
If a section in here ever doesn't match what the coach actually does, tell the coach. We update both.
The whole onboarding happens in the message. Tell the coach who you are and what you're chasing. It'll take it from there.