How it's built · an agentic project ·
August 2026
A personal fitness dashboard, built and run by an AI agent
This dashboard runs without supervision. It syncs on its own schedule, publishes a reading visitors can trust, and says plainly when that reading has gone stale. A health check on the live data path is the one step still run by hand, as the last step of a deploy. Six controls got it there. Take them in order if you can, though each one is worth having on its own. The same shape works for Oura, Garmin, or Apple Health as well as it does for WHOOP.
Field note
This site's data went 21 days without updating, from 20 May to 10 June 2026, before anyone noticed. The system was checking the numbers it produced and never the pipeline producing them, so a dead credential looked exactly like a quiet stretch of training. Fixing the credential fixed the data. The three weeks of not knowing are why step five exists. A dashboard that stops updating is worse than one that was never built, because at a glance it still looks trustworthy.
- 01 Tools & governance
- 02 Connect the data
- 03 Sync efficiently
- 04 Publish, don't depend
- 05 Health check
- 06 Ordinary infrastructure
- Build your own
- Field notes
01Choose the right tool for each task, and calibrate the model to the stakes
Decisions get made in chat: which metrics matter, how a daily recommendation should read, whether a page like this one is worth writing at all. Building happens in the terminal. The sync fix, the test suite, and the smoke test were all written there across a run of Claude Code sessions, with every deploy reviewed before it went out. Cowork does the day-to-day maintenance, working straight on files and a browser, and it produced this page without a terminal ever opening. Scheduled tasks cover whatever should be watched without a person asking. One of them sat dormant for weeks checking whether WHOOP had published pro-athlete data yet; the day it had, that became the pro-athlete snapshot on the dashboard, and the task was retired. The daily data refresh is not one of these: it runs as a cron job on the hosting side, with no Claude session involved.
Chat
Decide
- Which metrics matter
- Drafting text like this page
Terminal
Build
- Claude Code sessions
- Wrote the sync fix & tests
- Owner reviews deploys
Cowork
Maintain
- Files & a browser
- Commits to GitHub
- Built this page
Scheduled tasks
Repeat
- Quarterly design review
Left to right: decided in chat, built in the terminal, maintained in Cowork, then repeated on a schedule.
Mode settles where the work happens. Which version of Claude does it is a separate call, and the habit worth building is matching strength to stakes instead of reaching for the biggest model every time. Routine, unsupervised work runs on the fastest and cheapest version. Ordinary building work gets the standard one. When a mistake would be expensive to undo, the strongest version available is the cheap option. This page was written on a version tuned for prose.
02Connect the data, and keep the login out of the browser's reach
Signing in to WHOOP happens once, handled entirely by a small piece of code that runs on the server, never inside the browser. That code manages every data request after that, so the actual login credentials are never exposed to anything running in a browser tab. Enforce this one without exception, whichever wearable you connect.
03Keep syncing fast, and don't let a login refresh collide with it
An early version of this sync asked WHOOP for recovery one day at a time, close to 180 small requests on top of everything else a refresh already pulled, slow enough that it occasionally dropped the connection mid-sync. Two fixes resolved it: pulling recovery as one paginated collection instead, which brings a full refresh down to about 30 requests, and making sure the login was confirmed valid before firing the rest all at once, so a login quietly expiring mid-sync couldn't corrupt the update.
04Publish a snapshot; don't make visitors dependent on a live call
Visitors never query WHOOP directly. A small storage layer holds the most recently published reading, and that is the only source the page reads from. If a sync fails or a credential needs attention, visitors still see the last verified reading, clearly labeled with its age, rather than a broken page. Refreshing that reading on demand doesn't require authentication either: a plain Refresh control on the page triggers the same pull, throttled server-side so repeated requests cannot exhaust the API's rate limit. One open gap: there is no dated history of prior snapshots, so a genuinely corrupted sync could still overwrite the one verified copy with nothing to restore from.
05Build a health check that only observes
The check confirms the live data pipeline is actually healthy and current, not merely that the deploy completed. It is one command, run by hand after deploying; nothing runs it on a schedule. It has no authority to remediate anything, only to report clearly when something is wrong. This is the control the 21-day gap described above was missing: a failed sync went undetected because the system was verifying the output, not the pipeline producing it.
06Keep the infrastructure simple
Ordinary GitHub repository. Push is the whole deploy. Netlify rebuilds in under a minute, handles the WHOOP sign-in and the sync, and holds the snapshot visitors see. A docs-only change skips a rebuild entirely, so a free tier's rebuild budget goes to changes visitors actually see. The diagram below is the whole system.
Build your own · a starting point · August 2026
Build one for yourself
This entire site started from one written request to Claude, then grew in stages: a live sync, a real domain, a health check, every irreversible step held for approval along the way. Below is a version of that starting request. Copy it, adapt it to your own wearable or data source, and paste it into a new Claude conversation.
I want to build a personal fitness dashboard that reads my real recovery, sleep, and training data automatically from my wearable's app (WHOOP, Oura, Garmin, Apple Health, whichever I actually use). Here's the pattern I want it to follow: 1. Connect to my wearable's data through its official API, with my login handled securely on the server side and never exposed anywhere in the browser. 2. Publish a small, real website I can bookmark and check from my phone, showing my latest numbers. No login needed for me to view it day to day. 3. Sync on a schedule so it's never more than a day stale, without me having to ask. 4. Keep a plain Refresh button on the page for me to trigger a check on demand. 5. Build in a health check I can run after every update, which tells me clearly if the data pipeline itself is broken, not just whether the numbers on screen look reasonable. 6. Be honest about the age of what I'm looking at: always show when a reading was last confirmed, rather than silently going stale. Please help me scope this into a first small version we can finish today, tell me exactly what you'd need from me at each step (any account access, any purchase like a domain name, anything you can't do without my say-so), and don't do anything irreversible without checking with me first.
All of this runs inside Cowork, out of one project folder Claude keeps on your behalf. Alongside the code and the data sits a file called CLAUDE.md: Claude's own running notes on how the system works, what has already been decided, what's still open, and which mistakes not to repeat. Every new session reads that folder before it does anything else, then writes its notes back before it ends. You never re-explain the project.
Worth knowing before you start
Build in a health check from day one. It's the cheapest insurance you can add to a project like this, and far easier to set up before you need it than after. This exact dashboard's own check has already caught a stale data feed early more than once, instead of it going unnoticed for days.
Field notes
What running this system took
The sync bug in step 03 was misdiagnosed twice, first as a missing permission and then as a login that wasn't saving between sessions. Reading the code found it. Guessing from the symptoms never would have.
Credentials stay with the person. They get generated and rotated inside WHOOP's own account settings, and any one that has been exposed even once is replaced rather than reused. None of them pass through a chat conversation.
Compare only what both sides actually measure. Resting heart rate and weekly session count sit side by side in the pro-athlete snapshot because this dashboard has both. Everything else is labeled as sourced context.