-
Notifications
You must be signed in to change notification settings - Fork 1
Stryd LBSS v2 Field Setup
Since v0.6.0 the LBSS-based PMC defaults to the custom field StrydLBSSv2
(env LBSS_FIELD). Unlike StrydILR / StrydLBSSmod, it is not in the
Intervals.icu community search box — you build it on your own account. This page
is the copy-paste guide (~15 min). How the formula was identified — and why it
reproduces Stryd's native LBSS at 0.0% error — is in
LLM Agent Recipes §3.
If you'd rather not build anything, set LBSS_FIELD=StrydLBSSmod and keep using
the community field. Everything below is optional.
| Field | Formula (per activity) | Anchor | Role |
|---|---|---|---|
StrydLBSSv2 |
(100/3600) · Σ ILRᵢ / CI |
1 h at ILR = CI → 100 | Faithful replica of Stryd's native LBSS (β = 1, linear). Source for the LBSS PMC. |
EccLBSS (optional) |
(100/3600) · Σ max(0, (ILRᵢ − CI) / CI) |
1 h at ILR = 2×CI → 100 | Linear excess above CI — isolates downhill / high-impact seconds that the β = 1 sum dilutes. Flat easy ≈ 0.06–0.16/h vs. hilly ≈ 1.05–2.06/h in our data. |
Two fields because one metric can't be both Stryd-faithful and discriminate eccentric overload: β = 1 means the native LBSS deliberately does not overweight impact spikes.
- A Stryd pod, with the community
StrydILRfield added and populating (INSTALL.md → Setting up the Stryd custom fields). Both scripts read the per-secondStrydILRstream. Stryd ILR data exists from roughly November 2025 onward. - Your Critical Impact (CI) value — Step 1.
CI is your Impact Loading Rate at critical power, in bw/s (the load-side analogue of CP). Best available source first:
-
You already maintain an ILR@CP value (the community ILR@CP Calculator
field used by
StrydILRTreshold) → reuse it. -
Read Stryd's own per-activity
critical_impactwith a browser agent (Recipes §2) and take the median over recent weeks. This is the value the formula was calibrated against. -
Estimate it from Intervals streams alone by regression
(Recipes §4);
a deterministic
estimate_critical_impactserver tool is on the roadmap.
Don't over-tune it: a CI error scales LBSS linearly and uniformly, so your CTL/TSB trends survive a wrong-but-stable CI. Consistency beats precision. (For one athlete we observed ~56–72 bw/s depending on shoes.)
In Intervals.icu: Settings → Sport Settings → RUN → CUSTOM FIELDS opens the Activity Fields dialog. Click ADD FIELD — the magnifying-glass FIELD button next to it is the community search; that is not the one you want here. The field editor has three tabs (TYPE / DESCRIPTION / SCRIPT):
| Setting (TYPE tab) | StrydLBSSv2 |
EccLBSS |
|---|---|---|
| Code | StrydLBSSv2 |
EccLBSS |
| Name | Stryd LBSS v2 | Ecc LBSS |
| Type | Numeric | Numeric |
| Format | .1f |
.2f |
Scripts go in the SCRIPT tab — paste as-is, then replace 57.4 with your
CI (same value in both):
// StrydLBSSv2 — Stryd-faithful LBSS replica (beta = 1). Anchor: 1 h at CI = 100
{
let CI = 57.4; // ← your CI (bw/s); keep identical in EccLBSS
let s = streams.get("StrydILR").data;
let tot = 0;
for (let i = 0; i < s.length; i++) {
let v = s[i];
if (v && v > 0) tot += v / CI;
}
tot * 100.0 / 3600.0;
}// EccLBSS — linear excess above CI (downhill / overload discrimination). Anchor: 1 h at 2xCI = 100
{
let CI = 57.4; // ← same value as StrydLBSSv2
let s = streams.get("StrydILR").data;
let tot = 0;
for (let i = 0; i < s.length; i++) {
let v = s[i];
if (v && v > CI) tot += (v - CI) / CI;
}
tot * 100.0 / 3600.0;
}Script-environment pitfalls (each one cost us a failed attempt):
- The field Code must be CamelCase — underscores are rejected
(
StrydLBSS_v2→StrydLBSSv2). -
No top-level
let/const(script scope is shared; you get "Variable already declared") → the whole script is wrapped in{ … }. Keep the braces. - A Numeric field must return a number (last expression; strings fail validation).
- Don't call
Object.keys(activity)— host-object enumeration throws. Named access (activity.gear_idetc.) is fine. - Activities without a
StrydILRstream (rides, pre-Stryd history) just produce no value — harmless, the server treats missing as null.
Recommended Description (DESCRIPTION tab) — make the field self-describing with machine-readable JSON (a planned server feature will auto-discover fields by role; this also documents your parameters for free):
{"icu_role": "lbss", "ver": 2, "formula": "sum(ILR/CI)/36", "ci": 57.4, "beta": 1.0, "calibrated": "2026-06-07"}(for EccLBSS: {"icu_role": "ecc_lbss", "ver": 1, "formula": "sum(max(0,(ILR-CI)/CI))/36", "ci": 57.4, "calibrated": "2026-06-07"})
Advanced — per-shoe CI table. Scripts can read activity.gear_id, so if your
activities have gear assigned (Recipes §6
bootstraps that from Stryd), CI can follow the shoe and re-analysis stays
idempotent when CI changes:
{
let CI_BY_GEAR = { "12345": 57.4, "67890": 69.0 }; // gear_id → CI
let g = activity.gear_id;
let CI = (g && CI_BY_GEAR[g]) ? CI_BY_GEAR[g] : 57.4; // fallback: current value
// … rest identical
}New activities compute the fields automatically. For existing ones:
- Open Activities in list view, select a batch (e.g. one month).
- EDIT → Analyze, check "Keep existing intervals", OK.
- Repeat per batch — pause between batches; rapid-fire triggers
429 Too Many Requests.
Backfill as far as StrydILR exists (≈ Nov 2025) — the PMC's 42-day EMA needs
a few months of history before CTL is trustworthy.
-
Sanity anchor: an easy flat ~1 h run with average ILR near your CI should
score near 100 (more precisely ≈
100 × hours × avgILR / CI). -
From the server:
get_current_pmcwithinclude_legacy: true→lbss(v2) andlbss_legacy(StrydLBSSmod) should both populate, with different values. The scales are not comparable (v2 ran ≈ 1.3× mod for one athlete — don't assume that ratio); never splice v2 CTL onto a mod CTL history.
- Review CI monthly and on shoe / CP changes. Stryd's own CI is time-varying (we observed it move within 56–61 over three months, and 72→56 across a shoe transition).
- Editing the constant rewrites history on the next re-analysis — either re-analyze everything so the whole history uses one CI, or use the gear table above and never touch past entries.
- Keep
StrydLBSSv2andEccLBSSon the same CI at all times. - Server side:
LBSS_FIELD/LBSS_FIELD_LEGACY/ILR_FIELDenv vars, per-calllbss_fieldoverride, andinclude_legacyfor a parallel-run period — see INSTALL.md → Optional settings.
Formula and procedures validated against Stryd-native values on real data (single athlete, 2026-06-07; 10-activity calibration set, 0.0% error). Read the numbers as a method demo, not a population guarantee. This project is not affiliated with Stryd or Intervals.icu.