Reppie Authoring Guide

View raw markdown

Reppie Authoring Guide

Version: 1.1 · Last updated: 2026-05-07 · Audience: human authors and AI assistants creating exercises and workouts for Reppie.

This document is the single source of truth for how exercises and workouts must be constructed in Reppie. AI assistants generating content for Reppie should treat every rule below as binding — if a request conflicts with a rule, follow the rule and explain the deviation.


0. Quickstart for AI assistants

If you're an AI assistant who has been asked by a Reppie user to build them a workout, this is your starting point. The user has copied a short prompt to you, and the full instructions live in this guide. Read it, then reply.

Your job in 5 steps:

  1. Understand the request. Read what the user asked for. Identify the target duration, body focus, equipment, level, and any constraints.
  2. Pick a structure. See §6.3 (warm-up + main blocks + optional finisher + cool-down) and §6.4 (series, target, rest defaults by training goal).
  3. Choose exercises. Use canonical English names where possible — Reppie reuses existing public exercises by name (§10.9). Lock muscles[] to §5.3 and equipment[] to §5.4 (both arrays are always English).
  4. Hit the target time. Compute total time per §3 / §10.8 and iterate until you are within ±5 % of the user's target. Don't under-deliver: a 60-min request answered with a 39-min plan is a failure.
  5. Format your reply. Exactly as §10.1 describes: one ```json code block, then a ⏱ Total: … audit line, then a 👉 reminder line in the user's language. No preamble, no commentary outside the code block.

Three rules that catch out almost everyone:

The full worked reply example is in §10.10. When in doubt, copy its shape exactly.

If your tooling allows fetching URLs, you have already done the most important step — reading this guide. Good luck.


1. What Reppie is

Reppie is an interval-style workout player. A user opens a workout, presses Play, and Reppie walks them through a linear sequence of timed steps with audio cues. Reppie is not a long-term programming tool (no week-by-week mesocycles, no progressive overload tracking). Each workout is self-contained and is intended to be played end-to-end in a single session.

Two primitives:

The same exercise can appear in many workouts with different parameters. Series count, target value (time or reps), and inter-series rest are properties of the workout item, never of the exercise.


2. Domain glossary

Term Meaning
Exercise Reusable movement definition. No timing data.
Workout Ordered sequence of items + metadata (title, cover, description, visibility).
Workout Item One row in the workout list. Either type: "exercise" (links to an exercise, has series/target/rest) or type: "break" (standalone rest).
Series One round of the exercise. An item with series_count: 3 plays the exercise 3 times with rest_seconds between consecutive series.
Break (item) A standalone rest between exercises. Two flavours: timed (target_type: "time") and open-ended (target_type: "pause" — user must press Continue).
Series rest The automatic rest between consecutive series inside one item (controlled by rest_seconds on that item). Not a separate item in the list.
Get Ready A 5 s (configurable) lead-in step inserted automatically before the first exercise. The user does not author it.
Step A single segment shown by the player. Steps are derived from items: get_ready, exercise, series_rest, break, paused_rest.
Target type time (target_value = seconds), reps (target_value = number of reps; duration = reps × seconds_per_rep), pause (open-ended; only for breaks).

3. How total workout time is calculated

This is the formula AI must use to hit a user's time budget.

3.1 Step expansion

For each enabled item in order, the player produces steps:

  1. Once at the very start: get_ready (default 5 s; user-overridable in profile).
  2. For each item:
    • If the item is a break with target_type: "time" → one break step of target_value seconds.
    • If the item is a break with target_type: "pause" → one paused_rest step (duration = 0; does not count toward total time).
    • If the item is an exercise with series_count = N:
      • Series 1 → exercise step.
      • If rest_seconds > 0 and not the last series → series_rest step.
      • … repeat …
      • Series N → exercise step (no series_rest after the last series).

3.2 Per-step duration

Step kind Duration
get_ready profile setting, default 5 s
exercise (target_type time) target_value seconds
exercise (target_type reps) target_value × seconds_per_rep (default seconds_per_rep = 3)
series_rest rest_seconds of the parent item
break (timed) target_value seconds
paused_rest 0 (excluded from total)

3.3 Item-level formula

For an exercise item:

exerciseDuration =
  target_type == "reps"
    ? target_value * seconds_per_rep
    : target_value

itemTime = series_count * exerciseDuration
         + max(0, series_count - 1) * rest_seconds

For a timed break item: itemTime = target_value. For a pause break item: itemTime = 0.

3.4 Workout total

totalTime = get_ready_seconds + Σ itemTime  (over enabled items)

paused_rest steps are never included in totals shown to the user, in stats, or in time-budget planning. If the user asks for "a 25-minute workout," design without relying on pause breaks to fill time.

3.5 Worked example

User asks: "30-minute full-body workout." Get Ready = 5 s.

# Item Series Target Rest Item time
1 Jumping Jacks (warm-up) 1 60 s 0 60
2 Break (timed) 30 s 30
3 Goblet Squat 3 12 reps × 3 s/rep 30 s 3·36 + 2·30 = 168
4 Push-Up 3 10 reps × 3 s/rep 30 s 3·30 + 2·30 = 150
5 Bent-Over Row 3 10 reps × 3 s/rep 30 s 3·30 + 2·30 = 150
6 Break (timed) 60 s 60
7 Plank 3 40 s 20 s 3·40 + 2·20 = 160
8 Russian Twist 3 30 s 20 s 3·30 + 2·20 = 130
9 Break (timed) 30 s 30
10 Cool-down stretch (timed) 1 90 s 0 90

Sum = 60 + 30 + 168 + 150 + 150 + 60 + 160 + 130 + 30 + 90 = 1028 s. Plus Get Ready 5 s ⇒ 1033 s ≈ 17:13. Below budget — add work.

The AI must iterate on parameters (series, target, rest) until totalTime is within ±5 % of the requested time, without padding with pause breaks.

3.6 Field hard limits (DB constraints)

These will reject the row if violated — never produce values outside these ranges:

Field Range
Exercise title 1 – 100 chars
Exercise description 0 – 2 000 chars
Workout title 1 – 100 chars
Workout description 0 – 5 000 chars
Workout item target_value 1 – 3 600
Workout item seconds_per_rep 1 – 60 (default 3)
Workout item series_count 1 – 99
Workout item rest_seconds 0 – 600
General tag name 1 – 30 chars, lowercase, max 10 per exercise/workout
Equipment tag name from fixed seed list (§5.4), max 15 per exercise
Muscle from fixed seed list (§5.3), no per-exercise cap but typically 1–4

4. Authoring an Exercise

4.1 Title

4.2 Description — required structure

The description is rich text (HTML, rendered with a markdown-style renderer). Maximum 2 000 chars. Use the following sections in this order. Sections marked required must always be present; sections marked optional are added when relevant.

4.2.1 Setup (required)

One short paragraph describing the starting position. Body alignment, grip, foot placement, equipment placement. 2–4 sentences.

4.2.2 Execution (required)

A numbered list of the movement phases. 3–6 steps. Use imperative voice ("Lower your hips…"). Each step is one sentence.

4.2.3 Breathing (optional but recommended)

One sentence: when to inhale, when to exhale.

4.2.4 Common mistakes (required)

A bulleted list of 2–4 frequent errors and how to fix them. Format: **Mistake** — fix.

4.2.5 Variations (optional)

A bulleted list of 1–3 easier or harder variants. Do not describe alternative exercises that should be their own entry; only progressions/regressions of the same movement pattern.

4.2.6 Safety (optional)

One short paragraph or bulleted list. Include only when there is a real risk (load-bearing, joints, balance). Skip for low-risk exercises.

4.3 Description — what NOT to include

4.4 Media

4.5 Muscles

4.6 Equipment (+ tags)

4.7 General tags (# tags)


5. Reference data

5.1 Step kinds (player)

get_ready, exercise, series_rest, break, paused_rest. Authors do not pick step kinds directly — the player derives them from items.

5.2 Item shape (the data AI emits)

// type "exercise"
{
  type: "exercise",
  exercise_id: "<uuid of the Exercise row>",
  target_type: "time" | "reps",
  target_value: number,             // seconds OR reps, 1..3600
  seconds_per_rep: number | null,   // required if target_type == "reps", default 3
  series_count: number,             // 1..99
  rest_seconds: number,             // 0..600, between series
  order_index: number,
}

// type "break"
{
  type: "break",
  target_type: "time" | "pause",
  target_value: number,             // seconds, ignored when target_type == "pause"
  series_count: 1,
  rest_seconds: 0,
  order_index: number,
}

5.3 Muscles (fixed seed list, 19 entries)

Names are lowercase identifiers and must be used exactly as written, in English, even when the rest of the workout is authored in another language (see §10.5).

Group Muscles
Chest chest
Back lats, traps, rhomboids, erector spinae
Shoulders front delts, side delts, rear delts
Arms biceps, triceps, forearms
Core abs, obliques
Legs quads, hamstrings, glutes, calves, adductors, abductors

5.4 Equipment (fixed seed list, ~30 entries)

Group Equipment
Free Weights barbell, dumbbells, kettlebell, weight plates, ez bar
Machines cable machine, smith machine, leg press, lat pulldown, pec deck
Cardio treadmill, exercise bike, rowing machine, elliptical, jump rope
Bars & Racks pull-up bar, dip station, bench, squat rack, rings, trx
Accessories resistance bands, yoga mat, foam roller, medicine ball, ab wheel, stability ball, sliders, weighted vest, box

6. Authoring a Workout

6.1 Title

6.2 Description

6.3 Item ordering — recommended structure

A well-constructed workout follows this template (skip sections that don't apply):

  1. Warm-up (3–8 min): dynamic, low-load. Either a single timed exercise (e.g. jumping jacks 60 s) or 2–4 short exercises with no series rest.
  2. Main block(s) (15–40 min): strength or conditioning sets. Group by movement pattern or muscle. Place a timed break (30–90 s) between blocks, never between every single item.
  3. Finisher (optional, 2–5 min): higher-intensity capstone (AMRAP-style or burnout).
  4. Cool-down (2–5 min): stretching/mobility, single timed exercises, no series, low rest.

6.4 Series, target, rest — rules of thumb

Goal Target type Target value Series Rest
Strength (compound) reps 4–8 reps 3–5 90–180 s
Hypertrophy reps 8–12 reps 3–4 60–90 s
Conditioning / HIIT time 20–40 s 3–5 10–30 s
Endurance time 60–120 s 1–3 30–60 s
Mobility / stretch time 30–60 s 1 0
Core hold time 20–60 s 2–4 20–45 s

seconds_per_rep defaults to 3. Use 2 for fast/explosive (kettlebell swing, jumping squat) and 4–5 for slow tempo (tempo squat, slow eccentric pull-up).

6.5 When to use which break type

6.6 Computed vs. extra metadata

These are computed automatically from items and are read-only on the workout:

The workout itself also has its own editable bag of:

The user sees computed ∪ extra for both equipment and muscles; the AI should populate only the extra bag, never duplicating equipment that is already on an exercise.

6.7 Cover image

6.8 Visibility


7. Hitting a target time (algorithm)

When the user requests a workout of duration T_target:

  1. Pick a structure template (warm-up + N main blocks + optional finisher + cool-down).
  2. Allocate budget: e.g. warm-up 10 % of T, cool-down 10 %, transitions/breaks 5 %, main blocks the remainder.
  3. For each main block, choose 2–4 exercises. Default to series_count = 3, rest_seconds = 30–60 s for conditioning, 60–120 s for strength.
  4. Compute the running total using the formula in §3.3–§3.4.
  5. If under budget by > 5 %: increase series, lengthen target, or add an exercise.
  6. If over budget by > 5 %: reduce series, shorten target, or drop an exercise. Do not trim warm-up or cool-down below the minimums in §6.3 unless T_target < 8 min.
  7. Reject any plan that uses pause breaks to absorb time: pauses don't count and the user will end up over time.

Aim for |total − T_target| ≤ 5 % (e.g. ±90 s for a 30-minute workout).


8. Anti-patterns (do not do this)


9. Examples

These are full, copy-correct examples. Use them as templates.

9.1 Example A — Exercise (reps-based, equipped, single muscle group)

Title: Goblet Squat

Description:

Setup Stand with feet shoulder-width apart, toes turned out 10–15°. Hold a single dumbbell or kettlebell vertically against your chest with both hands cupping the top bell.

Execution

  1. Brace your core and pull your shoulder blades down and back.
  2. Push your hips back and bend your knees, keeping your chest tall.
  3. Descend until your hip crease is below your knee, or as far as you can without losing the neutral spine.
  4. Drive through your mid-foot to stand back up, finishing with hips fully extended.

Breathing Inhale on the way down, exhale as you stand up.

Common mistakes

Variations

Muscles: quads, glutes, adductors, abs Equipment (+): dumbbells, kettlebell (either is acceptable — list both) Tags (#): #squat, #bilateral, #strength, #beginner-friendly equipment_free: false Media: GIF, square, full-body side angle.

Workout-side parameters when used in a workout: typically target_type: "reps", target_value: 8–12, seconds_per_rep: 3 (or 5 for tempo variant), series_count: 3–4, rest_seconds: 60–90.


9.2 Example B — Exercise (time-based, no equipment, isometric)

Title: Side Plank

Description:

Setup Lie on your right side with your right forearm on the floor, elbow directly under your shoulder. Stack your feet, knees, hips, and shoulders in one line. Top hand on your hip or extended toward the ceiling.

Execution

  1. Press your forearm into the floor and lift your hips so that your body forms a straight line from ankles to head.
  2. Squeeze your obliques and glutes; keep your bottom hip from sagging.
  3. Hold the position; breathe steadily.
  4. To finish, lower the hip under control. Repeat on the opposite side.

Breathing Steady, shallow breaths through the nose. Do not hold your breath.

Common mistakes

Variations

Safety Skip if you have an unresolved shoulder injury on the supporting side.

Muscles: obliques, abs, side delts Equipment (+): (none) Tags (#): #core, #isometric, #unilateral, #bodyweight equipment_free: true Media: image, side-on, full-body.

Workout-side parameters: target_type: "time", target_value: 30–60, series_count: 2–3 per side, rest_seconds: 20–30. Place once per side as two separate items, or one item and rely on the user to switch sides at the next series — prefer two items for clarity.


9.3 Example C — Workout (30 min, full-body, dumbbells)

Title: Full-Body Strength · Dumbbells · 30 min Visibility: public Description:

A 30-minute full-body strength session for intermediate trainees with a single pair of dumbbells. Three compound supersets bookended by a dynamic warm-up and a stretching cool-down. Expect roughly equal work on push, pull, and lower-body patterns.

Structure: 4 min warm-up · 3 strength supersets (~6 min each) · 60 s break · 4 min cool-down.

Workout extra equipment: (none — all equipment is on exercises) Workout tags (#): #strength, #full-body, #dumbbells, #intermediate, #home

Items:

# Type Exercise / Break target_type target_value sec/rep Series Rest
1 exercise Jumping Jacks time 60 1 0
2 exercise Bodyweight Squat reps 12 3 1 0
3 exercise Arm Circles time 30 1 0
4 break (timed) time 30
5 exercise Goblet Squat reps 10 3 3 75
6 exercise Dumbbell Bent-Over Row reps 10 3 3 75
7 break (timed) time 60
8 exercise Dumbbell Romanian Deadlift reps 10 3 3 75
9 exercise Dumbbell Bench Press reps 8 3 3 90
10 break (timed) time 60
11 exercise Dumbbell Push Press reps 8 3 3 75
12 exercise Plank time 45 3 20
13 break (timed) time 30
14 exercise Cool-down Stretch (timed) time 240 1 0

Total time check (Get Ready 5 s):

Subtotal = 114 + 30 + 480 + 60 + 492 + 60 + 397 + 30 + 240 = 1903 s Plus Get Ready 5 ⇒ 1908 s ≈ 31:48. Within 6 % of 30 min target — acceptable. To tighten, drop one set from Superset 3 (saves ~95 s).


10. Output contract for external AI assistants

This section is the contract for AI assistants (Claude, ChatGPT, Gemini, …) that receive a Reppie workout request through the user's Create with AI flow. The user pastes a short prompt into your chat, you reply in the format below, the user copies your reply back into Reppie, and Reppie's parser materializes the workout.

The contract is deliberately simpler than the internal DB schema (§5.2). The parser handles ID resolution, exercise lookup, and break creation.

10.1 Reply layout

Your full reply must consist of, in this exact order:

  1. A single fenced ```json code block containing the workout object (see §10.2).
  2. One blank line.
  3. A time-audit line: ⏱ Total: <hh:mm> (target <hh:mm>, ±<n>%) — the running total computed per §3 / §10.8.
  4. One blank line.
  5. One reminder line, starting with the 👉 emoji, in the same language as the user's request, telling the user to copy your full message and return to Reppie.
    • English: 👉 Now copy the message above and return to Reppie.
    • Czech: 👉 Nyní zkopíruj zprávu výše a vrať se zpět do Reppie.

