The handbook

How Coach Cadence works.

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.

01 · The map

Three components, one quiet
conversation.

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.

Your WhatsApp
Strava
01Bridge

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
talks to Your WhatsApp
02Brain

The Agent

The coach. Reads everything, decides what to say.

  • Assembles context from every available source
  • Reasons with an LLM, calls tools when it needs them
  • Holds the plan, the memory, and the athlete card
talks to Claude · Anthropic
03Memory

Strava Data Layer

Connects Strava, remembers every ride.

  • Handles OAuth, refreshes tokens, syncs new rides
  • Normalises rides into structured data, power, HR, GPS
  • Computes weekly trends, load, consistency, volume
talks to Strava
events flow both ways →
The event busPersistent · deterministic · replayable

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.

component we builtexternal serviceevent name
02 · One message, end-to-end

What happens when you tap send.

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.

  1. 0100:00
    You

    You send a voice note.

    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.

  2. 02+200ms
    Bridgemessage.received

    We receive, persist, and tick.

    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.

  3. 03+10s
    Bridgeturn.ready

    We wait for you to finish.

    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.

  4. 04+10.1s
    Agent

    Voice becomes text.

    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.

  5. 05+10.5s
    Agentactivities.listrollups.current

    The coach assembles context.

    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.

  6. 06+12s
    Agent

    The LLM reasons.

    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.

  7. 07+13s
    Agentsend.requested

    It decides how to reply.

    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.

  8. 08+13.5s
    Bridgechunk.sentturn.delivered

    We send the reply, in order.

    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.

  9. 09+14s
    Agentagent_turn.completed

    It remembers what matters.

    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.

In plain English

"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."

03 · Section one

The post office.
A dumb pipe with promises.

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.

Inbound

What happens when you message the coach.

Read left to right →
  1. 1step

    Message arrives

    Text, voice, image, location, document.

  2. 2step

    Save & download

    Stored in our database. Media files pulled and saved.

  3. 3step

    Blue tick fires

    Immediately. Not a promise to reply, a promise we received it.

  4. 4step

    Wait for silence

    10s of no new messages (or 45s max). Lets you finish your thought.

  5. 5step

    Hand off as a turn

    Bundle everything into one turn.ready event. Coach takes it from here.

Why we wait

Batching keeps replies sane.

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.

Outbound

What happens when the coach replies.

Each reply is sent piece-by-piece.

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.

textMorning. Yesterday's block looked clean.1.5s pause
textToday: recovery, 60 mins zone 1.1.5s pause
image🖼️ Weekly plan chart1.5s pause
document📄 route-90min-z2.gpxdone

What happens if it fails, or you message back.

  • Retry on failureEach chunk retries up to 3 times with exponential backoff (2s, 4s, 8s).
  • Stop on partial failureIf a chunk fails permanently, we abandon the rest. Partial replies are worse than no reply.
  • You messaged back mid-replyThe bridge stops sending. Your new message wins. The coach starts a new turn.
  • Crash recoveryDurable workflows mean a crashed delivery resumes from the chunk it was on.

What you can send.

Inbound media types
TypeWhat it isHow we handle it
💬TextStandard messages.Passed through as-is.
🎙️Voice notesHold-to-record messages.Downloaded, transcribed before the coach sees them.
🖼️ImagesPhotos and screenshots.Downloaded. The coach reads them with vision.
📍LocationsPin drops.Coordinates extracted. Used for routes and weather.
📄DocumentsPDFs and GPX route files.Downloaded. GPX summarised. PDFs read as text.
🎞️VideoRecorded clips.Acknowledged honestly, not processed.
👍ReactionsEmoji on a message.Logged. Doesn't trigger a reply.
What the bridge owns
  • · Receiving every inbound message reliably
  • · Persisting before acknowledging
  • · Batching rapid messages into turns
  • · Delivering replies in order, with retry
  • · Sending blue ticks immediately
  • · Monitoring its own health
