Skip to content
← All projects
app production

The workout app that remembers what I lifted last Tuesday

Builds workouts from my real training history and adjusts them to how I actually feel that day.

6 AI features, one for every stage of a training session
  • React
  • Supabase
  • Claude API

Where this could work for other businesses

The obvious one first, quickly: any gym, personal trainer, or boutique studio wants exactly this — a coach that remembers what a client actually lifted last time instead of handing out the same laminated programme to everyone. That’s not the interesting part, though.

Physiotherapy and rehab clinics are a much better fit than they first look. The core mechanic here — take a person’s real history and current constraints, propose something specific, and let a human sign off before anything happens — maps almost exactly onto rehab progression: swap “avoid overhead pressing because of a shoulder” for “stay under this range of motion because of a knee,” and the same proposal-then-approve loop works for a physio programme instead of a hypertrophy block.

Corporate wellness programmes are another real one. The readiness-scaled recommendations and periodic written reviews are, functionally, an engagement mechanic — the difference between a benefit employees open once and one they keep using. Point the same “here’s your week, here’s what to watch” reviewer at step counts and stress check-ins instead of lifting data, and it’s a retention tool for whoever runs the wellness budget.

Strip away the fitness domain entirely and the underlying shape is: take a person’s structured history, accept a plain-English request, propose something specific and reviewable, never act until a human accepts it. That pattern is domain-agnostic. A nutrition coaching app, a running-plan subscription, even a study-plan tool for language learning — anywhere a business already has structured history on a customer and wants to turn “what should I do next” into a specific, personal answer rather than a generic template, this is the mechanism.

The problem

Every workout tracker I’d tried was either a spreadsheet wearing a nicer outfit, or a polished consumer app where my training data is quietly somebody else’s product. Neither one knows anything about me specifically. What did I actually do last week? Which muscles have I been neglecting? Do I have a shoulder that rules out half the exercise library on a given day? None of them combined that into a recommendation that felt personal instead of generic — and my gym doesn’t have every machine anyway, so half of what a generic app suggests isn’t even available to do.

The goal

Send everything the app actually knows about me to an AI before it suggests a session, instead of running me through a template that doesn’t know my shoulder exists.

What it does

The GerFit home screen, showing workout, set, and total-volume counters and a "Start a workout" panel.

Everything starts with an exercise library I control — hundreds of movements tagged with muscles worked, equipment needed, and how the load counts, since a pair of dumbbells isn’t “the same weight” as a barbell. I can add my own via a photo instead of typing anything.

The exercise library, filterable by muscle group, with a thumbnail photo per movement.

A chat-style routine builder is the centrepiece: describe what I want in plain English — muscle group, time budget, equipment I’ve actually got that day, a constraint to work around — and it proposes a full session from my own library, referencing what I’ve actually lifted before. I can talk back to it (“shorter, drop an isolation move”) and it revises in place. Accepting it is one tap.

A list of generated routines, each named for its focus and the training week it belongs to.

Starting a session turns that routine into an active workout screen: a quick readiness check-in nudges the first suggested weight up or down depending on how fresh I feel, and every logged set shows a live estimated one-rep max against my last session and my all-time best. A rest timer runs between sets, and I can bolt on an unplanned exercise mid-session without breaking anything.

Every completed session feeds a history and stats layer: on-demand AI summaries of how a session went, a stats view tracking volume and personal records over time, and a periodic written review that reads more like a coach’s note than a chart. A “visit” ties a lifting session together with anything else that happened that day — a swim, a class, a sauna session — into one combined day-level recap, tracked against any active injury or condition so the recap stays honest about what I’m actually working around:

The classes log, tracking non-weights activity like cycling and sauna sessions alongside lifting.

The training timeline, showing a two-week activity heatmap, active conditions being tracked, and a list of past visits.

The build

Built with Claude Code, and the one rule that shapes everything else: every AI feature proposes, nothing writes. Every single AI call in this app returns a draft, and the client decides whether to save it. There is no code path where a model’s output touches the database directly.

