DSL Syntax Guide
Describe an interval session as plain text; VelocityStack finds matching efforts in your rides.
Structure
4x work 3min ±30% @ 90-110%FTP recovery 2min ±50% @ <55%FTP
The first line is the repeat count (optional: without it the steps run once, in order); each other line is a step in the form role value unit [±tolerance%] @ band. Put 6x on its own line further down to repeat the steps below it until a blank line or end; groups can be nested up to 3 levels.
- work | recovery
- — Step role. "work" is the effort you want analysed; "recovery" is the rest between efforts.
- <value><unit>
- — Length of the step. Duration units: h, min, sec (also hr/hrs/hour/hours, mins/minutes and s/secs/seconds; 2h = 120min). Distance units: km, m ("m" is always metres, never minutes). Decimals are allowed (1.5min).
- ±<n>%
- — Optional tolerance (0-100%) on the length when matching the step against an activity. Left out it is ±0%, so "work 15min @ Z3" and "work 15min ±0% @ Z3" are the same. It is separate from the band: a bare target like 50W is still 50W ±5%.
- @ <band>
- — Intensity target (power, speed, heart rate or cadence): a range, an upper/lower bound, or "best".
Bands (the part after @)
90-110%FTP— Range as a percentage of your FTP.<55%FTP— Upper bound only (at most 55% FTP) — typical for recoveries.>80%FTP— Lower bound only (at least 80% FTP).250-300W— Absolute watts range; works without an FTP set. Bounds (<150W, >200W) work too.30-40km/h— Speed range in km/h. Bounds (<20km/h, >45km/h) work too.150-165bpm— Average heart rate range in beats per minute. Bounds (<120bpm, >170bpm) work too.80-90%HRmax— Heart rate as a percentage of the activity's max HR (the recorded max, or the highest value in the HR stream). Bounds work too.95-105%LT2— Power as a percentage of your LT2 (lactate threshold 2) power, taken from the activity's own LT snapshot for its date. Bounds (<100%LT1, >100%LT2) work too. Set LT values in your profile settings; without them the run reports a message.85-100%LT1— Same as above but relative to LT1 power. Use %LT1HR / %LT2HR (e.g. 97-103%LT2HR) for the average heart rate relative to LT1/LT2 heart rate.Z3— A power zone (Z1 to Z6) from your zone settings: Z3, Z2-Z3 (range), <Z2 (below) or >Z4 (above). Zones are built from LT1/LT2 (or estimated from FTP) as stored on the activity; without either the run reports a message.3-3.5W/kg— Power per kilogram of body weight, using the weight valid on the activity's date (set it under body weight in your profile). Bounds (<2W/kg, >4W/kg) work too; a bare target like 3W/kg means 3 W/kg ±5% (stored as 2.85-3.15W/kg). Without a weight the run reports a message.90-100rpm— Average cadence range in rpm. Bounds (<60rpm, >110rpm) work too.best / max— No threshold: find the single highest-average window of that length. On duration steps this means power.best power / best speed— Required for "best"/"max" on distance steps, which have no default metric.
Warm-up, cool-down, sets, multi-step blocks and contiguous steps
6x— A repeat count on its own line (not the first line) starts a repeated group: the steps below it repeat 6 times. The group ends at the next blank line or an "end" line.end— Closes the innermost repeated group, so steps can follow it directly (and a group can contain another group). Groups nest up to 3 levels; a blank line closes all open groups.3 sets of 5x— First line: 3 sets, each with 5 repeats of the block. Reps are numbered within each set.set recovery 5min ±30% @ <55%FTP— Optional, only with sets: the rest searched for between sets (never after the last one). Same syntax as a step, but without then.then work 1min ...— Prefix a step with "then" to make it start exactly where the previous step ended (over-unders, pyramids, ramps). Not allowed on the first step.warmup 15min— Ignore the first 15 minutes of the activity (h, min or sec). At most once.metrics np, vi, hr_recovery(30sec), decoupling— Template runs always report avg W/kg, avg power, NP, avg speed, avg cadence and avg HR where data exists. Choose extra summary metrics per work effort and for the run: avg_power, max_power, np, vi, if, avg_wkg, max_wkg, np_wkg, avg_hr, max_hr, avg_cadence, max_cadence, avg_speed, max_speed, work_kj, pacing, dropoff, decoupling, time_below_lt1, time_lt1_lt2, time_above_lt2, time_below_lt1_hr, time_lt1_lt2_hr, time_above_lt2_hr, time_z1, time_z2, time_z3, time_z4, time_z5, time_z6, hr_recovery, estimated_ftp, estimated_lt2_power, estimated_lt2_hr, estimated_lt1_power, estimated_lt1_hr. hr_recovery takes an optional window (default 60sec); np_wkg, avg_wkg and max_wkg are power per kg of the activity weight; the time_below/lt1/above_* metrics are seconds in lactate zones (power, or heart rate with the _hr suffix); time_z1 to time_z6 are seconds in each power zone; the estimated_* metrics propose FTP / LT1 / LT2 from a threshold test, with the test protocol in brackets, e.g. estimated_ftp(20min), estimated_ftp(8min), estimated_ftp(ramp), estimated_lt2_hr(30min), estimated_lt1_power(steady). At most once.pattern repeated_bursts— Use instead of the repeat line to run a built-in detector: repeated_bursts, flying_sprint, sustained_tt, standing_start. Then add its option lines (repeated_bursts: count, duration, recovery window; flying_sprint: distance; sustained_tt: min duration, distances, lap; standing_start: distance). Only metrics is also allowed.lap 250m— Track context: report per-lap split times (full laps only, from the speed stream) for every work effort, plus lap_count, best_lap_sec, slowest_lap_sec and avg_lap_sec for the run. At most once; also valid under pattern sustained_tt.time & distance results— Automatic, no line needed. Duration steps (20min) report the distance covered plus average speed; distance steps (3km) and the legacy pursuit/flying/standing patterns report the exact elapsed time (interpolated, shown as a race time) plus average speed. Needs a speed stream; without one the run says so. Run summaries add best/avg/total time or distance, and a faster time counts as an improvement in comparisons.cooldown 10min— Ignore the last 10 minutes of the activity (h, min or sec). At most once.
A repeat can contain several work/recovery lines. They are matched one after another in the order written; prefix a step with then to require it to start right where the previous one ended.
Write 3 sets of 5x on the first line for sets: the block repeats 5 times per set, three times. An optional set recovery line is the rest searched for between sets.
Duration vs. distance steps
Use h/min/sec to match by time (work 2h @ Z2), or km/m to match by distance (e.g. a 4km individual pursuit or a 200m flying sprint). Because a distance window has no inherent power-vs-speed preference, best/max must be written as best power or best speed on those steps.
Examples
Without a repeat line every step is simply done once, in order. Names are case-insensitive and a bare target like 50W means 50W ±5%.
work 15min ±0% @ Z3 recovery 8min ±0% @ <Z3 Work 15min ±0% @ Z3 Recovery 8min ±0% @ 50W work 15min ±0% @ Z3
h is hours (1.5h = 90 minutes). The ±tolerance is optional and defaults to ±0%, so these lines match exactly like "work 2h ±0% @ Z2".
work 2h @ Z2 recovery 10min @ <Z2 work 1.5h @ Z3
A "6x" line repeats the steps below it until the next blank line.
recovery 20min ±0% @ Z1 6x work 40sec ±0% @ Z5 recovery 20sec ±0% @ 50W recovery 10min ±0% @ Z2
A group inside a group; "end" closes the inner one so the recovery belongs to the outer repeat. (When the first line is a repeat count it applies to the whole description.)
3x work 10min ±10% @ Z3 2x work 1min ±5% @ Z5 recovery 1min ±20% @ <Z2 end recovery 5min ±30% @ <Z2
Four 3-minute efforts at 90-110% FTP, each followed by 2 minutes of easy spinning.
4x work 3min ±30% @ 90-110%FTP recovery 2min ±50% @ <55%FTP
One continuous 20-minute effort at 95-105% FTP.
1x work 20min ±15% @ 95-105%FTP
Longer repeats with a lower-bound-only target, so anything above 88% FTP counts.
3x work 10min ±10% @ >88%FTP recovery 5min ±30% @ <60%FTP
Ten 15-second sprints at or above 150% FTP with long recoveries.
10x work 15sec ±20% @ >150%FTP recovery 3min ±50% @ <55%FTP
Find the best 5-minute effort in the ride; no recovery line and no threshold.
1x work 5min ±40% @ best
Use watts directly when the rider has no FTP configured.
5x work 30sec ±20% @ 250-300W recovery 90sec ±50% @ <150W
Target speed instead of power, e.g. for motor-paced or track efforts.
2x work 2km ±10% @ 45-50km/h recovery 3min ±50% @ <30km/h
Work by heart rate (bpm or %HRmax) instead of power; needs an HR stream on the activity.
3x work 10min ±10% @ 150-165bpm recovery 5min ±30% @ <70%HRmax
Work relative to your LT2 power with recoveries below LT1, reporting time spent between and above the thresholds. Needs LT1/LT2 in your profile.
4x work 8min ±15% @ 95-105%LT2 recovery 4min ±40% @ <100%LT1 metrics avg_power, time_lt1_lt2, time_above_lt2
Heart rate relative to LT2 / LT1 heart rate.
3x work 10min ±15% @ 97-103%LT2HR recovery 5min ±40% @ <100%LT1HR metrics time_lt1_lt2_hr, time_above_lt2_hr
Work in a power zone with recoveries below it, reporting time in each zone. Needs LT1/LT2 or an FTP.
3x work 15min ±10% @ Z3 recovery 5min ±40% @ <Z3 metrics avg_power, time_z2, time_z3, time_z4
Work at a W/kg target. Needs a body weight in your profile.
2x work 20min ±15% @ 3.5-4W/kg recovery 5min ±40% @ <2W/kg metrics avg_power, avg_wkg, np_wkg
Find the best 20 minutes and propose FTP (x 0.95) and LT2 heart rate. Protocols: 20min, 8min, ramp, 30min, 60min; estimated_lt1_* use "steady" for a decoupling-based LT1 test. Proposals can be reviewed and applied to your profile from the run card.
1x work 20min ±0% @ best metrics avg_power, avg_hr, pacing, estimated_ftp(20min), estimated_lt2_hr(20min)
High-cadence work bouts with low-cadence recoveries.
4x work 5min ±15% @ 100-110rpm recovery 3min ±30% @ <70rpm
Skip the first 15 and last 10 minutes so openers and a final sprint do not count as reps.
3x warmup 15min cooldown 10min work 10min ±10% @ 90-100%FTP recovery 5min ±30% @ <55%FTP
Each repeat is a 2-minute tempo step, a 1-minute hard step, then a recovery.
3x work 2min ±10% @ 95-100%FTP work 1min ±10% @ 105-110%FTP recovery 3min ±30% @ <55%FTP
Back-to-back under/over/under steps, then a recovery; "then" keeps them contiguous.
4x work 2min ±5% @ 95-100%FTP then work 1min ±5% @ 105-110%FTP then work 2min ±5% @ 95-100%FTP recovery 4min ±30% @ <55%FTP
Ascending then descending steps with no rest in between.
1x work 1min ±5% @ 100-105%FTP then work 2min ±5% @ 105-110%FTP then work 3min ±5% @ 110-115%FTP then work 2min ±5% @ 105-110%FTP then work 1min ±5% @ 100-105%FTP
Stepwise increasing targets.
1x work 1min ±5% @ 50-60%FTP then work 1min ±5% @ 60-70%FTP then work 1min ±5% @ 70-80%FTP then work 1min ±5% @ >80%FTP
Five 30-second efforts with 30 seconds easy, repeated in three sets separated by 5 minutes of rest.
3 sets of 5x work 30sec ±20% @ 120-140%FTP recovery 30sec ±50% @ <55%FTP set recovery 5min ±30% @ <55%FTP
Report normalized power, variability, power:HR decoupling and HR recovery 30 seconds after each rep.
3x work 10min ±10% @ 90-100%FTP recovery 5min ±30% @ <55%FTP metrics np, vi, decoupling, hr_recovery(30sec), dropoff, pacing
Distance-keyed steps need an explicit metric after "best".
4x work 1km ±5% @ best power recovery 2min ±50% @ <55%FTP
One-shot distance step looking for the fastest 200m.
1x work 200m ±10% @ best speed
Legacy fixed patterns are written with "pattern" and options instead of steps.
pattern repeated_bursts count 3 duration 3min ±45sec recovery window 1min
Sustained time trial over 2, 3 and 4 km with 250m lap splits and decoupling.
pattern sustained_tt distances 2km, 3km, 4km lap 250m metrics decoupling
Fastest 1km on the track, with a split time for every 250m lap.
1x work 1km ±10% @ best speed lap 250m
Rules
- The repeat line is optional. Without it the steps run once, in order. A first line "4x" (1 or greater) repeats the whole description; "3 sets of 5x" adds sets.
- Every other line is one step, a warmup/cooldown line, or a repeated group ("6x" ... blank line/"end"); at least one "work" step is required.
- Repeated groups nest up to 3 levels, repeat 1-100 times, and expand to at most 200 steps in total.
- A repeat can have several work/recovery steps; they are matched in the order written.
- Step values must be greater than 0; tolerance (optional, default ±0%) must be 0-100%.
- In a range, the minimum must be lower than the maximum.
- The tolerance sign is "±" (plus-minus).
- "best"/"max" on km/m steps must say "power" or "speed".
Common mistakes
1x work 1km ±10% @ best speed lap 250m lap 125m
Only one "lap" line is allowed.
pattern flying_sprint count 3
That option does not belong to this pattern. flying_sprint only accepts "distance" (and metrics).
1x work 5min ±10% @ best metrics np, speedy
Unknown metric. Use the names listed under "metrics".
3x 2x 1x 1x 1x work 1min ±5% @ Z3
Repeated groups can be nested at most 3 levels deep.
2x end
A repeated group needs steps, and "end" only closes a group that is open.
1x work 1km ±5% @ best
Distance steps need a metric: "best power" or "best speed".
1x work 3min +-30% @ 90-110%FTP
Use the single "±" character, not "+-".
1x work 3min ±30% @ 110-90%FTP
The minimum must be lower than the maximum.
1x then work 3min ±5% @ 90-110%FTP
"then" needs a preceding step; remove it from the first step.
3x work 1min ±5% @ best set recovery 5min ±30% @ <55%FTP
"set recovery" needs a sets line first, e.g. "3 sets of 3x".