What it deliberately doesn't do
  • · Read the contents of your messages
  • · Transcribe voice or understand images (that's the agent's job)
  • · Decide whether to reply
  • · Filter or moderate content
  • · Call Strava or any other service
  • · Hold any coaching logic at all
04 · Section two

The training memory.
Every ride, structured.

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.

Data tiers

The coach works at any gear level.

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.

1tier

GPS only

What every Strava ride has.

You have
  • Distance
  • Duration
  • Elevation gain
  • Average speed
Load score

Load score is estimated from duration and elevation.

"The coach speaks in plain terms, "you rode about 2 hours with solid climbing", rather than quoting numbers it can't reliably compute."
2tier

GPS + Heart Rate

Most cyclists who track training.

You have
  • Everything in Tier 1
  • Average HR, max HR
  • Strava Relative Effort
  • HR zone time (if set up)
Load score

Load score uses hrTSS, more accurate than estimation.

"The coach can talk about effort, drift, and zones with confidence."
3tier

GPS + Power meter

Riders training to numbers.

You have
  • Everything in Tier 2
  • Average power, normalised power
  • Power zone distribution
  • If FTP known: TSS, IF, kJ
Load score

Load score is true TSS, comparable to anything you've seen before.

"The coach can prescribe to watts. "Today: 3×15 at 92% of threshold.""
Important

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.

Connection lifecycle

From OAuth to every-day sync.

  1. Day 1

    Connect

    You tap the OAuth link the coach sends. Strava asks if it's OK to share. We get tokens, save them.

  2. Minutes 1-30

    Backfill

    We pull the last 6 months of rides, page by page. Rate-limited, resumable, idempotent. You'll see backfill progress in chat.

  3. Forever

    Live sync

    Strava pings us when you upload a ride. We fetch the details, normalise, and emit an activity event for the coach.

  4. Daily safety net

    Polling fallback

    Webhooks fail silently more often than they should. Once a day per athlete we poll for anything the webhook missed.

