IronScript overview

The language your program is written in.

IronScript defines program schedules, state, config fields, workouts, sets, and progression rules, in plain text you can read and edit.

01

Open the starter file.

02

Edit exercises, loads, and schedule entries.

03

Validate the program before saving.

A small working program

The Designer starter is shown below as a minimal compiling example.

starter program

.is

// Tiny starter: one workout, one progressing lift.
program "Starter Squat" id="starter-squat" {
  schedule = [A, rest, A, rest, A, rest, rest]

  state {
    squat_w = 60
  }

  workout A "Squat Day" {
    exercise "Squat" {
      count  = 3
      reps   = 5
      weight = squat_w
      rest   = 180
    }

    progress {
      if all_complete {
        squat_w = squat_w + 2.5
      }
    }
  }
}

Language guide

Core language pieces.

A program is composed from schedules, state, exercises, sets, config fields, templates, and progress rules.

Program identity and schedule

program "My Program" id="my-program" {
  description = "One sentence summary."
  about = """
    *Bold* highlights, _italic_ nuance, simple lists, and numbered steps are
    rendered in program detail views.

    - Use `-` or `*` for bullets.
    1. Use `1.` style markers for ordered steps.
  """
  schedule    = [dayA, rest, dayB, rest, dayA, rest, rest]
  ...
}
  • id must be unique across all programs. If omitted the parser uses the name.
  • description is the compact one-line summary for cards and lists.
  • about is longer guidance for detail views. It remains a plain string in the

runtime, but web and mobile render a tiny Markdown-like subset: *bold*, _italic_, bullet lists starting with - or * , and ordered lists starting with 1. style markers.

  • schedule is a weekly rotation: each entry is a workout id or the literal rest.
  • The scheduler advances scheduleIndex circularly; rest entries are skipped automatically.

State

state {
  squat_tm = 100
  week     = 1
}
  • All values are numbers (integers or decimals).
  • State is mutable across sessions; config is immutable after enrollment.
  • Every variable used in expressions must be declared here.

Exercises: shorthand vs. explicit sets

Shorthand (one block of identical sets):

exercise "Squat" {
  count  = 5
  reps   = 5
  weight = squat_tm * 0.8
  rest   = 180
}

Explicit (different sets within one exercise):

exercise "Squat" {
  set { reps = 5  weight = squat_tm * 0.65  rest = 180 }
  set { reps = 5  weight = squat_tm * 0.75  rest = 180 }
  set { reps = 5  weight = squat_tm * 0.85  rest = 240  amrap = true }
}

Set fields:

FieldTypeRequiredNotes
countnumbernoHow many identical repetitions of this set spec. Defaults to 1 when omitted.
repsnumberyesTarget reps per set
weightnumbernoNumeric load in the enrollment's active unit; concrete targets are rounded to the user's configured total-load jump
rpenumbernoRate of perceived exertion, 1–10
restnumbernoRest period in seconds
amrapbooleannoLast set is "as many reps as possible"
warmupbooleannoMarks the set as warmup volume. Warmup sets are logged and displayed, but ignored by progress-rule completion checks.

count may evaluate to 0 to omit a conditional set spec from the concrete workout. The legacy spelling sets is still accepted as an alias for count.

Config-driven exercises

name = ident in the body lets the user pick which exercise fills this slot at enrollment (the config value behind ident is an exercise reference id, not a display string). enabled = ident lets the user toggle the slot on/off.

exercise "T2 Squat" {
  name    = t2_squat_id
  enabled = t2_squat_enabled
  count   = 3
  reps    = 10
  weight  = squat_tm * 0.5
}

Progress rules

Triggered after each workout completion. All expressions evaluate against a snapshot of state taken before any updates in the block are applied. Order within the block does not matter.

progress {
  if all_complete {
    week     = week < 4 ? week + 1 : 1
    squat_tm = week == 4 ? squat_tm + 5 : squat_tm  // sees old week, not the updated one
  }
}