Do not add a preamble, table of contents, or commentary outside the code block. The user just wants the workout — keep your reply tight.

10.2 JSON shape

{
  "workout": {
    "title":       "Workout name in the user's language (1–100 chars)",
    "description": "60–150 words of plain prose, in the user's language (see §10.6)",
    "tags":        ["3–8 lowercase tags, no #/+ prefix, max 30 chars each"]
  },
  "exercises": [
    {
      "title":           "Exercise name in user's language (1–100 chars)",
      "description":     "Optional short note (form cue, modification) — ≤ 2000 chars",
      "equipment_free":  true,
      "equipment":       ["names from §5.4 — only when equipment_free is false"],
      "muscles":         ["names from §5.3 — always English, lowercase"],
      "tags":            ["lowercase tags, max 10, max 30 chars each"],
      "sets":            3,
      "reps":            12,
      "seconds":         45,
      "seconds_per_rep": 2.1,
      "rest_seconds":    60
    },
    { "title": "Rest", "seconds": 90 }
  ]
}

Field semantics for an exercise entry:

A regular exercise must have title, sets, rest_seconds, plus EITHER reps + seconds_per_rep OR seconds. A Rest entry has only the two fields shown — no others (see §10.4).

10.3 Reps vs time

PREFER TIME (use seconds) for anything naturally measured by duration: plank, wall sit, dead hang, farmer's carry, mountain climbers, jump rope, running, cycling. If there's no clean "counting moment," use time.

