Skip to content

Routine and workout documents

Routines and logged workouts can be read and written as small JSON documents: exercises by name, weights in a stated unit, sets as short text. gymgym routine show <name> --json and gymgym workout show <id> --json print them; gymgym routine apply and gymgym workout apply take them back from a file or from stdin (-). A document with an id replaces that routine or workout; without one, a new one is created. The same conversion lives in @gymgym/sdk/documents for other clients.

Exercises can be written as a catalog name (barbell bench press), an everyday name (bench press, RDL), a custom exercise name, or an id; gymgym exercises <words> finds them. Invalid documents are rejected with the path of the first problem, for example exercises[2].reps: a range goes from low to high, and nothing is saved.

Field Type Required Meaning
id string Existing routine to replace; omit to create a new routine
name string yes
icon string dumbbell, barbell, bench, pullup, squat, trophy …
progression “linear” | “greyskull” | “double” | “time” | “none” How targets grow; default linear
unit “kg” | “lb” Unit of every weight in the document (default: the user’s unit)
deload boolean A planned deload: opens on these targets, never feeds progression
exercises array yes

Each entry of exercises:

Field Type Required Meaning
exercise string yes Catalog or custom exercise name, everyday name (“bench press”, “RDL”) or id
sets integer yes
reps integer or string Reps, or a range “8-12”
time integer or string Hold or cardio duration instead of reps: 45, “45s”, “1:30”
weight number or null Starting weight
rest integer or string Rest after each set (max 900 s)
superset string or null Exercises sharing a letter alternate as a superset
progression “linear” | “greyskull” | “double” | “time” | “none” | null Overrides the routine’s rule
warmups integer Warm-up sets ramped toward the work weight
drops integer Drop sets after the last work set
bursts integer Rest-pause bursts after the last work set
{
"name": "Upper A",
"progression": "double",
"unit": "kg",
"exercises": [
{
"exercise": "bench press",
"sets": 4,
"reps": "6-10",
"weight": 80,
"rest": "2:30"
},
{
"exercise": "pull-up",
"sets": 3,
"reps": "6-10",
"superset": "A"
},
{
"exercise": "dumbbell lateral raise",
"sets": 3,
"reps": "12-15",
"superset": "A"
},
{
"exercise": "weighted front plank",
"sets": 2,
"time": "45s"
}
]
}
Field Type Required Meaning
id string Existing workout to replace; omit to log a new one
name string
date string yes
start string Start time, ISO 8601 with offset (default noon UTC on the date)
minutes integer Duration
bodyweight number or null
unit “kg” | “lb” Unit of every weight in the document (default: the user’s unit)
effort “rir” | “rpe” Scale of “@” effort ratings in the sets (default: the user’s scale, else RPE)
routine string or null Id of the routine followed
notes string or null Free-text notes about the session
skipProgression boolean Exclude the entire session from progression
exercises array yes

Each entry of exercises:

Field Type Required Meaning
exercise string yes
superset string or null
note string or null Today’s note on this exercise
pinned boolean Show the note again next time
skipProgression boolean Leave this exercise out of progression
sets array yes

A set is text: 80x5 (weight × reps), x12 (reps only), bw x 12 (no load), 45s or 1:30 (holds and cardio), each optionally followed by @8 for an effort rating on the scale chosen in Settings. A planned set that was not done is { "set": "80x5", "done": false }.

{
"name": "Evening push",
"date": "2026-10-03",
"start": "2026-10-03T19:00:00+03:00",
"minutes": 50,
"unit": "kg",
"exercises": [
{
"exercise": "bench press",
"sets": [
"80x8",
"80x7@8",
{
"set": "80x6",
"done": false
}
]
},
{
"exercise": "weighted front plank",
"sets": [
"45s",
"1:00"
]
}
]
}

For validation in editors and agent frameworks (also printed by gymgym routine schema and gymgym workout schema):