Conditions:

  • all_complete: every set in the workout was completed
  • any_complete: at least one set completed
  • always: fires unconditionally
  • not_all_complete: at least one set was skipped

When a progress block lives inside an exercise, it fires per exercise and sees bindings scoped to that exercise's logged sets (warmups excluded):

  • complete / incomplete: every work set was done (or skipped)
  • amrapReps: reps logged on the final AMRAP set
  • total_reps: total reps completed across all work sets, regardless of weight
  • total_volume: total weight × reps across completed work sets
  • total_time / amrapTime: seconds for timed sets
  • completedSets / numberOfSets: counts of done vs prescribed work sets
  • completedReps_N, targetReps_N, completedWeight_N, ... : 1-indexed per-set values

Array indexing for lookup tables

The [e0, e1, ...][idx] primary lets you build week/tier lookup tables inline. Index is clamped to bounds.

reps   = [5, 3, 1, 5][week - 1]
weight = squat_tm * [0.85, 0.90, 0.95, 0.60][week - 1]

Config block

Drives the enrollment onboarding form. Fields can seed state variables, be grouped into UI sections/slots, and be conditionally shown.

config {
  squat_1rm: weight "Squat 1-Rep Max"
    default = 100
    -> squat_tm          // seeds state.squat_tm at enrollment
    reconfigurable       // user can update after starting

  use_accessory: boolean "Include accessory work?"
    default = true

  accessory_name: exercise "Accessory exercise"
    if = use_accessory
    optional
    suggest = [dumbbell_row, cable_row_seated, machine_row]   // catalog-id swaps shown first in the picker

  scheme: select "Rep scheme"
    default = "5/3/1"
    option "5/3/1" { reps_target = 1 }
    option "Boring But Big" { reps_target = 10 }
}

Config field types:

TypeUI widgetNotes
exerciseText/search inputStores an exercise name string. Optional suggest = [catalog_id, ...] surfaces author-blessed swaps first (UI hint only; validated catalog slug ids)
weightNumeric inputStored as number
incrementNumeric inputPer-session weight increase
booleanToggleStored as 0 (false) or 1 (true) in config
selectDropdownRequires option declarations; can patch state

Full-stack templates

Templates declare config fields, state variables, and exercises together. When expanded via use ... as "prefix", all identifiers are automatically prefixed. Weight/increment config fields implicitly seed state variables of the same name; no -> needed.

template t1(default_name, default_weight, default_inc) {
  config {
    name: exercise "T1 Exercise" default = default_name
    tm: weight "Start Weight" default = default_weight
    inc: increment "Increment" default = default_inc reconfigurable
  }
  state {
    stage      = 0
    scheme_idx = 0
  }
  exercise "T1 Lift" {
    name   = name
    count  = [5, 6, 10][stage]
    reps   = [3, 2, 1][stage]
    weight = tm
    amrap  = true
    progress {
      if complete   { tm = tm + inc }
      if incomplete { stage = stage < 2 ? stage + 1 : 0 }
    }
  }
}

workout A "Day A" {
  use t1("Squat", 60, 5) as "A.t1"
}

The as "A.t1" clause:

  • Prefixes all identifiers: tm -> A_t1_tm, stage -> A_t1_stage, etc.
  • Sets the config section for UI grouping.
  • Template parameters (default_name, etc.) are compile-time literal values substituted into default = ... clauses.

Starter workflow

Edit the starter in Designer.

A small, valid program you can edit, validate, and save, straight from the Designer.

Assistant workflow

Assistant context

Use the language guide and a close example when asking an assistant to draft or review IronScript.

Assistant guide

A compact file with the public IronScript reference, ready to paste into an assistant's context.

Open llms.txt

Draft it in the Designer

Paste what the assistant writes into the Designer to compile it, see the projection, and fix anything that does not hold up.

Open the Designer