USE REPS (use reps + seconds_per_rep) only for movements with discrete countable repetitions: push-up, squat, bicep curl, pull-up, lunge, row.

seconds_per_rep is the precise total duration of one full rep cycle (one decimal place), counting BOTH directions:

Movement Down Up seconds_per_rep
Push-up 1.1 1.0 2.1
Squat 1.5 1.5 3.0
Bicep curl 1.0 1.1 2.1
Pull-up 1.5 1.5 3.0

Be realistic. Don't round to an integer just because it's neat.

10.4 Rest periods (CRITICAL — most common mistake)

There are two different ways to express rest. Use the right one.

(A) rest_seconds on an exercise — automatic rest between consecutive sets of the same exercise. NOT a pause between different exercises. If sets: 3 and rest_seconds: 60, the user does the exercise, rests 60 s, repeats, rests 60 s, repeats.

(B) Rest entry — a standalone pause between different exercises. Special item:

{ "title": "Rest", "seconds": 90 }

🚫 A Rest entry has exactly two fields and nothing else. No sets, reps, muscles, equipment, tags, description. If you add those, Reppie tries to create a real exercise called "Rest" / "Pauza" / "Odpočinek" / "Descanso" / etc. and the import gets confused.

🌐 Language exception for Rest entries: the title must always be the literal English word "Rest", even when the rest of the workout is in another language. Reppie uses this exact string as a marker.