What we measure (and what we'll never fake).

Rollup metrics
📊

Per-ride load

A single comparable number per ride, TSS, hrTSS, or estimated, so we can talk about "a hard week" with one consistent yardstick.

📅

Weekly volume

Hours, distance, elevation gained, always available, even on Tier 1.

⚖️

Weekly load

Total stress for the week. Comparable week-to-week within your own data.

📈

Load trend

This week's load ÷ trailing 4-week average. Tells the coach if you're ramping, holding, or tapering.

🎯

Consistency

Sessions per week over the last 4 weeks. Often a better predictor than load.

🗺️

Training patterns

Which days you ride, how long, what time of day. Inferred from history, not asked at setup.

Honesty principle

"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."

Home base

Where you ride from, inferred.

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.

Idempotent everything

Duplicate webhooks? No problem.

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.

05 · Section three

The coaching brain.
An LLM with a great desk.

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.

Context assembly

What the coach sees, every turn.

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.

The desk→ to the LLM

Athlete card

Profile

Who you are, goals, FTP, weight, availability, timezone, notes you've shared.

Recent activities

From Strava

Your last ~30 rides, each formatted as compact text, date, type, duration, HR, power, load.

Rollup metrics

Derived

Weekly volume, weekly load, load trend, consistency. The shape of your training right now.

Current plan

Agent state

Where you are in your training, phase, week, today's session and the reason it exists.

Relevant memories

Vector search

Things the coach remembered: "sensitive knees in cold", "hates the turbo", "target weight 72kg".

Conversation history

Bridge data

The last few exchanges. Enough for continuity, not the whole archive.

Today's message

From bridge

Your most recent turn, text, transcribed voice, image descriptions, location.

~30
rides on the tray
formatted, compact text
~2k
tokens for context
enough but not bloated
0
hallucinated numbers
absence over invention
Tools

The coach's hands.

The agent can do things, not just say things. Each tool is a well-defined action with predictable inputs and outputs.

💭

Memory

Recall, search, save, update what matters about you.

📚

Strava data

Pull recent rides, a specific activity, segment history.

🗓️

Plan

Build, read, adjust the training plan at any of 4 levels.

🪪

Athlete card

Read and update your profile, goals, FTP, weight.

🌤️

Weather

Forecast for a date and your home base.

🗺️

Routes

Generate cycling routes. Google Maps link, image, or GPX.

📈

Charts

Deterministic charts of your real numbers, no model hallucination.

🎨

Image generation

Visuals for plans, summaries, illustrations.

🔍

Web search

Look up event details, race entries, coaching references.

Plan structure

Four levels, like a real coach.

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.

Plan

12-32 weeks

The whole programme toward a goal. Worked backwards from your event date.

Phase

3-16 weeks

A training block with a single focus. Base → Build → Peak → Transition, always in that order.

BaseBuildPeak/TaperTransition

Week

7 days

A microcycle. Either a loading week (progressive stress) or a recovery week.

MonOff
TueSweet spot
WedRecovery
ThuThreshold
FriEasy
SatLong
SunOff

Session

1 ride

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.

Near-term: detailed

This week and next are filled in session-by-session. The coach generates them based on how you're actually responding.

Long-term: directional

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.

How it replies

Six ways to respond.

The coach picks the format that fits the moment. Sometimes silence is the right answer.

💬

Text

Chunked for WhatsApp readability. The default response.

🖼️

Image

Charts, plan calendars, or illustrative visuals.

📎

Document

GPX files. PDFs of plans. Bike-computer-ready.

👊

Reaction

An emoji on your message. No text. Acknowledgement without noise.

🧩

Combined

Text + image, or text + document.

🔇

Silence

A deliberate non-reply. The blue tick still fires.

Memory

What gets remembered, and when.

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.

Example memories
  • · preference: Hates the turbo. Prefers outdoor unless raining hard.
  • · constraint: Sensitive knees in cold weather.
  • · fact: Working toward sub-3 at Mallorca 312, April 2026.
  • · context: Lives in NW London, rides from Regent's Park most days.
Proactive coaching

When the coach messages first.

The agent doesn't just wait for you. It can message proactively based on three kinds of triggers:

  • Activity events

    You finished a ride. The coach might react with 👊, or write a debrief, or stay silent.

  • Rollup changes

    Your load trend crossed a threshold worth mentioning, ramping too fast, or backing off when you shouldn't be.

  • Schedule ticks

    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."

06 · How it fits together

The event bus, named.

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.

BridgeAgent

Inbound messages and delivery feedback.

  • message.receivedA new message landed. Used by the agent to abort proactive turns mid-flight.
  • turn.readyYour batched message is closed, the agent can start reasoning.
  • turn.supersededYou messaged again before the coach finished replying. Cancel the in-flight turn.
  • chunk.sent / turn.deliveredConfirmation that an outbound chunk or full turn was delivered.
  • chunk.failed / turn.send_failedA chunk exhausted its retries; remaining items abandoned.
StravaAgent

Connection state and ride activity.

  • athlete.connectedOAuth completed. The agent seeds the athlete card from the synced Strava profile.
  • athlete.disconnectedYou revoked access, or tokens went invalid. The agent decides whether to message about it.
  • backfill.completedHistorical rides are loaded, the agent has enough to start onboarding properly.
  • activity.createdA new ride synced. The agent decides whether to debrief, recognise, or stay silent.
  • rollups.recomputedWeekly trends changed. Maybe worth a proactive message, maybe not.
  • segment_effort.recordedYou just set a PR on a segment. Recognition opportunity.
AgentBridge

Commands to send messages.

  • send.requested (reactive)Reply to an inbound turn, text, image, document, or reaction.
  • send.requested (proactive)Coach-initiated message with no inbound turn to anchor to.
  • reaction.requestedStandalone reaction on a specific message. No reply, just an emoji.
AgentStrava

Read-only queries.

  • activities.listRecent rides for the athlete, optional filters.
  • activities.getFull detail of a specific ride.
  • rollups.currentCurrent week + trailing 4-week metrics, plus training patterns.
  • segment_efforts.listSegment history for goal-setting and PR recognition.
  • connection.getConnection state, tier, timezone, home base.
Deterministic IDs

Each event ID is derived from its content. Replay-safe by design.

Persisted first

Events are stored before they fire. Crashes can't lose state.

Idempotent handlers

Processing the same event twice produces the same result, not double-work.

Loosely coupled

A new consumer can listen to an existing event without touching the producer.

07 · Glossary

Every term we use, in plain
English.

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.

Physiology7 terms
FTPFunctional Threshold Power
The highest power (in watts) you can sustain for about an hour. The reference number every power-based session is calibrated against.
VO2 max
The maximum rate at which your body can use oxygen. The hardest, shortest interval work targets this.
HR Zones
Heart rate ranges from easy (Z1) to maximal (Z5+). Calibrated against your max HR or threshold HR.
Sweet spot
An effort just below threshold, around 88-94% of FTP. The sweet spot between manageable and stimulating. Big returns for the fatigue cost.
Threshold
Riding at or very near your FTP. Hard but sustainable for 20-60 minute efforts. Where you raise the ceiling.
Tempo
A solid steady effort below threshold, 76-87% of FTP. Comfortably uncomfortable.
Cadence
Pedalling speed in revolutions per minute (RPM). Higher cadence is easier on the legs, harder on the heart. ~90 rpm is typical.
Numbers & metrics7 terms
TSSTraining Stress Score
A single number per ride that captures intensity × duration. 100 TSS = a one-hour effort at threshold. Requires a power meter and FTP.
hrTSSHeart-rate TSS
TSS computed from heart rate data instead of power. Less precise but useful when there's no power meter.
IFIntensity Factor
The ratio between the normalised power of a ride and your FTP. 1.0 = exactly at threshold. A two-hour ride at 0.85 IF was an honest day.
Load
Generic term for training stress, regardless of tier. We use TSS, hrTSS, or duration-and-elevation estimation, whichever your data supports, and call it your load.
Load trend
This week's load divided by your trailing 4-week average. Above 1.1 = ramping. 0.9-1.1 = steady. Below 0.9 = tapering or resting.
Consistency
Average sessions per week over the last 4 weeks. Often a stronger predictor of progress than any single hard ride.
Relative Effort
Strava's perceived-effort score, mostly HR-based. Useful as a fallback when we can't compute TSS or hrTSS.
Plan structure7 terms
Periodisation
Structuring training into phases with different focuses, so you peak at the right time. Base → Build → Peak → Transition.
Base phase
Aerobic foundation. Lots of low-intensity volume. Where you build the engine before adding intensity.
Build phase
Intensity arrives, sweet spot, threshold, VO2. Volume drops to protect session quality.
Peak / Taper
Volume cuts sharply, short sharp efforts preserve race sharpness. Used in the final 1-3 weeks before a goal event.
Transition phase
Unstructured. Recovery. No intervals. The off-season between training blocks.
3:1 loading
Three weeks of progressive stress, then one recovery week. The most common loading rhythm for amateur cyclists.
Microcycle
A single week's worth of training. Usually built around hard-easy alternation with 48-72 hours between intense sessions.
How the system speaks5 terms
Event bus
The shared message board between our three components. They never call each other directly, they emit events and the right consumer picks them up.
Turn
A batch of inbound messages from you that the coach treats as one thought. Closed when you've been silent for 10 seconds (or 45 seconds total).
Rollup
A pre-computed summary of your training over a window, a week, the last four weeks. Recomputed whenever a ride changes.
Memory
Anything the coach has decided is worth remembering about you across conversations. Typed, audited, retrievable.
Tier
How much data your rides have. Tier 1 = GPS only. Tier 2 = GPS + HR. Tier 3 = GPS + power. We pick yours from the dominant data type across recent rides.
End of the handbook

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.

07 · Ride with us

Open the chat.
Say hello.

The whole onboarding happens in the message. Tell the coach who you are and what you're chasing. It'll take it from there.

Message the coach on WhatsApp+44 7745 253345 · Free during alpha