# Corset routine format, version 1

Corset is an app that runs exercise routines for the back, neck, hips and knees: a timer, spoken cues, animated
figures and a daily "how does it feel" log. A routine is a small JSON document. Anyone can write one: a physio, a
friend, or an AI assistant working from someone's exercise sheet. This page is everything you need to write one.

Short version: [llms.txt](https://corset.app/llms.txt). Library exercises with their steps: [movements.json](https://corset.app/movements.json).

## How to answer

Answer with the routine as JSON in **one code block** (```json). Nothing is needed after it.

The user copies your whole answer, opens Corset (https://app.corset.app, or the iOS or Android app) and goes to
Routines → Add your own exercises → Paste → Open it. Corset finds the code block, shows a preview, and adds nothing
until the user taps Add.

Ask first when something is missing or unclear. A question is better than a routine with a guessed number.

## Rules

- Use only the exercises in the user's source (an exercise sheet, a photo of one, a message). Don't add, drop or reorder any.
- Copy sets, reps, holds and rests exactly. If a number is missing or unclear, ask the user before you write the routine.
- Put a library id in `"ex"` only when the exercise is done exactly like Corset's (see the list below, or [movements.json](https://corset.app/movements.json) for the steps). A variation (against a wall, from the knees, halfway, with a ball or band) is not the same. Then, or when you're not sure, leave `"ex"` out and write it as the user's own: `"name"`, a one-sentence `"cue"` and up to 6 short `"how"` steps from the source.
- Write `"name"`, `"cue"` and `"how"` in English, like the rest of Corset. If the source is in another language, put its own name for the exercise in `"note"`.
- Copy the source's "stop if" advice into `"warnings"`, word for word where you can.
- A speed ("slowly", "lower over 3 seconds") goes in `"tempo"`, not `"note"`: `{"down": 3}`. `up` is moving into the position, `down` moving back. "Slowly" with no number is 3 seconds, both ways unless the source says which.
- Don't diagnose anything, and don't add medical advice or claims. Corset doesn't check routines: the preview tells the user who wrote it and that Corset hasn't checked it.
- If the user has no exercises and asks you to suggest some, say plainly that they should check them with a physio or doctor first, and set `"source": "ai"`.

## The document

| Field | Value | Meaning |
|---|---|---|
| `corset` | `1` | Required. The format version; also how Corset finds the routine in a pasted answer. |
| `title` | text, up to 80 | The routine's name, as the source has it. |
| `about` | text, up to 500 | A short description. Shown, never spoken. |
| `by` | text, up to 60 | Who wrote the exercises, as written: `"Anna Peeters (physio)"`. |
| `source` | `physio`, `doctor`, `trainer`, `book`, `ai`, `self`, `other` | `physio` (a physiotherapist or physical therapist), `doctor` (a doctor), `trainer` (a trainer or coach), `book` (a book, video or website), `ai` (an AI assistant suggested the exercises), `self` (the user wrote them), `other` (anything else). |
| `sourceNote` | text, up to 120 | Where they came from: `"Exercise sheet, 12 Sep 2026"`. |
| `area` | `lumbar`, `neck`, `upper-back`, `glutes`, `hips`, `joints`, `other` | The part of the body it is for: `lumbar` (lower back), `neck` (neck), `upper-back` (upper back and shoulders), `glutes` (buttock or leg), `hips` (hips), `joints` (knees, ankles or wrists only), `other` (anything else, like an elbow or a foot). Corset asks the user how that part feels after each session. |
| `schedule` | `"daily"`, `{"perWeek": 3}` or `{"days": ["mon", "thu"]}` | How often. `perWeek` is 1 to 6 (7 is `"daily"`); days are `mon` to `sun`. Leave it out and the user chooses. |
| `slot` | `morning`, `day`, `evening`, `any` | Time of day for the whole routine: `morning` (morning), `day` (during the day), `evening` (evening), `any` (any time). |
| `warnings` | up to 6 texts, each up to 200 | The source's "stop if" advice. Shown with the routine. |
| `phases` | 1 to 5 phases, up to 40 exercises in all | The exercises, in order. See below. |
| `stages` | up to 6, with up to 40 changes in all | Only when the source has weeks or levels. See below. |
| `stage` | a number from 0 | The stage to start on, counting from 0. Leave it out to start at the first (with `lib`: as written). |
| `lib` | a library routine id | Instead of `phases`: one of Corset's own routines. See "Corset's own routines". |

Leave out every field you don't need. Corset ignores fields it doesn't know. Text is plain text: no Markdown, HTML or
links. Text longer than its limit is cut.

### Phases

| Field | Value | Meaning |
|---|---|---|
| `name` | text, up to 40 | Shown as the phase starts. Leave it out for a routine with one phase. |
| `slot` | `morning`, `day`, `evening`, `any` | Makes the phase a block of its own at that time of day ("morning and evening" on a sheet is two phases). |
| `items` | a list | The exercises. |

A routine has 1 to 5 phases. Most sheets are one phase with no name.

### Exercises (items)

| Field | Value | Meaning |
|---|---|---|
| `ex` | a library id | Only for a clear match: Corset shows its animated figure and steps, and uses its recorded voice. |
| `name` | text, up to 60 | The source's name for it. Required without `ex`. |
| `sets` | 1 to 10 | Default 1. |
| `reps` | 1 to 50, or a list with one number per set: `[10, 8, 6]` (up to 10 sets) | Reps in each set. Per side when `sides` is set. |
| `hold` | 1 to 120 seconds | How long to hold each rep. Leave it out for reps done at a steady pace. |
| `time` | 5 to 600 seconds | A timed exercise instead of reps. With `sets`, that many timed holds. Per side when `sides` is set. |
| `tempo` | `{"up": 3, "down": 3}`, either or both, 0.5 to 10 seconds | How fast each rep moves: `up` into the position (where a `hold` holds), `down` back to the start. Only for reps with no `hold` or a hold under 5 seconds. |
| `nonstop` | `true` | A timed exercise that keeps moving the whole time (marching, cycling, jumping jacks). |
| `sides` | `"each"` or `"alternate"` | `each`: all of one side, then the other. `alternate`: switch every rep. |
| `rest` | 0 to 300 seconds | Rest between sets, or between sides. Leave it out for Corset's usual rest. |
| `cue` | text, up to 140 | One sentence shown before it starts: how to set up. |
| `how` | up to 6 texts, each up to 200 | Short steps, shown on the card. |
| `note` | text, up to 200 | Anything else from the source ("use a rolled towel", "8-12 reps"). Shown, never spoken. |
| `key` | text, up to 24 | Only needed when two items would have the same name or `ex` and a stage changes one of them. |

**How Corset reads the numbers**

- Write numbers as numbers: `"reps": 10`, not `"reps": "10"`.
- Reps: `"sets": 3, "reps": 10`. Add `"hold": 5` when each rep is held for 5 seconds.
- Timed: `"time": 30` is one 30-second block. `"sets": 3, "time": 20` is three 20-second holds (a wall sit).
- Give reps or a time, not both. When both are given, the time is used.
- Tempo: "lower over 3 seconds" is `"tempo": {"down": 3}`; "slowly" is 3 seconds, both ways (`{"up": 3, "down": 3}`)
  unless the source says which part. `up` is always moving into the position and `down` moving back to the start,
  whichever way the body goes (on a step-down, `up` is the lowering). A half you leave out keeps Corset's pace for
  the exercise (usually 1 second up, 2 seconds down). Seconds go to the half second. Timed exercises and reps held
  5 seconds or more ignore the tempo, and the preview says so.
- 0 means "not given". A number outside its range is set to the nearest limit, and the preview says so.
- A range on the sheet ("8-12 reps"): use the lower number and put the range in `note`.
- `sides` comes from the sheet ("each side", "each leg", "alternate"). An item with `ex` and no `sides` is done
  on the sides Corset uses for it (the Sides column below).
- An item with `ex` and no numbers plays Corset's own dose for that exercise. An item with any numbers plays
  exactly those numbers.
- With `ex`, Corset speaks its own cue and shows its own steps. The item's `name`, `cue` and `note` are shown
  with them, as what the sheet says.
- Without `ex`, the item is a text card: its `name`, `cue` and `how` are shown, not read aloud (Corset's voice
  is recorded, and only has its own exercises).

### Stages

Use stages only when the source describes weeks or levels. The first stage is usually the routine as written, with
no changes. Each later stage lists what is different from the routine as written (not from the stage before it).

| Field | Value | Meaning |
|---|---|---|
| `label` | text, up to 40 | What the stage is: `"Weeks 1-2"`, `"From the knees"`. |
| `summary` | text, up to 200 | One sentence about what changes. |
| `weeks` | 1 to 52 | How long the source says to stay on it. |
| `changes` | a list | Each: `item` (the `key`, `ex` or `name` of an exercise), and any of `ex` (a library id to swap in), `sets`, `reps`, `hold`, `time`, `tempo`, `note`. |

A change that gives any of `sets`, `reps`, `hold` or `time` replaces that exercise's whole dose. A `tempo` is not
part of the dose: a change that gives only a tempo keeps the sets, reps and hold, and changes only the halves it
gives. A swap (`ex`) moves at the new exercise's own pace unless the change gives a `tempo` too.

### Limits

5 phases, 40 exercises, 6 stages and 40 stage changes. A routine that goes past these is
not opened. 120 seconds per hold, 600 seconds per timed exercise, 10 sets, 50 reps per set,
300 seconds of rest, 0.5 to 10 seconds each way in a tempo. The whole routine can take up to
90 minutes, at every stage, rests included.

## Examples

### A physio sheet

The sheet:

```text
Lower back programme. Anna Peeters, physiotherapist, 12 Sep 2026. Once a day.
1. Bird dog: 2 sets of 8 per side, alternate sides, hold 5 seconds.
2. Glute bridge: 3 x 10, rest 30 s between sets.
3. Knee rolls: lie on your back, knees bent, feet flat. Let both knees fall slowly to one side, then the
   other. 10 each way.
Stop if pain spreads down your leg, or if you feel numbness or tingling.
```

The answer:

```json
{
  "corset": 1,
  "title": "Lower back programme",
  "by": "Anna Peeters (physio)",
  "source": "physio",
  "sourceNote": "Exercise sheet, 12 Sep 2026",
  "area": "lumbar",
  "schedule": "daily",
  "warnings": ["Stop if pain spreads down your leg, or if you feel numbness or tingling."],
  "phases": [
    {
      "items": [
        {
          "ex": "bird-dog",
          "name": "Bird dog",
          "sets": 2,
          "reps": 8,
          "hold": 5,
          "sides": "alternate"
        },
        {"ex": "glute-bridges", "name": "Glute bridge", "sets": 3, "reps": 10, "rest": 30},
        {
          "name": "Knee rolls",
          "reps": 10,
          "sides": "alternate",
          "cue": "Lie on your back, knees bent, and let both knees fall slowly to one side, then the other.",
          "how": [
            "Lie on your back, knees bent, feet flat.",
            "Let both knees fall slowly to one side.",
            "Bring them back through the middle and over to the other side."
          ]
        }
      ]
    }
  ]
}
```

Bird dog and glute bridge are done the way Corset does them, so they use `ex`. Knee rolls aren't in the library, so
the item has its own `name`, `cue` and `how`.

### Morning and evening, with weeks

The sheet:

```text
Knee exercises from Tom (physio). Weeks 1-2, then weeks 3-4.
Morning: straight leg raise, 3 x 10 each leg, hold 3 s. Lie on your back, other knee bent; tighten the thigh,
lift the straight leg to the height of the other knee, lower slowly over 3 seconds.
Evening: wall sit, 3 x 20 s, rest 30 s. From week 3: wall sit 3 x 30 s.
Stop if your knee swells.
```

The answer:

```json
{
  "corset": 1,
  "title": "Knee exercises",
  "by": "Tom (physio)",
  "source": "physio",
  "area": "joints",
  "schedule": "daily",
  "warnings": ["Stop if your knee swells."],
  "phases": [
    {
      "name": "Morning",
      "slot": "morning",
      "items": [
        {
          "name": "Straight leg raise",
          "sets": 3,
          "reps": 10,
          "hold": 3,
          "tempo": {"down": 3},
          "sides": "each",
          "cue": "Lie on your back, one knee bent, the other leg straight.",
          "how": [
            "Tighten the thigh of the straight leg.",
            "Lift it to the height of the other knee.",
            "Lower slowly."
          ]
        }
      ]
    },
    {
      "name": "Evening",
      "slot": "evening",
      "items": [{"ex": "wall-sit", "name": "Wall sit", "sets": 3, "time": 20, "rest": 30}]
    }
  ],
  "stages": [
    {"label": "Weeks 1-2", "weeks": 2},
    {"label": "Weeks 3-4", "weeks": 2, "changes": [{"item": "wall-sit", "sets": 3, "time": 30}]}
  ]
}
```

"Lower slowly over 3 seconds" is `"tempo": {"down": 3}`: each rep is 1 second up, the 3-second hold, and 3 seconds
down. The wall sit gets longer from week 3, so the second stage changes its dose.

## Corset's own routines

To pass on one of Corset's own routines, name it with `lib` instead of writing `phases`. `by`, `schedule`, `slot`
and `stage` still apply. Without `stage`, it starts as written; the stages before that are lighter, those after it
stronger.

```json
{"corset": 1, "lib": "neck-care", "by": "Anna (physio)", "schedule": {"perWeek": 3}}
```

| lib | Routine | What it is | `stage` |
|---|---|---|---|
| `corset` | The Corset | McGill’s Big Three with a gentle start and glute work, to keep the lower back steady. | 0 Side plank from the knees; 1 Side plank from the feet (as written); 2 One-leg bridge, longer holds |
| `desk-survival` | Desk Survival | Open the chest, loosen the upper back and neck after a day at a screen. | 0 Shoulder blade squeeze; 1 Y raise (as written); 2 Longer holds |
| `hip-liberation` | Hip Liberation | Stretch the front of the hips and get the glutes doing their share again. | 0 Shorter stretches; 1 Full stretches (as written); 2 One-leg bridge, banded walk |
| `glute-and-leg` | Glute and Leg | Slow nerve glides, a deep glute stretch and light glute work. Stop if anything travels further down the leg. |  |
| `morning-reset` | Morning Reset | Breathing and easy spine movement to shake off the night. |  |
| `twist-guard` | Twist Guard | Three blocks for a back that twinges after twisting or bending. | 0 From the knees; 1 From the feet (as written); 2 Band, carry and one-leg bridge; 3 Adding load |
| `seven-minute` | 7-Minute Workout | The classic 12-exercise bodyweight circuit. Conditioning, not care: skip it during a flare-up. |  |
| `steady-joints` | Steady Joints | Strength and balance for joints that ache or wobble after a long day on your feet. | 0 Shorter wall sit; 1 Full wall sit (as written); 2 One-leg calf raise |
| `neck-care` | Neck Care | Settle a stiff, guarded neck, practise the chin tuck, then add light strength. Stop if pain or tingling spreads down the arm. | 0 Shoulder blade squeeze (as written); 1 Y raise, longer neck holds |

## Library exercises

Use these ids in `ex` only for a clear match. [movements.json](https://corset.app/movements.json) has each one's steps
and the body areas it is used for.

| id | Name | Sides | Also called |
|---|---|---|---|
| `prone-resting` | Prone Resting |  | prone lying, lying prone, lying face down |
| `mckenzie-press-ups` | McKenzie Press-Ups |  | prone press up, extension in lying, mckenzie extension, mckenzie press up, prone press ups |
| `modified-curl-up` | Modified Curl-Up | alternate | mcgill curl up, modified curl up, mcgill curl ups, modified curl ups |
| `side-plank` | Side Plank | each | side bridge, side plank on feet |
| `bird-dog` | Bird-Dog | alternate | bird dog, birddog, quadruped opposite arm and leg, quadruped arm and leg raise |
| `glute-bridges` | Glute Bridges |  | glute bridge, hip bridge, bridge, bridging |
| `hip-hinge-at-wall` | Hip Hinge (at wall) |  | hip hinge, wall hip hinge |
| `chest-doorway-stretch` | Chest Doorway Stretch | each | doorway stretch, doorway chest stretch, doorway pec stretch |
| `thoracic-extension-over-chair` | Thoracic Extension over Chair |  | thoracic extension over a chair, chair thoracic extension |
| `upper-trap-neck-stretch` | Upper-Trap Neck Stretch | each | upper trap stretch, upper trapezius stretch |
| `chin-tucks` | Chin Tucks |  | chin tuck, cervical retraction, neck retraction |
| `scapular-wall-slides` | Scapular Wall Slides |  | wall angel |
| `prone-y-raise` | Prone Y Raise |  | prone y, prone y lift |
| `half-kneeling-hip-flexor-stretch` | Half-Kneeling Hip Flexor Stretch | each | kneeling hip flexor stretch |
| `supine-figure-4-stretch` | Supine Figure-4 Stretch | each | supine figure four stretch, lying figure 4 stretch, lying figure four stretch |
| `90-90-hip-switches` | 90/90 Hip Switches |  | 90 90 hip switch, 90 90 switch, 90 90 hip transition, ninety ninety hip switch |
| `clamshells` | Clamshells | each | clam, clams, clam shell |
| `quadruped-hip-extension` | Quadruped Hip Extension | alternate | donkey kick |
| `sciatic-nerve-glide` | Sciatic Nerve Glide |  | sciatic nerve floss, sciatic nerve flossing |
| `single-knee-to-chest` | Single Knee-to-Chest | each | single knee to chest stretch, one knee to chest |
| `supine-piriformis-stretch` | Supine Piriformis Stretch | each | lying piriformis stretch |
| `diaphragmatic-breathing` | Diaphragmatic Breathing |  | belly breathing, diaphragm breathing |
| `cat-cow` | Cat-Cow |  | cat camel, cat and cow |
| `open-book-thoracic-rotation` | Open-Book Thoracic Rotation | each | open book, open book stretch, open book rotation |
| `standing-side-bend` | Standing Side Bend | alternate | standing lateral bend |
| `pallof-press` | Pallof Press | each | paloff press, anti rotation press |
| `single-leg-bridge` | Single-Leg Bridge | each | single leg glute bridge, single leg hip bridge, one leg bridge |
| `banded-lateral-walk` | Banded Lateral Walk | each | lateral band walk, banded side step |
| `suitcase-carry` | Suitcase Carry | each | one arm farmer carry, single arm farmer carry, suitcase walk |
| `wall-sit` | Wall Sit |  | isometric wall sit, wall squat hold |
| `slow-step-down` | Slow Step-Down | each | eccentric step down, forward step down |
| `calf-raise` | Calf Raise |  | heel raise, standing calf raise, double leg calf raise |
| `toe-raise` | Toe Raise |  | tibialis raise, tib raise |
| `single-leg-balance` | Single-Leg Balance | each | single leg stance, single leg stand, one leg stand, standing on one leg |
| `quadruped-wrist-rocks` | Quadruped Wrist Rocks |  | wrist rocks |
| `plank-shoulder-taps` | Plank Shoulder Taps | alternate | shoulder taps, plank with shoulder taps, high plank shoulder taps |
| `wrist-flexor-stretch` | Wrist Flexor Stretch | each | forearm flexor stretch |
| `supine-neck-retraction` | Supine Neck Retraction |  | supine chin tuck, lying chin tuck |
| `shoulder-blade-squeeze` | Shoulder Blade Squeeze |  | scapular squeeze, scapular retraction, shoulder blade retraction |
| `isometric-neck-holds` | Isometric Neck Holds |  | neck isometrics, isometric neck exercises |
| `jumping-jacks` | Jumping Jacks |  | jumping jack, star jumps |
| `push-ups` | Push-Ups |  | push up, pushup, pushups |
| `abdominal-crunch` | Abdominal Crunch |  | ab crunch, abdominal crunches |
| `step-up-onto-chair` | Step-Up onto Chair |  | chair step up, chair step ups |
| `squat` | Squat |  | bodyweight squat, air squat |
| `triceps-dip-on-chair` | Triceps Dip on Chair |  | chair dip, chair triceps dip, tricep dip on chair |
| `plank` | Plank |  | forearm plank, elbow plank, front plank |
| `high-knees` | High Knees |  | high knee run, high knee running |
| `lunge` | Lunge |  | forward lunge |
| `push-up-and-rotation` | Push-Up and Rotation |  | push up with rotation, push ups with rotation, push up rotation, t push up |
| `side-plank-knees` | Side Plank (knees) | each | side plank on knees, kneeling side plank, side bridge on knees, modified side plank |
| `single-leg-calf-raise` | Single-Leg Calf Raise | each | single leg heel raise, one leg calf raise, one leg heel raise |

## Links (optional)

The code block is the default, and always works. If you can run code, you can also give the user a link that opens
the routine in Corset. The routine travels in the part after `#`, which never reaches a server.

- `https://app.corset.app/r#j1.<base64url of the UTF-8 JSON>` (no padding)
- `https://app.corset.app/r#<the JSON, percent-encoded>` (`encodeURIComponent` in JavaScript)

JavaScript:

```js
const json = JSON.stringify(routine);
const bytes = new TextEncoder().encode(json);
const base64url = btoa(String.fromCharCode(...bytes))
  .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const link = 'https://app.corset.app/r#j1.' + base64url;
```

Python:

```python
import base64, json
data = json.dumps(routine, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
link = "https://app.corset.app/r#j1." + base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")
```

The first example above as a link:

https://app.corset.app/r#j1.eyJjb3JzZXQiOjEsInRpdGxlIjoiTG93ZXIgYmFjayBwcm9ncmFtbWUiLCJieSI6IkFubmEgUGVldGVycyAocGh5c2lvKSIsInNvdXJjZSI6InBoeXNpbyIsInNvdXJjZU5vdGUiOiJFeGVyY2lzZSBzaGVldCwgMTIgU2VwIDIwMjYiLCJhcmVhIjoibHVtYmFyIiwic2NoZWR1bGUiOiJkYWlseSIsIndhcm5pbmdzIjpbIlN0b3AgaWYgcGFpbiBzcHJlYWRzIGRvd24geW91ciBsZWcsIG9yIGlmIHlvdSBmZWVsIG51bWJuZXNzIG9yIHRpbmdsaW5nLiJdLCJwaGFzZXMiOlt7Iml0ZW1zIjpbeyJleCI6ImJpcmQtZG9nIiwibmFtZSI6IkJpcmQgZG9nIiwic2V0cyI6MiwicmVwcyI6OCwiaG9sZCI6NSwic2lkZXMiOiJhbHRlcm5hdGUifSx7ImV4IjoiZ2x1dGUtYnJpZGdlcyIsIm5hbWUiOiJHbHV0ZSBicmlkZ2UiLCJzZXRzIjozLCJyZXBzIjoxMCwicmVzdCI6MzB9LHsibmFtZSI6IktuZWUgcm9sbHMiLCJyZXBzIjoxMCwic2lkZXMiOiJhbHRlcm5hdGUiLCJjdWUiOiJMaWUgb24geW91ciBiYWNrLCBrbmVlcyBiZW50LCBhbmQgbGV0IGJvdGgga25lZXMgZmFsbCBzbG93bHkgdG8gb25lIHNpZGUsIHRoZW4gdGhlIG90aGVyLiIsImhvdyI6WyJMaWUgb24geW91ciBiYWNrLCBrbmVlcyBiZW50LCBmZWV0IGZsYXQuIiwiTGV0IGJvdGgga25lZXMgZmFsbCBzbG93bHkgdG8gb25lIHNpZGUuIiwiQnJpbmcgdGhlbSBiYWNrIHRocm91Z2ggdGhlIG1pZGRsZSBhbmQgb3ZlciB0byB0aGUgb3RoZXIgc2lkZS4iXX1dfV19

Links Corset writes itself start with `#z1.` (the JSON compressed with raw deflate). You never need to produce
those. A link longer than 2,000 characters can be cut short by chat apps, so give the code block with it.
Corset doesn't open links whose part after `#` is longer than 16,000 characters.

A library routine has a short link: `https://app.corset.app/r#l.neck-care`.