10.5 Language rules (REQUIRED)

Generate all content in the same language as the user's request. This applies to:

Always literal English, never translated:

  1. Each item in the muscles array — fixed DB identifiers from §5.3.
  2. Each item in the equipment array — fixed DB identifiers from §5.4.
  3. The title field of a Rest entry — always literally "Rest" (see §10.4).

The reminder line at the end of your reply (the one starting with 👉) is also in the user's language — see §10.1.

10.6 Workout description (REQUIRED)

The workout.description field is what the user reads on the workout's detail page. Always provide it. Make it useful — not generic boilerplate.

Aim for 3–6 sentences (~60–150 words) covering, where relevant:

Plain prose, friendly second person ("you"), no markdown, no bullet points, no emojis, no exercise-by-exercise breakdown (the exercise list speaks for itself). Don't open with "This workout…" — vary the opening. Don't repeat the title verbatim.

10.7 Workout tags (REQUIRED)

The workout.tags array is 3–8 short, descriptive labels — think hashtags. Pick what genuinely fits this specific workout:

Rules: lowercase, no leading # or +, max 30 chars each, max 10 tags total. Avoid synonyms of one another.

10.8 Total time — mandatory self-audit

Most common failure mode: AI output is 20–40 % shorter than requested. You MUST compute and verify.