Getting good proposals meant solving a context problem first. The routine builder pulls the full library, recent training history, non-training activity, and a profile of goals and constraints, all fetched in parallel before I’ve finished typing. From that it derives two compact summaries rather than dumping raw history at the model: a muscle-balance readout (what’s had volume recently, and how recently), and a per-exercise recent-performance line. That’s the difference between a model guessing and one reasoning from what actually happened.

The response comes back as schema-constrained structured output rather than free text — a defined shape the client can parse directly, instead of extracting a workout from a paragraph that sometimes reads as a list and sometimes as prose. Every proposed exercise is checked against the real library before anything is shown; anything that doesn’t resolve is silently dropped rather than surfacing an error. And every system prompt carries an explicit instruction to treat whatever I typed as data to read, never as an instruction to follow — a basic, cheap prompt-injection defence worth doing by default.

The same propose-then-approve pattern powers the other five AI features — summarising a workout, interpreting a period of pre-computed stats, reading an exercise out of a photo, recapping a whole day. In every case the client does the arithmetic and the model does the interpretation — sending raw numbers for a model to crunch is slower and less reliable than doing the maths yourself and asking for a sentence about what it means. A periodic review makes the pattern concrete: real computed numbers feeding a written verdict with specific things to watch, not a generic pep talk —

A monthly AI review: a written verdict, highlights, things to watch, and a focus for the coming week.

— and the same shape applies at the single-session level, where a finished workout gets its own written summary rather than just a row of numbers:

A single day's AI visit summary, with a written verdict on the session and a list of specific wins.

Cost is managed with prompt caching on the one genuinely large, stable block of context — the exercise library itself — so that a back-and-forth refinement conversation doesn’t re-pay the full cost of that block on every single turn.

Problems & solutions

Symptom: the first version of the routine builder used free-form text output, and parsing exercises back out of it was fragile — sometimes a list, sometimes prose, sometimes both. Diagnosis: free text is for humans to read, not for code to parse reliably. Fix: switch to schema-constrained output entirely; every response becomes trivially parseable, and the fragile-parsing class of bug disappeared.

Symptom: early proposals were technically fine programmes but felt generic — nothing referenced what I’d actually lifted. Diagnosis: the model wasn’t being given any real history to reason from. Fix: derive and always include the muscle-balance and recent-performance summaries — proposals immediately started referencing real numbers instead of guessing at them.

Symptom: the model occasionally invented a plausible-sounding exercise reference that didn’t exist in my library. Diagnosis: language models are probabilistic; an invented reference was always going to happen eventually. Fix: validate every reference against the real library client-side and silently discard anything that doesn’t resolve — a wrong proposal becomes a smaller proposal, never corrupted data.

Symptom: sending the full exercise library with every message got expensive fast once conversations ran to several turns. Diagnosis: the library is large, but it’s also stable — it doesn’t change mid-conversation. Fix: mark that block for prompt caching, so repeat and refinement calls within the same session read it from cache instead of paying full price every time.

The stack

ComponentWhy
ReactA mobile-first frontend that works from a phone in a gym with patchy signal
SupabaseAuth, a Postgres database with row-level security, and the serverless functions that keep the AI key off the browser entirely
Claude APIEvery AI feature — routine proposals, workout summaries, periodic reviews, and reading exercises out of photos

Results

Writing a session used to mean checking a spreadsheet, remembering what I’d been neglecting, and spending fifteen or twenty minutes building something from a mental template. Now it’s a one-sentence description and a few seconds of waiting, and the result actually reflects what I’ve done rather than a generic plan. The post-workout summaries changed how I use my own history — I went from glancing at logged numbers as a confirmation to reading a specific note on whether to add weight, hold, or ease off next time. The photo-to-exercise feature quietly removed the single biggest piece of friction in maintaining the library: the old path was noting a machine, looking it up later, and typing it in; the new path is a photo and a confirmation tap.

What’s next

Nearer term, an offline-capable workout screen and a proper background notification for the rest timer would fix the two rough edges that show up most in an actual gym with patchy signal and a phone that’s locked in a pocket between sets. Further out, opening this to more than one person means rethinking the cost model properly — real billing, a quota that fails safely instead of open, and per-location equipment profiles so the same app works for a gym chain with different kit at every branch, not just my own gym.