The .badger file format
A .badger file is how Badger hands a routine, a gym, or a set of machines to someone
else. It is a single JSON text file, so you can open one in any text editor and read all of it.
What a file holds
- A routine file holds a program: its days, exercises, planned sets and rep targets, supersets and tempo, and, where the program has them, progression rules, percentage sets and weekly waves.
- A gym file holds a gym's equipment: machines, attachments, bars, accessories, dumbbell and kettlebell racks, and plates.
- A machines file holds just machines.
A file never holds your workout history: no logged workouts, sets or PRs, no training max, and nothing about you. To move your own history to a new phone, use a backup instead (see moving to a new phone). The full list is under what a file does not carry.
Opening a file on your phone
Tap the file wherever it arrived (a message, an email, a download), or open it from your file manager (Files on an iPhone). Badger shows a preview of what the file will add before anything is saved.
Importing only adds. Nothing you already have is changed, and exercises you already have are matched by name and type, so they keep their history.
Where to find ready-made files
Programs has every program built into Badger as a file you can download and open. To have an AI write one for you, the Use your own AI guide has a prompt for it. The rest of this page is the specification, for anyone writing a file by hand, with a tool, or with an AI.
Specification
From here to the end, this page defines what a file may contain and what import does with it.
Fields marked required must be present. Any other field may be left out or written as
null, and either reads as absent. Unknown fields are ignored.
Keys marked "Needs Badger 1.1.12 or later" are ignored by older versions; see versions and compatibility.
Terms used below
- Slot: one exercise on one day of a routine, with its planned sets. A slot is
a
DayExercise. - Progression group: the slots of one routine that share a
progression_group_key, on any of its days. They progress as one: a single reference weight, failure counter, stage and remembered weight between them. A rule in the group reads sessions from its own day and from the days of the other members that carry a rule. A slot with no key is a group of its own. - Training max: the number a set's percentage is taken from. A progression rule moves it, and it never goes on the bar itself.
- Reference weight: the number a slot's percentage sets are a percentage of.
Under a rule whose
reference_kindistraining_max, it is the training max. Each lifter has their own, and a file never carries it. Slots in one progression group share one. A slot with no reference weight of its own takes another slot's; seepercent_reference. - Waved day: a day whose sets change by week of a repeating cycle (5/3/1's four weeks) or by stage. Each version of the day's sets is a variant. See Waves.
- Stage: on a stage-based day (GZCLP, StrongLifts), which of the day's set
variants the slot is on, counting from 0. Only
next_stageandreset_stagemove it. - Driver set: the one planned set whose logged reps some triggers read, marked
with
is_progression_driver. - Missed session (a failure): a session of this slot in which at least one logged working set was left incomplete or came in under its planned minimum. A skipped set counts neither way. A session where every logged working set met its minimum is a success. A session with no completed set of the exercise at all is neither, and the rule ignores it.
- Failure counter: the run of missed sessions in a row. A success resets it to
0, and so does a
consecutive_failures_at_leastorstage_is_lastclause firing.holdlets it move;noneundoes this session's change to it. - Remembered weight: the slot's weight as it stood while the slot was on its
first stage, recorded each time the rule reads a session there.
set_from_rememberedrestarts from it.
The envelope
Every file has the same five top-level fields. Import needs three of them.
| Field | Type | Meaning |
|---|---|---|
badger | string, required |
Schema version. Today it is always share/v1. A file with any other value is
refused.
|
app_version | string | The app version that wrote the file, for example 1.1.1. Informational. |
created_at | string | UTC timestamp in ISO 8601. Informational. |
type | string, required |
One of routine, gym, machines. Any other value and
the file is rejected as invalid.
|
payload | object, required | The contents. Its shape depends on type: a routine payload or a gym or machines payload. |
Files Badger writes leave optional fields out rather than writing null.
A routine payload
type: "routine". The payload has four keys. Only routine is required:
a missing days, exercises or machines reads as an empty
list, though a routine needs days and exercise definitions to be of any use.
| Key | Type | Contents |
|---|---|---|
routine | Routine, required | The routine itself: name, notes, and its settings. |
days | array of Day | The days, in order. Each day carries its own exercises array: that day's slots, in order, with their planned sets. |
exercises | array of Exercise | The definition of every exercise any day references: its name, type, and category. Slots point into this list by exercise_name. |
machines | array of Machine | Machines the slots pin. May be left out. The import preview asks before creating any. |
Two arrays are called exercises. The top-level one is an array of
Exercise and defines what each exercise is. Each day's
exercises is an array of DayExercise: that
day's slots, which point at the definitions by name. A slot whose name matches no definition is
skipped, and the import preview warns about it.
Routine
The object in the payload's routine key.
| Field | Type | Meaning |
|---|---|---|
name | string, required | The routine name. |
notes | string | Program-level notes. |
weight_source | string |
Where starting weights come from: last_performance (default),
routine_defaults, or routine_defaults_then_last.
|
history_scope | string |
Which history the weight lookup reads: any_workout (default) or
this_routine.
|
Day
The objects in days, one per session in the program.
| Field | Type | Meaning |
|---|---|---|
name | string, required | Day name, for example "Push" or "Workout A". |
scheduled_days | array of integers |
Weekdays this day is scheduled on: [1, 3, 5] means Monday, Wednesday,
Friday. 1 is always Monday and 7 is always Sunday, whatever the app's first-day-of-week
setting and wherever the file is opened. Values outside 1 to 7 are dropped on import.
Leave the field out for a program you rotate through instead of pinning to weekdays.
|
default_gym_name | string | Gym this day defaults to. The gym is created on import if the name is new. |
cycle_length | integer |
How many set variants this day cycles through, if it is waved:
4 for a 5/3/1 day (four weeks), 3 for a GZCLP day (three
stages). Leave it out for a day that runs the same session every time. When it is
present, each set's week_index says which
variant the set belongs to. Waves explains what picks the variant.
Needs Badger 1.1.12 or later.
|
exercises | array of DayExercise | The day's slots. Left out, the day imports empty. |
Exercise
The objects in the payload's top-level exercises: the definitions the slots point
at. List only the exercises the routine uses. Import matches each one against the recipient's
library first, so most usually resolve to exercises they already have.
| Field | Type | Meaning |
|---|---|---|
name | string, required | Matching is by name, so plain full names travel best. "Barbell Back Squat" lands on the recipient's existing squat; "BB Squat (heavy day)" creates a new exercise. |
type | string |
One of weight_reps (the default), reps_only,
time_only, distance_only, weight_only,
weight_time, weight_distance, reps_time,
reps_distance, distance_time. An unrecognized value falls back to
weight_reps.
|
category_name | string | Category for an exercise that has to be created. Any name is valid: an existing category is reused by name, a new name creates one, and absent reads as "Other". A fresh install has Chest, Back, Shoulders, Biceps, Triceps, Legs, Core, and Cardio. These are not a fixed list, since categories can be renamed or deleted, but using them puts new exercises where most libraries already sort them. |
DayExercise
The objects in a Day's exercises array. Each is one
slot: one exercise on that day, with its planned sets.
| Field | Type | Meaning |
|---|---|---|
exercise_name | string, required | Must match a name in the payload's exercises list. |
exercise_type | string, same values as Exercise.type |
The referenced exercise's type, repeated here. Optional, but include it: it tells a
"Plank" you time apart from a "Plank" someone counts reps on. When present it must
exactly equal the definition's type, because import matches the slot by
name and type together. A mismatch matches nothing, and the slot is skipped and counted
in the import preview's warning, like an unmatched name.
|
rest_override_seconds | integer | Rest for this slot, when it should differ from the exercise's own default. |
default_machine_name | string |
Machine this slot is pinned to, by name. Import looks for it among the recipient's own
machines and the payload's machines list, so a machine the recipient already
has does not need to be in the file. Include it in machines if the file
should also work for someone who lacks it. A name that matches nothing leaves the slot
unpinned. Import links the matched machine to the exercise.
|
superset_key | string |
Slots in the same day sharing a key become a superset, in the order they appear. The key
can be anything ("1", "a"); it only has to match between the
members. A key held by a single slot is ignored.
|
superset_name | string | Display name for the superset. The first member's value wins. Leave it out and the app names the group itself. Group color does not travel: the recipient's own palette assigns it. |
tempo | string | Tempo prescription for the slot, carried word for word, for example "3-1-2-0". |
alternatives | array of objects |
Swap options for this slot, in order. Each is
{ "exercise_name": "...", "exercise_type": "..." }, with
exercise_name required, and is matched by the same rules as the slot itself,
so each needs a definition in the payload's exercises list. An unmatched
alternative is skipped and counted in the import preview's warning.
|
progression | Progression | This slot's progression rule: what happens to its weight next session. At most one per slot. Leave the key out for a slot with no rule. Needs Badger 1.1.12 or later. |
progression_group_key | string |
Slots anywhere in the routine sharing a key form one
progression group and progress as one. StrongLifts groups
the squat on Workout A with the squat on Workout B, so three misses in a row count across
both days. Only the sessions of members that carry a progression rule move
the group; a member with no rule reads the group's number, as Madcow's Monday and
Wednesday squats do. Give different lifts, and two tiers of one lift (GZCLP's T1 and T2),
different keys.
The key can be anything ( "sl-squat", "1"); it only has to match
between the members, case included. Surrounding spaces are ignored, and an empty key
reads as absent. Import gives each group a new key of its own and keeps who is in it.
Leave the key out and the slot's progress is its own. A key no other slot shares also keeps
progress separate, but it stops a percentage set on that slot from borrowing a reference
weight (see percent_reference), so leave the key out rather than giving a slot
one of its own. Needs Badger 1.1.12 or later.
|
percent_reference | object |
The lift this slot's percent_of_reference
sets are a percentage of, when it is a different lift: close-grip bench at 80% of the
bench press's training max. Written like an alternative,
{ "exercise_name": "...", "exercise_type": "..." } with
exercise_name required, and matched against the payload's
exercises list by the same rules.
It applies while the slot has no reference weight of its own. The slot then takes the reference weight of a slot in this routine that programs the named lift and carries a rule, and looks nowhere else. Leave the key out and the reference weight comes from the slot's progression group if the slot has a progression_group_key, and
otherwise from a ruled slot in the routine programming the same exercise.
A name that matches no definition, or that names the slot's own exercise, reads as absent. A lift the routine does not program is kept: the log preview says those sets need a reference weight, and their weight can be typed in. Do not put the two lifts in one progression group to get this, since a group also shares one failure counter and one stage. Needs Badger 1.1.12 or later. |
predefined_sets | array of PredefinedSet | The planned sets. May be left out or empty. |
PredefinedSet
The objects in a DayExercise's
predefined_sets, one per planned set. Fill in the fields the exercise type uses:
weight and reps for a bench press, duration_seconds for a plank,
distance for a row. Leave out fields that do not apply.
| Field | Type | Meaning |
|---|---|---|
is_warmup | boolean, defaults to false | Marks a warmup set. Warmup sets do not count toward working volume. |
weight | number |
A planned weight, in the unit named by weight_unit. Most shared programs
leave it out so each lifter's own weights fill in.
|
weight_unit | string | "kg" or "lbs". Weights are stored in the unit they were entered in, never converted. Absent means kg. |
reps | integer | The rep target. With reps_max present it is the bottom of a range instead. |
reps_max | integer |
Top of a rep range: reps: 8, reps_max: 10 reads as 8-10. Leave it out for an
exact target. Never valid on a warmup; import drops it there.
|
is_amrap | boolean, defaults to false |
An open-topped target: reps becomes a required minimum with no ceiling,
shown as 8+. reps: 1, is_amrap: true is how a set to failure is
written. Mutually exclusive with reps_max: if a set carries both, import
keeps the open target and drops the range. Never valid on a warmup.
|
duration_seconds | integer | Planned time, for timed exercises. |
distance | number | Planned distance in kilometers. |
percent_of_reference | number |
This set's weight as a percentage of the slot's
reference weight: 85.0 is 85%. Badger works out
the load from the recipient's own reference weight and snaps it to a weight they can
load. Leave it out for an ordinary set with an absolute weight. Import accepts values
above 0 and up to 200; anything outside that is read as an ordinary absolute-weight set.
weight is optional beside it. While the percentage applies,
Badger ignores the weight but keeps it, so turning the percentage off restores the
number. The built-in program files leave the weight out. Needs Badger 1.1.12 or later.
|
is_progression_driver | boolean, defaults to false |
Marks the driver set: the set whose logged reps the
driver_reps_at_least, driver_reps_between,
driver_reps_below_plan and cycle_missed_minimum triggers read.
At most one per week of the slot's cycle, and never on a warmup. On a
waved day each week_index may have its own driver, as
5/3/1's plus set does in weeks 1 to 3. A set with no week_index belongs to
every week, so it rules out any other driver in the slot. If a file carries more than
that, import keeps the first in array order and clears the rest, and a driver on a
warmup is dropped. Needs Badger 1.1.12 or later.
|
week_index | integer |
Which week of its day's cycle this set belongs to, counting from
0. Leave it out and the set applies to every week: that is how
every set on an unwaved day is written, and how a 5/3/1 file writes its accessory work
once instead of four times. A value at or above the day's cycle_length is
out of range, and the set applies to every week.
|
target_rpe | integer |
How hard the set should feel, on the RPE scale: 8 is RPE 8, about two reps
left in reserve. Whole numbers from 6 to 10. Import rounds a half up (8.5
becomes 9) and moves a value outside 6 to 10 to the nearer end. Mutually exclusive with
target_rir: if a set carries both, import keeps target_rpe and
drops target_rir. Never valid on a warmup; import drops it there. It is shown
on the set as a target, and no progression trigger reads it. Needs Badger 1.1.12 or
later.
|
target_rir | integer |
The same target in reps in reserve: 2 means stop with two reps left. Whole
numbers from 0 to 5. Import drops any fraction (2.5 becomes 2) and moves a
value outside 0 to 5 to the nearer end. Write target_rpe or
target_rir, never both. Never valid on a warmup; import drops it there.
Needs Badger 1.1.12 or later.
|
is_unilateral | boolean | true plans the set for each arm: one target, reps and
optionally reps_max, that applies to the left and to the right. Leave the key
out when the set is not marked. It only takes effect on an exercise whose
unilateral_mode resolves to "optional", or to
"always", where every set is left and right anyway. Needs Badger 1.1.14 or later.
|
Waves: cycle_length and week_index
A day whose sets change from week to week is written once, not once per week. 5/3/1's four-week cycle is the standard case. Two keys do it, and they only make sense together. Both need Badger 1.1.12 or later.
-
Day'scycle_lengthsays how many weeks the cycle runs for. Absent means the day is not waved. -
Each
PredefinedSet'sweek_indexsays which week that set belongs to, counting from 0. Absent means every week, which is how accessory work done all cycle long is written once.
A week_index that matches no week (negative, or at or above the day's
cycle_length) is read as every week. The recipient starts the program at its first
week: which week the sender is on does not travel.
The week counter belongs to the routine, not the day. It is one number that every waved day in the routine reads. It moves on once every day waved to the same length has been trained since the last move. Stage-based days (below) do not move it.
Each day reads the counter against its own cycle_length, so give every waved day in
a routine the same length. cycle_complete fires when the counter wraps back to the
first week. If lengths differ, each length moves the shared counter on its own schedule, and
cycle_complete wraps at each day's own length.
Stage-based programs (GZCLP, StrongLifts) use the same two keys, with each
week_index a stage and cycle_length the number of stages.
A slot whose
rule has a next_stage or reset_stage clause, or any clause targeting
stage, shows the variant for its current stage. The stage changes only when one of
those clauses fires; in GZCLP and StrongLifts that happens when you stall. Every other slot shows
the variant for the routine's current week.
A complete routine file
One routine, one day scheduled Monday and Thursday, two exercises. The bench press has a warmup set and three working sets of 8-10; the plank is timed. This is the real example-routine.badger, indented for reading. Files the app writes are minified, and whitespace makes no difference either way.
{
"badger": "share/v1",
"app_version": "1.1.11",
"created_at": "2026-09-13T05:09:30.410810Z",
"type": "routine",
"payload": {
"routine": {
"name": "Example Routine",
"notes": "A two-exercise day, kept small enough to read.",
"weight_source": "last_performance",
"history_scope": "any_workout"
},
"days": [
{
"name": "Day 1",
"scheduled_days": [
1,
4
],
"exercises": [
{
"exercise_name": "Flat Barbell Bench Press",
"rest_override_seconds": 180,
"exercise_type": "weight_reps",
"predefined_sets": [
{
"is_warmup": true,
"reps": 8
},
{
"is_warmup": false,
"reps": 8,
"reps_max": 10
},
{
"is_warmup": false,
"reps": 8,
"reps_max": 10
},
{
"is_warmup": false,
"reps": 8,
"reps_max": 10
}
]
},
{
"exercise_name": "Plank",
"exercise_type": "time_only",
"predefined_sets": [
{
"is_warmup": false,
"duration_seconds": 60
},
{
"is_warmup": false,
"duration_seconds": 60
}
]
}
]
}
],
"exercises": [
{
"name": "Flat Barbell Bench Press",
"type": "weight_reps",
"category_name": "Chest"
},
{
"name": "Plank",
"type": "time_only",
"category_name": "Core"
}
],
"machines": []
}
} For files that use progression rules, percentage sets and waves, open the files on the Programs page, such as 531-bbb.badger and gzclp.badger.
Progression rules
A slot's progression rule says what happens to its weight after each session. It is a
Progression object holding a list of
Clause objects. The example
below shows a complete one.
Progression
The object in a DayExercise's progression
key. At most one per slot. Needs Badger 1.1.12 or later.
The rule travels; the sender's progress against it does not, including their
training max (see what a file does not carry). A
training_max key written into a file is an unknown key and is ignored.
| Field | Type | Meaning |
|---|---|---|
cadence | string, required |
How often the program means the rule to be looked at: session,
week or cycle. Badger stores it and nothing reads it, like
scheme below. Badger evaluates the most recent qualifying session whenever
the log preview opens. An unrecognized value still drops the whole rule.
|
reference_kind | string, required |
Which number the rule moves: working_weight (a real weight on the bar) or
training_max. A working_weight rule may not carry a clause
targeting reference, and a file that has one loses the rule.
|
clauses | array of Clause, required |
The rule itself, in evaluation order: the first clause whose trigger
matches is the one that fires. Any clauses directly after it that state the same
trigger with the same numbers, and move a different target,
fire with it; that is how one outcome both resets the stage and cuts the weight. Nothing
else runs. Must be non-empty and must end with an always clause.
|
scheme | string |
Where the rule came from, as a label: linear,
double_progression, gzclp_t1, gzclp_t2,
gzclp_t3, wave_531, nsuns_t1,
nsuns_t2, madcow_weekly, custom. Nothing behaves
differently because of it; the clauses are the behavior. An unrecognized value reads as
custom, and the rule still imports.
|
note | string |
The author's own line about the rule. Displayed word for word and never parsed, like an
accessory's label.
|
Clause
The objects in clauses. Each one is a trigger and the action it fires.
count, reps_min and reps_max belong to the trigger;
target, amount, amount_unit and percent
belong to the action. The terms missed session, failure counter, stage and remembered weight are
defined under Terms used below, at the start of the specification.
| Field | Type | Meaning |
|---|---|---|
trigger | string, required |
What makes the clause fire. One of:
|
count | integer |
How many qualifying sessions in a row the trigger needs. Leave it out and the trigger
fires on a single occurrence. A written 1 behaves the same as an absent key,
but Badger prints the written one as "for 1 session".
|
reps_min / reps_max | integer |
Inclusive rep bounds for driver_reps_at_least and
driver_reps_between. With both left out, the trigger does not look at reps
at all; they are never defaulted to zero or to the plan's own numbers. Either of those
two triggers with no reps_min, or a reps_max below the
reps_min, drops the whole rule.
|
action | string, required |
What happens when it fires. One of:
|
target | string, required |
What the action moves: working_weight, reference (the training
max), stage, or increment. Required on every clause, including
hold and none. The pairs Badger's own programs use:
reference in a
working_weight rule.
|
amount | number |
The absolute amount, in the unit named by amount_unit. Required for
add_absolute and set_from_remembered; leaving it out on either
drops the whole rule. It never falls back to the exercise's own increment, so write the
number.
|
amount_unit | string | "kg" or "lbs", for amount. Absent means kg. |
percent | number |
The percentage for add_percent: -10 means drop 10%. Required
for that action and meaningless for any other.
|
If a rule breaks any of these, import skips the whole rule and counts it in the import preview's warning. The rest of the file imports normally.
- An unrecognized
trigger,action,target,cadenceorreference_kind. - A
driver_reps_at_leastordriver_reps_betweentrigger with noreps_min. (driver_reps_below_plantakes its minimum from the plan.) - A
driver_reps_betweenwhosereps_maxis below itsreps_min. - A missing
amountorpercentthat the action requires. - A clause targeting
referenceunderreference_kind: "working_weight". - No clauses at all, or a
clausesarray that does not end with analways. Analwaysin the middle leaves every clause after it unable to fire. - A clause that can never fire because an earlier one already covers it, such as
consecutive_failures_at_least2 before the same trigger at 3, or a run of same-trigger clauses that moves one target twice.
Example: a linear rule
Add 2.5 kg after every session in which all working sets hit their target, take 10% off after three missed sessions in a row, and otherwise keep the weight. This is one slot, with three sets of 5:
{
"exercise_name": "Barbell Back Squat",
"exercise_type": "weight_reps",
"progression": {
"scheme": "linear",
"cadence": "session",
"reference_kind": "working_weight",
"clauses": [
{
"trigger": "consecutive_failures_at_least",
"count": 3,
"action": "add_percent",
"target": "working_weight",
"percent": -10
},
{
"trigger": "all_sets_met",
"action": "add_absolute",
"target": "working_weight",
"amount": 2.5,
"amount_unit": "kg"
},
{
"trigger": "always",
"action": "hold",
"target": "working_weight"
}
]
},
"predefined_sets": [
{
"is_warmup": false,
"reps": 5
},
{
"is_warmup": false,
"reps": 5
},
{
"is_warmup": false,
"reps": 5
}
]
}
Badger reads the clauses in order and fires the first that matches. After a third missed session
in a row, the first clause takes 10% off and resets the failure counter to 0. After a session
where every planned working set reached 5 reps, the second clause adds 2.5 kg. Any other session
reaches the always clause, and the weight holds while the failure counter still
moves.
The rule ends with always, every clause names a target, and
add_absolute and add_percent carry the amount and
percent they need, so none of the conditions above drops it.
Gym and machines payloads
type: "gym" shares a whole gym: the gym itself, its machines, attachments, bars and
accessories, which of each belong to it, its dumbbell and kettlebell racks, and its plates.
type: "machines" is the smaller version: one key, machines, an array
of Machine, with no gym, bars, accessories, or inventory.
A gym file carries what describes the gym. Notes about a machine travel. Your photo of it, and the setup cues you saved against one exercise on it, stay on your phone.
| Field | Type | Meaning |
|---|---|---|
gym | Gym, required | A Gym is just { "name": "..." }. |
machines | array of Machine | The same Machine objects a routine payload carries. |
attachments | array of Attachment | An Attachment is a name and optional notes. |
bars | array of Bar | Named bars. Omitted when the gym has none. |
accessories | array of Accessory | Bands, chains, and straps. Omitted when the gym has none. |
gym_machines | array of strings | Names of the machines that belong to this gym. |
gym_attachments | array of strings | Names of the attachments that belong to this gym. |
gym_bars | array of strings | Names of the bars that belong to this gym. |
gym_accessories | array of strings | Names of the accessories that belong to this gym. |
racks | array of Rack | The gym's dumbbell and kettlebell racks. Omitted when the gym has none set up. |
plate_inventory | array of PlateInventory | The plates the gym actually has. Omitted when nobody has set them up. |
Equipment is defined in its own arrays, and the four gym_* lists name which of it
belongs to this gym, so one machine can belong to several gyms. Files Badger writes list exactly
the objects defined beside them.
Leave a membership list out to include everything
defined in the file. Writing it as [] means none of them, which leaves the
gym with nothing of that kind and is almost never what you want.
Machine
The objects in machines, in a routine payload and a gym or machines payload alike.
In a routine payload, importing the machines is a toggle the recipient controls. In a gym or
machines payload, machines are always created.
| Field | Type | Meaning |
|---|---|---|
name | string, required | Machine name. |
notes | string | Free text about the machine, such as "third from the left, seat pin sticks". |
uses_attachments | boolean, defaults to false | Whether the machine takes attachments (bars, handles, ropes). |
uses_grip_types | boolean, defaults to false | Whether grip is worth recording on this machine. |
supports_bands | boolean, defaults to false | Whether bands can be attached here. It decides whether a machine exercise offers accessories at all, and then only band-kind ones. |
machine_type | string | "selectorized" (a stack with a pin) or "plate_loaded". |
weight_increment | number | Smallest real step on this machine, in the machine's own unit. |
weight_increment2 | number | Second step size, for a stack whose plates get heavier further up. |
increment_threshold | number | Weight at and above which weight_increment2 applies. |
plate_calculator_mode | string | "dual_loaded" (plates on both sides) or "single_loaded" (one
lever arm).
|
bar_weight | number |
Weight of the bar or empty carriage, in the unit named by bar_weight_unit,
so a 45 lb bar travels as 45.
|
bar_weight_unit | string | "kg" or "lbs", for bar_weight. |
weight_unit | string | "kg" or "lbs", when this machine is labeled in a different unit from the rest of your logging. Absent means the machine follows the recipient's own logging unit, and weight_increment, weight_increment2 and increment_threshold are read in that unit. Write it whenever the file states those numbers. |
logs_weight_per_side | boolean |
What a weight logged on this machine means: true for one side (iso-lateral
machines), false for the total. Leave the key out if the machine has no
preference; Badger then uses the exercise's own setting, which is not the same as
writing false. Only meaningful on a plate-loaded machine; a value on any
other kind is ignored.
|
unilateral_mode | string |
Whether sets logged on this machine are left and right: "off",
"optional" or "always". It overrides the exercise's own setting,
including "off". Leave the key out if the machine has no preference. Any other
value is read as absent. Needs Badger 1.1.14 or later.
|
Bar
The objects in bars: a named bar, with its own weight.
| Field | Type | Meaning |
|---|---|---|
name | string, required | Bar name, for example "Olympic bar" or "Trap bar". |
notes | string | Free text about the bar. |
bar_weight | number |
What the bar weighs empty, in the unit named by bar_weight_unit, so a 45 lb
bar travels as 45. Leave it out for a bar nobody has weighed; Badger then
falls back to the machine's or the exercise's own bar weight.
|
bar_weight_unit | string | "kg" or "lbs", for bar_weight. Absent means kg. |
Accessory
The objects in accessories: a band, a chain, a set of suspension straps, or another add-on.
| Field | Type | Meaning |
|---|---|---|
name | string, required | Accessory name, for example "Green band". |
kind | string |
One of band, chain, suspension, other.
A missing or unrecognized value reads as other.
|
color | integer |
Packed ARGB, for example 4283215696. Omitted when the accessory has no color
set. It travels because people name a band by its color.
|
label | string |
Free text shown beside the name, for example "rated 25 lbs". Carried word
for word and never parsed. Accessories never feed any calculation in Badger, so a number
in here stays text.
|
notes | string | Free text about the accessory. |
Rack
The objects in racks: the dumbbells or kettlebells a gym owns. List every weight on
the rack, since racks do not step evenly (5, 10, 15 up to 50, then a jump). The plus and minus
buttons step through this list when you log.
| Field | Type | Meaning |
|---|---|---|
equipment | string, required | "dumbbell" or "kettlebell". Any other value is skipped. |
unit | string, required | "kg" or "lbs", for every weight in this rack. |
weights | array of objects, required |
Each one is a weight (number, required) and an optional color
(packed ARGB integer), for competition kettlebells, which are identified by color. Leave
the color out for an unpainted weight.
|
One entry per equipment-and-unit pair, so a gym with kilogram kettlebells and pound dumbbells carries two. Nothing is converted between them: 45 in a pound rack is a 45 lb dumbbell.
PlateInventory
The objects in plate_inventory: what the plate calculator has to work with.
| Field | Type | Meaning |
|---|---|---|
unit | string, required | "kg" or "lbs", for every number in this entry. |
bar_weight | number | The bar the calculator starts from, in the unit above, so 45 in a pound entry is a 45 lb bar. Absent falls back to the ordinary bar for that unit. |
plates | array of objects, required |
Each one is a weight (number, required), a color (packed ARGB
integer), a quantity (how many are available per side, defaults to
2) and enabled (defaults to true). A plate that exists but is switched off
has enabled: false.
|
One entry per unit, and nothing converts between them. A gym still on Badger's built-in default
plates writes no plate_inventory at all.
What import does
- Nothing is overwritten. Import only adds. An existing exercise, machine, gym, or routine is never edited by a file you open.
- Exercises match on name and type, ignoring case and surrounding spaces. The same name with a different type is a different exercise. With no match, the exercise is created in the named category, which is created too if it is new.
- Machines, attachments, bars, accessories, gyms, and categories match on name alone, again ignoring case and spaces.
- A routine name collision does not merge. Importing a routine whose name you already use gives you "Name (imported)", then "Name (imported) 2", and so on. You keep both.
- It is one transaction. A file that fails partway through leaves your database exactly as it was.
- Days, slots, and sets import in array order.
- A warmup never carries a rep range or an open target. Import drops
reps_maxandis_amrapfrom a warmup set. A working set carrying both keeps the open target and loses the range. - An unreadable progression rule is skipped whole and counted in the import
preview's warning; the rest of the file imports normally. What drops a
rule is listed with the clause fields. Per-set flags are repaired instead: extra driver
sets are cleared as described under
is_progression_driver, a driver on a warmup is cleared, and aweek_indexorpercent_of_referencethat cannot mean anything is read as absent. An intensity target is repaired as described undertarget_rpe. - Files over 10 MB are refused without being read.
What a file does not carry
A routine file is the plan, and only the parts of it that work for a different lifter in a different gym.
- No history. No workouts, no logged sets, no PRs. To move your own history to a new phone, use a backup instead: see moving to a new phone.
- No notes below the routine level. Routine notes travel; per-day and per-exercise notes do not. In a gym file, notes on a machine, attachment, bar or accessory do travel. The setup cues you save against one exercise on one machine never do.
- No default attachment, default bar, or default grip on a slot, and no superset group color; the recipient's palette assigns it. (An accessory's color does travel.)
- No training max, and no progress against a rule. A slot's progression rule travels. The training max it multiplies does not, and neither does any counter behind it: a run of missed sessions, a stage, a cycle position, which session was last evaluated. The recipient sets their own training max, from their own history, the first time they run the program.
- No per-exercise detail beyond name, type, and category. An exercise that gets created on import starts blank: no instructions, no muscles, no rest default, no increment. Anything you already had keeps everything it already has. That includes an exercise's own Log left and right separately setting, which never travels, like its per-side weight setting. A machine's
unilateral_modedoes. - No photos of machines, attachments, or bars.
- Nothing about you. No account, no device identifier, no settings, no training notes.
Versions and compatibility
Unknown fields are ignored, so a file written by a newer Badger still opens in an older one,
minus whatever that older version has no concept of. If the shape ever has to change in a way
that breaks, badger gets a new value and share/v1 keeps being read.
A file you exported today should still import years from now. See also the promise.
- Optional keys are left out when unused. A file that uses none of the newer keys is byte-identical to one written before they existed, and an older copy of Badger reads it unchanged.
- 1.1.12 keys.
progression,progression_group_key,percent_reference,percent_of_reference,is_progression_driver,cycle_length,week_index,target_rpeandtarget_rirneed Badger 1.1.12 or later. An older version ignoresprogressionand imports the slot without a rule. When a percentage set also carries aweight, an older version that has never heard ofpercent_of_referencestill finds the weight as the target. It reads a set with an intensity target as the same set with no target. -
is_amrapis omitted when false. Becauserepsstill holds the minimum, an older version reads an open target as an exact one. -
logs_weight_per_side: older versions ignore the key and lose nothing else. - 1.1.14 keys. A machine's
unilateral_modeand a set'sis_unilateralare omitted when not set. An older version ignores both and imports the routine or machine without them, so the sets read as ordinary both-arms sets. - Older values still read.
machine_type: "plateLoaded"; the camelCaseplate_calculator_modevalues; a machine'sbar_weight_kg(always kg) in place ofbar_weightandbar_weight_unit; and the retiredsort_orderfield, which is ignored.
Last checked against Badger 1.1.11, schema share/v1. The
example above and the files on the Programs page were exported by that
build and imported back into it before publishing. The progression,
percentage, driver and wave keys were checked against Badger 1.1.12's own
import and export code. The published files are regenerated whenever the seeded programs
change.