ftp
Skill0 starsChanged 24 days agoMITView on GitHub
Estimate a cyclist's FTP (functional threshold power) from their recent Strava rides, no ramp test needed. Reads best 3, 5, 10, 20, 30 and 60 minute power over the last 42 and 84 days through Strava's official Claude connector, then gives one FTP number with a range, the rides behind it, and sanity checks (95% of best 20 min, a 2-parameter critical power fit, long steady efforts as a floor). Read-only. Use for /ftp, 'what's my FTP', 'estimate my FTP from my rides', 'is my FTP still right', 'should I change my FTP', or after a hard ride. Needs a Strava account with a power meter and the official Strava connector.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- jurapascal/claude-code-hubtheir own version, first seen Oct 20, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- jurapascal/claude-code-hub★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 2 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 12
Read-only: Use only Strava's read tools: list_activities, get_activity_performance, get_athlete_profile, get_athlete_zones.
- Distinctive: line 17
Don't guess numbers: Every watt in the input file comes from a tool result.
- Very specific: line 24
Look for Strava's tools (list_activities, get_activity_performance).
- Very specific: line 31
Call list_activities with range_start = today minus 84 days (YYYY-MM-DDT00:00:00), range_end = today (YYYY-MM-DDT23:59:59), first: 100, …
- Very specific: line 35
Keep sport_type Ride, GravelRide, MountainBikeRide and VirtualRide.
- Very specific: line 39
If more than about 40 rides are left, read only the last 42 days and set "windows": [42] in the input file.
- Very specific: line 45
Call get_activity_performance for each kept ride.
- Very specific: line 64
Follow examples/example-input.json in this skill's folder:
- Very specific: line 88
Add --out <file.md> to save the report, or --json for the raw numbers.
- Very specific: line 91
If it exits with "These best efforts can't all be right", a value was copied wrong (a longer duration came out higher than a shorter one it …
- Distinctive: line 115
If they want a sharper number without a ramp test: one evenly paced, hard 20 to 30 minute effort, ideally on a steady climb.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
FTP from Strava rides
Estimates FTP from rides the user has already done. No ramp test, no new workout.
Rules
- Read-only. Use only Strava's read tools:
list_activities,get_activity_performance,get_athlete_profile,get_athlete_zones. Never change FTP or anything else in Strava or any other app. Give the user the number; they enter it where they want it. - Never use Strava's own FTP estimate as an input. Show the FTP stored in Strava for comparison only.
- Don't guess numbers. Every watt in the input file comes from a tool result. If a value is missing, leave it out.
- The rides are the user's personal data. Keep the input file in a temporary or scratch folder, and don't share it anywhere.
Step 0: is the Strava connector there?
Look for Strava's tools (list_activities, get_activity_performance). Depending on the app
they may carry a prefix, such as <something>__list_activities. If they aren't available,
stop and tell the user: "Connect Strava's official connector in Claude (Settings, Connectors,
Strava), turn it on for this chat, then run /ftp again."
Step 1: list the rides
Call list_activities with range_start = today minus 84 days (YYYY-MM-DDT00:00:00),
range_end = today (YYYY-MM-DDT23:59:59), first: 100, include_tags: true. Follow
has_next_page until done.
Keep sport_type Ride, GravelRide, MountainBikeRide and VirtualRide. Drop e-bikes, runs,
walks, strength and generic "Workout" entries. Drop rides with moving_time under 180 seconds.
is_trainer: true means indoor.
If more than about 40 rides are left, read only the last 42 days and set "windows": [42] in
the input file. Each performance answer is 2 to 10 KB, and the 42-day window is the one that
sets the number.
Step 2: read each ride's best efforts
Call get_activity_performance for each kept ride. For each one record:
has_device_watts. If false, the ride has no power meter: add it with"has_power": falseand no values.- From
best_efforts, thevalueofGreatestPower3min,GreatestPower5min,GreatestPower10min,GreatestPower20min,GreatestPower30minandGreatestPower1hr, as"3","5","10","20","30","60". Skip any the ride doesn't have. - From
segment_efforts, any effort withmoving_timeof 3000 seconds (50 minutes) or more, as{"name", "minutes": moving_time / 60, "watts": avg_watts}. A long, steady climb is the best floor for FTP there is.
Strava's per-ride best efforts agree with a second-by-second recomputation of the power stream to within about 1 W, so there's no need to pull streams.
Optional extras: get_athlete_profile gives weight (kg) for W/kg. get_athlete_zones
gives the FTP stored in Strava and ftp_is_estimated.
Step 3: write the input file
Follow examples/example-input.json in this skill's folder:
{
"as_of": "YYYY-MM-DD",
"windows": [42, 84],
"weight_kg": 70,
"current_ftp": {"watts": 240, "estimated": false},
"rides": [
{"date": "YYYY-MM-DD", "name": "ride name", "indoor": false, "has_power": true,
"best": {"3": 330, "5": 318, "10": 296, "20": 272, "30": 262, "60": 248},
"long_efforts": [{"name": "segment name", "minutes": 56, "watts": 250}]}
]
}as_of is today. Dates are the ride's local start date.
Step 4: run the math
python3 <this skill's folder>/scripts/ftp_calc.py <input.json>Add --out <file.md> to save the report, or --json for the raw numbers. Standard library
only; it runs anywhere Python 3.9+ does.
If it exits with "These best efforts can't all be right", a value was copied wrong (a longer
duration came out higher than a shorter one it contains). Re-read that ride's
get_activity_performance and fix the file. Don't edit numbers to make the check pass.
What the script does
- Best power per duration across each window.
- Two primary estimates: 95% of the best 20 minutes, and a 2-parameter critical power fit (work against time, least squares) on the 3, 5, 10 and 20 minute bests.
- One sensitivity estimate: the same critical power model fit as power against 1/time. It leans on short efforts and usually reads higher, so it only sets the top of the range.
- Floors: the best 60 minutes, and the hardest steady effort of 50 minutes or more.
- FTP = median of the 42-day primary estimates, rounded to 5 W. Range = the higher of the floor and the lowest estimate, up to the highest estimate.
- Sanity ratios: 20 min / 5 min is typically 0.85 to 0.88, and 60 min / 20 min 0.90 to 0.95. Outside those bands, one of the efforts probably wasn't all-out, and the report says which estimate to trust.
Step 5: tell the user
Lead with the FTP and range. Name the rides behind the 5, 20 and 60 minute bests and the long effort floor. If Strava's stored FTP is 5 W or more away, say so; changing it is the user's call. Mention any indoor bests (trainer power can read differently from a power meter).
If they want a sharper number without a ramp test: one evenly paced, hard 20 to 30 minute effort, ideally on a steady climb. 95% of a true 20-minute effort, or the full 30-minute average, beats any model.
Limits
- Needs a power meter or smart trainer. Strava's estimated watts are not used.
- Bests set late in long rides understate fresh power, so the estimate leans conservative.
- It's an estimate from riding data, not a lab test.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

