Progression macros

A progression macro is a reusable rule you define once and attach to as many exercises as you like with using. A macro can supply the exercise's sets, its progression logic (a hook), or both.

This is the complete reference. For the hook variables and runtime rules a macro's logic runs under, see lifecycle hooks.

Two flavours of macro

FlavourBody containsWhat using does
Set-schemeset lines (5 @%90, amrap @%100)Expands into the exercise's sets
Hookan on_complete / on_set blockBecomes the exercise's progression hook

A macro may contain both. The built-in macros (below) are set-scheme only — they lay out reps and percentages but do not progress the training max on their own. Pair them with a hook (inline or your own macro) to add progression.

A macro's on_complete hook drives progression today; an on_set hook is parsed and validated but not yet evaluated at runtime.

Attach with using:

Parameters

A macro declares parameters in parentheses. Each may have an optional : type annotation (number or weight) and an optional = default:

progression "ramp" (increment = 2.5, bump: weight = 2.5kg, target: weight) { ... }

Value- vs reference-binding

How you bind an argument at the using site decides whether the macro can write to it — this is what makes a macro stateful.

BindingExampleInside the macro
Value (literal)using "ramp" (bump: 5kg)Read-only. Assigning to it is a compile error.
Reference (state)using "ramp" (load: state.row_weight)Writable. Assignments write through to the referenced state variable.
Barbell Row {
  8-12 @state.row_weight
  using "double_prog" (load: state.row_weight, top: 12)
}

A set-scheme macro takes literal arguments only — passing a state reference to one is an error, because there's no number to expand into a set.

Override & precedence rules

Built-in macros

Four set-scheme macros ship with every program — use them by name without defining anything. Each declares an increment parameter for convention, but remember these are set layouts, not progression logic:

NameSets it lays outDefaults
lpamrap @%100increment = 5
lp_deload5 / 3 / amrap, all at @%deload_pctincrement = 5, deload_pct = 90
dp5 @%90, 3 @%95, amrap @%100increment = 2.5
wave_lp5 @%65, 5 @%75, 5 @%85increment = 5
Bench Press {
  using "dp"
}

Built-in functions

Available inside any hook body (and therefore any macro hook):

FunctionReturns
round(x, n)x rounded to the nearest multiple of n
floor(x) / ceil(x)Round down / up to a whole number
min(a, b) / max(a, b)Smaller / larger of the two
clamp(x, lo, hi)x constrained to [lo, hi]
pct_of(base, pct)base × pct (pct as a fraction)
rpe_to_pct(reps, rpe)%1RM for a reps/RPE pair (RTS table)
pick(cond, a, b)a if cond is non-zero, else b

Unit-aware increments

Weights in ReptoLang are raw numbers labelled with a unit — nothing ever converts kg ↔ lbs. To bump by the right amount for either lifter, write a unit pair { <kg>, <lbs> }:

{ Akg, Blbs } is shorthand for pick(unit_is_metric, A, B). It needs exactly one kg and one lbs slot (order doesn't matter), each a non-negative weight literal — a leading - is a parse error, so write a subtraction (tm.self -= { 2.5kg, 5lbs }) instead.

For the variables and runtime caveats a macro's hook runs under, see lifecycle hooks; for the full grammar, the language reference.