Routine document schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "gymgym routine document",
"type": "object",
"required": [
"name",
"exercises"
],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Existing routine to replace; omit to create a new routine"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"icon": {
"type": "string",
"description": "dumbbell, barbell, bench, pullup, squat, trophy …"
},
"progression": {
"enum": [
"linear",
"greyskull",
"double",
"time",
"none"
],
"description": "How targets grow; default linear"
},
"unit": {
"enum": [
"kg",
"lb"
],
"description": "Unit of every weight in the document (default: the user's unit)"
},
"deload": {
"type": "boolean",
"description": "A planned deload: opens on these targets, never feeds progression"
},
"exercises": {
"type": "array",
"maxItems": 100,
"items": {
"type": "object",
"required": [
"exercise",
"sets"
],
"additionalProperties": false,
"properties": {
"exercise": {
"type": "string",
"description": "Catalog or custom exercise name, everyday name (\"bench press\", \"RDL\") or id"
},
"sets": {
"type": "integer",
"minimum": 1,
"maximum": 20
},
"reps": {
"anyOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 500
},
{
"type": "string",
"pattern": "^\\d+\\s*[-–]\\s*\\d+$"
}
],
"description": "Reps, or a range \"8-12\""
},
"time": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "string",
"pattern": "^(\\d+|\\d+:\\d{1,2}|(\\d+m)?\\s*(\\d+s)?)$"
}
],
"description": "Hold or cardio duration instead of reps: 45, \"45s\", \"1:30\""
},
"weight": {
"type": [
"number",
"null"
],
"minimum": 0,
"description": "Starting weight"
},
"rest": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "string",
"pattern": "^(\\d+|\\d+:\\d{1,2}|(\\d+m)?\\s*(\\d+s)?)$"
}
],
"description": "Rest after each set (max 900 s)"
},
"superset": {
"type": [
"string",
"null"
],
"description": "Exercises sharing a letter alternate as a superset"
},
"progression": {
"enum": [
"linear",
"greyskull",
"double",
"time",
"none",
null
],
"description": "Overrides the routine's rule"
},
"warmups": {
"type": "integer",
"minimum": 0,
"maximum": 5,
"description": "Warm-up sets ramped toward the work weight"
},
"drops": {
"type": "integer",
"minimum": 0,
"maximum": 5,
"description": "Drop sets after the last work set"
},
"bursts": {
"type": "integer",
"minimum": 0,
"maximum": 5,
"description": "Rest-pause bursts after the last work set"
}
}
}
}
}
}
Workout document schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "gymgym workout document",
"type": "object",
"required": [
"date",
"exercises"
],
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"description": "Existing workout to replace; omit to log a new one"
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"start": {
"type": "string",
"description": "Start time, ISO 8601 with offset (default noon UTC on the date)"
},
"minutes": {
"type": "integer",
"minimum": 0,
"maximum": 1440,
"description": "Duration"
},
"bodyweight": {
"type": [
"number",
"null"
],
"minimum": 0
},
"unit": {
"enum": [
"kg",
"lb"
],
"description": "Unit of every weight in the document (default: the user's unit)"
},
"effort": {
"enum": [
"rir",
"rpe"
],
"description": "Scale of \"@\" effort ratings in the sets (default: the user's scale, else RPE)"
},
"routine": {
"type": [
"string",
"null"
],
"description": "Id of the routine followed"
},
"notes": {
"type": [
"string",
"null"
],
"maxLength": 2000,
"description": "Free-text notes about the session"
},
"skipProgression": {
"type": "boolean",
"description": "Exclude the entire session from progression"
},
"exercises": {
"type": "array",
"items": {
"type": "object",
"required": [
"exercise",
"sets"
],
"additionalProperties": false,
"properties": {
"exercise": {
"type": "string"
},
"superset": {
"type": [
"string",
"null"
]
},
"note": {
"type": [
"string",
"null"
],
"maxLength": 500,
"description": "Today's note on this exercise"
},
"pinned": {
"type": "boolean",
"description": "Show the note again next time"
},
"skipProgression": {
"type": "boolean",
"description": "Leave this exercise out of progression"
},
"sets": {
"type": "array",
"minItems": 1,
"items": {
"anyOf": [
{
"type": "string",
"description": "\"80x5\", \"x12\" (reps only), \"bw x 12\", \"45s\", \"1:30\"; append \"@8\" for effort; start with \"w:\" for a warm-up, \"d:\" for a drop set, \"rp:\" for a rest-pause burst"
},
{
"type": "object",
"required": [
"set"
],
"additionalProperties": false,
"properties": {
"set": {
"type": "string"
},
"done": {
"type": "boolean",
"description": "false for a planned set that was not done"
}
}
}
]
}
}
}
}
}
}
}