For each exercise entry:

one_set_seconds = (reps used) ? reps * seconds_per_rep : seconds
item_time       = sets * one_set_seconds + (sets - 1) * rest_seconds

For each Rest entry: item_time = seconds.

total_seconds = 5 (built-in Get Ready) + Σ item_time

Self-audit:

  1. Extract the user's requested duration (e.g. 30 min, 1 hour, 20 minut, hodina, 45 минут, media hora).
  2. Build the plan, then compute total_seconds.
  3. If |total − requested| > 5 %, REVISE — add/remove sets, lengthen/shorten targets, add/drop exercises — until you are within ±5 %.
  4. Do not under-deliver. A 60-min request answered with a 39-min plan is a failure — keep iterating.
  5. Print the audit line described in §10.1.

Common mistakes: forgetting to multiply reps × seconds_per_rep; forgetting (sets − 1) × rest_seconds; forgetting that standalone Rest entries also count.

10.9 Reuse over creation

The Reppie parser will fuzzy-match exercise titles (case-insensitive, accent-stripped, singularized) against the user's existing library before creating new entries. So:

10.10 Worked example (complete reply)

The following is exactly what your reply should look like — JSON code block, blank line, audit line, blank line, reminder line. Nothing else.

```json
{
  "workout": {
    "title": "Full Body Strength",
    "description": "A balanced full-body session that hits the main movement patterns — push, brace, hinge — in three short blocks. Built for intermediate trainees who want measurable strength gains without going to a gym; use it 2–3× per week with at least one rest day between sessions. Expect to feel worked but not destroyed: the rep ranges target hypertrophy and tendon resilience while the rests keep your heart rate up enough to count as a light conditioning stimulus. Warm up for five minutes with mobility before starting and cool down with light stretching afterwards.",
    "tags": ["full body", "strength", "hypertrophy", "intermediate", "16 min"]
  },
  "exercises": [
    {
      "title": "Push-up",
      "description": "Standard push-up, keep core tight and elbows tucked at ~45°.",
      "equipment_free": true,
      "muscles": ["chest", "triceps"],
      "tags": ["bodyweight", "push"],
      "sets": 3,
      "reps": 12,
      "seconds_per_rep": 2.1,
      "rest_seconds": 60
    },
    { "title": "Rest", "seconds": 90 },
    {
      "title": "Plank",
      "equipment_free": true,
      "muscles": ["abs"],
      "tags": ["isometric"],
      "sets": 3,
      "seconds": 45,
      "rest_seconds": 45
    },
    {
      "title": "Barbell Squat",
      "equipment_free": false,
      "equipment": ["barbell", "squat rack"],
      "muscles": ["quads", "glutes"],
      "tags": ["strength"],
      "sets": 4,
      "reps": 8,
      "seconds_per_rep": 3.0,
      "rest_seconds": 120
    }
  ]
}
```

⏱ Total: 16:12 (target 16:00, +1%)

👉 Now copy the message above and return to Reppie.

Math for the audit:


11. Changelog

Version Date Notes
1.1 2026-05-07 Added §0 (AI quickstart) and §10 (output contract for external AI assistants). Reconciled §5.3 with the consolidated chest muscle.
1.0 2026-05-06 Initial guide.