# Intrvl > Intrvl is a precision workout tracking app for iOS. It supports three interoperable JSON schemas: Program Collection (v1.6) for workout programs, Exercise Schema (v1.5) for standalone exercise import/export, and History Export (v1.1) for training data sharing. This file helps LLMs generate valid, importable files across all three formats. ## About Intrvl Intrvl is a precision interval timer and training analytics platform for iOS, built by Scott Owen and launched in 2025. It is designed for intermediate to advanced lifters who follow structured training programs and understand rest periods as a training variable — not an afterthought. Unlike general-purpose fitness apps, Intrvl unifies rest timing and weight tracking in a single interface, eliminating the need to switch between apps mid-workout. All analytics calculations — including Effective Volume, Strain Score, Muscle Heatmap, and Training Density — are processed entirely on-device, with no data sent to external servers. Optional iCloud sync is managed by Apple and never passes through Intrvl's infrastructure. Key differentiators: - **One-time purchase** ($24.99 USD, 14-day free trial) — no subscriptions, no ads, all features included - **On-device analytics**: Effective Volume excludes warm-up sets; Strain Score weights exercises by muscle group size and flags failure sets at 1.5× cost - **Coach integration**: Athletes export training history as structured JSON and share with coaches or AI tools; coaches import programs via file-sharing without requiring accounts or servers - **Background-safe timing engine**: Countdown timers remain accurate when the app is backgrounded, using system-level APIs - **Offline-first**: Full functionality with no internet connection Intrvl supports iOS 17+ and is available on the App Store at https://apps.apple.com/us/app/intrvl/id6748898722. Contact: info@intrvl.app. Intrvl combines interval timing with weight tracking and on-device analytics. Built for intermediate to advanced lifters who follow structured programs and recognise rest periods as a training variable. --- ## 1. Program Collection Schema v1.6 Programs define structured workouts with exercises and prescribed sets for import into Intrvl. ### Root Object | Field | Type | Required | Description | |-------|------|----------|-------------| | `version` | Number | **Yes** | Must be `1.6` (number, not string) | | `collectionName` | String | **Yes** | Program name | | `author` | String | No | Creator name | | `description` | String | No | Program description | | `tags` | Array | No | e.g., `["strength", "hypertrophy"]` | | `workouts` | Array | **Yes** | List of workout objects | ### Workout Object | Field | Type | Required | Description | |-------|------|----------|-------------| | `id` | String | No | Unique ID (auto-generated if omitted) | | `workoutName` | String | **Yes** | e.g., "Push Day A" | | `description` | String | No | Workout notes | | `restDefault` | Integer | No | Rest between sets in seconds (default: 120) | | `exercises` | Array | No | List of exercises | ### Exercise Object (shared with Exercise Schema) | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | String | **Yes** | Exercise name | | `capabilities` | Array | No | Metrics tracked (default: `["weight", "reps"]`) | | `muscleGroups` | Object | No | Primary/secondary muscle targeting | | `equipment` | Array | No | Required equipment | | `doublesVolume` | Boolean | No | `true` for bilateral exercises (e.g., dumbbell curls) | | `description` | String | No | Coaching notes | | `sets` | Array | No | Prescribed sets | ### Set Object (Program) | Field | Type | Required | Description | |-------|------|----------|-------------| | `reps` | Integer | No | Target repetitions | | `suggestedWeight` | Number | No | Weight in kg | | `duration` | Integer | No | Time value | | `durationUnit` | String | No | `"seconds"` (default) or `"minutes"` | | `distance` | Number | No | Distance value | | `distanceUnit` | String | No | `"m"` (default) or `"yards"` | | `resistance` | String | No | `"bodyweight"`, `"light"`, `"medium"`, `"heavy"` | | `isWarmUp` | Boolean | No | Warm-up set — excluded from effective volume | | `toFailure` | Boolean | No | Failure set — receives 1.5x volume multiplier | --- ## 2. Exercise Schema v1.5 Standalone exercise import and export. Four formats: single import, batch import, library export, and conflict resolution. ### Single Exercise Import (ExerciseJSON) | Field | Type | Required | Description | |-------|------|----------|-------------| | `version` | Number | **Yes** | Must be `1.3` or `1.5` | | `name` | String | **Yes** | Exercise name (cannot be empty) | | `capabilities` | Array | No | Metrics tracked. Overrides `exerciseType` | | `muscleGroup` | String | No | Primary muscle group category | | `exerciseType` | String | No | Legacy: `"weighted"`, `"timed"`, `"bodyweight"`, `"banded"`, `"distance"` | | `equipment` | Array | No | Required equipment | | `defaultResistance` | String | No | Band resistance level | | `description` | String | No | Exercise description | | `doublesVolume` | Boolean | No | `true` for bilateral exercises | | `defaultSets` | Array | No | Prescribed default sets | | `source` | Object | No | `{ author, url, importedAt }` | ### Batch Import (ExerciseBatchJSON) | Field | Type | Required | Description | |-------|------|----------|-------------| | `version` | Number | **Yes** | Must be `1.3` or `1.5` | | `libraryName` | String | No | Library name | | `author` | String | No | Creator name | | `exercises` | Array | **Yes** | Array of exercise objects (min 1) | Batch exercises support hierarchical `muscleGroups` object: ```json { "primary": { "Legs": ["Quads", "Glutes"] }, "secondary": { "Core": ["Abs"] } } ``` ### Conflict Resolution When importing exercises that match existing names: `keepCurrent` (default), `useImport`, or `merge` (union arrays, fill nil fields). ### Import URLs - Single: `intrvl://import-exercise?url=` - Batch: `intrvl://import?url=` --- ## 3. History Export v1.1 Training history exported from the app. Used for coach review, AI analysis, and the Intrvl Analytics dashboard. **Versioning:** v1.1 (App 2.7.1+) adds optional `volumeAnalytics`. v1.0 consumers that ignore unknown fields can safely parse v1.1 exports. Session and set structures are unchanged. ### Root Object | Field | Type | Required | Description | |-------|------|----------|-------------| | `version` | String | **Yes** | `"1.1"` or `"1.0"` (string, not number) | | `exportDate` | String | **Yes** | ISO 8601 UTC timestamp | | `appVersion` | String | **Yes** | e.g., `"2.7.1"` | | `dateRange.from` | String | **Yes** | `YYYY-MM-DD` start date | | `dateRange.to` | String | **Yes** | `YYYY-MM-DD` end date (inclusive) | | `unitPreference` | String | **Yes** | `"kg"` or `"lb"` | | `volumeAnalytics` | Object | No | **v1.1+** Coach-facing volume analytics. `null` or absent in v1.0 exports. | | `sessions` | Array | **Yes** | Session objects (may be empty) | ### volumeAnalytics Object (v1.1) Anchored to `dateRange.to`. Uses effective volume (kg) as the metric basis. | Field | Type | Description | |-------|------|-------------| | `metric` | String | Always `"effectiveVolumeKg"` | | `anchorDate` | String | `YYYY-MM-DD` — same as `dateRange.to` | | `windows` | Array | Trailing period comparisons for 7, 14, 30, 60, 90 days | | `trends` | Array | Daily effective volume and rolling averages per window | | `records` | Object | `lifetime` and `exportRange` record objects | **Window object fields:** `windowDays` (7/14/30/60/90), `current` (kg), `previous` (kg), `deltaPercent` (null if not comparable), `status` (`comparable` \| `noCurrentData` \| `insufficientHistory` \| `noPreviousData`). **Rolling window days by period:** 7D→3, 14D→5, 30D→7, 60D→10, 90D→14. **Record scopes:** `lifetime` (all sessions to anchorDate) and `exportRange` (sessions within dateRange). Each scope has: `highestWeeklyVolume`, `highestDailyVolume`, `mostSetsInDay` — each with `value` and `date` (YYYY-MM-DD). ### Session Object | Field | Type | Required | Description | |-------|------|----------|-------------| | `id` | String | **Yes** | UUID | | `date` | String | **Yes** | ISO 8601 UTC | | `startTime` | String | No | First set timestamp. `null` if no sets | | `endTime` | String | No | Last set timestamp. `null` if no sets | | `durationMinutes` | Number | No | Session duration. `null` if < 2 sets | | `notes` | String | No | User session notes | | `isComplete` | Boolean | **Yes** | `true` if >= 1 set logged | | `analytics` | Object | No | Pre-computed analytics. `null` if no sets | | `exercises` | Array | **Yes** | Exercise instances ordered by first set | | `timerLogs` | Array | No | Timer records. `null` if none | ### Analytics Object | Field | Type | Description | |-------|------|-------------| | `strainScore` | Number | 0-100+ scale | | `totalVolume` | Number | Effective volume in kg (warmups excluded, failure 1.5x) | | `hardSetCount` | Number | Non-warmup working sets | | `failureSetCount` | Number | Sets to failure | | `trainingLevel` | String | `"beginner"`, `"intermediate"`, `"advanced"` | | `strainZone` | String | `"recovery"`, `"productive"`, `"excessive"` | ### Exercise Instance (History) | Field | Type | Required | Description | |-------|------|----------|-------------| | `name` | String | **Yes** | Exercise name | | `category` | String | No | Primary muscle category | | `capabilities` | Array | **Yes** | Metric types | | `muscleGroups` | Object | No | `{ primary: {...}, secondary: {...} }` | | `equipment` | Array | No | Equipment. `null` if bodyweight | | `doublesVolume` | Boolean | **Yes** | `true` for unilateral exercises | | `sets` | Array | **Yes** | Set objects chronologically | ### Set Object (History) | Field | Type | Required | Description | |-------|------|----------|-------------| | `setNumber` | Number | **Yes** | 1-indexed position | | `timestamp` | String | **Yes** | ISO 8601 UTC | | `weight` | Object | No | `{ kg: Number, lb: Number }`. `null` if bodyweight | | `reps` | Number | No | Rep count. `null` for timed | | `duration` | Number | No | Seconds. `null` for rep-based | | `distance` | Number | No | Metres. `null` if N/A | | `isWarmup` | Boolean | **Yes** | Excluded from volume | | `isFailure` | Boolean | **Yes** | 1.5x volume multiplier | **Key:** `weight.kg` is source of truth. `weight.lb` calculated at export. Optional fields are `null`, not missing. Max 90-day range per export. --- ## Shared: Capabilities Reference 10 valid capability combinations, shared across all three schemas: | Type | capabilities | Example Exercise | |------|-------------|------------------| | Weighted | `["weight", "reps"]` | Bench Press, Squat | | Bodyweight | `["reps", "bodyweightVolume"]` | Pull-ups, Push-ups | | Weighted Bodyweight | `["weight", "reps", "bodyweightVolume"]` | Weighted Dips | | Loaded Carry | `["weight", "distance"]` | Farmer's Walk | | Timed Loaded | `["weight", "duration"]` | Weighted Plank | | Timed | `["duration"]` | Plank, Dead Hang | | Distance Only | `["distance"]` | Sprint | | Cardio | `["distance", "duration"]` | 5K Run | | Shuttle Runs | `["reps", "distance"]` | Sprint Intervals | | Banded | `["band", "reps"]` | Band Face Pull | ## Shared: Muscle Groups Hierarchy **Parents:** Legs, Back, Chest, Shoulders, Arms, Core | Parent | Children | |--------|----------| | Legs | Glutes, Quads, Hamstrings, Calves, Adductors, Abductors | | Back | Lats, Traps, Rhomboids, Lower Back | | Chest | Upper Chest, Middle Chest, Lower Chest | | Shoulders | Front Delts, Side Delts, Rear Delts | | Arms | Biceps, Triceps, Forearms | | Core | Abs, Obliques | **Rule:** Each parent can only appear in `primary` OR `secondary`, not both. --- ## Complete Example 1: Program Collection (v1.6) A classic two-workout strength program with barbell compound movements. ```json { "version": 1.6, "collectionName": "Strength 5x5 Program", "author": "Intrvl", "description": "The classic 5x5 strength program. Alternate between Workout A and B, three times per week.", "tags": ["5x5", "full body", "strength", "beginner"], "workouts": [ { "workoutName": "Workout A", "description": "Squat, Bench Press, Barbell Row", "restDefault": 180, "exercises": [ { "name": "Squat", "capabilities": ["weight", "reps"], "muscleGroups": { "primary": { "Legs": ["Glutes", "Quads", "Hamstrings"] }, "secondary": { "Core": ["Abs"] } }, "equipment": ["Barbell", "Squat Rack"], "sets": [ { "reps": 10, "suggestedWeight": 20, "isWarmUp": true }, { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60, "toFailure": true } ] }, { "name": "Bench Press", "capabilities": ["weight", "reps"], "muscleGroups": { "primary": { "Chest": ["Middle Chest"] }, "secondary": { "Arms": ["Triceps"], "Shoulders": ["Front Delts"] } }, "equipment": ["Barbell", "Bench"], "sets": [ { "reps": 5, "suggestedWeight": 40 }, { "reps": 5, "suggestedWeight": 40 }, { "reps": 5, "suggestedWeight": 40 }, { "reps": 5, "suggestedWeight": 40 }, { "reps": 5, "suggestedWeight": 40 } ] } ] } ] } ``` ## Complete Example 2: Exercise Batch Import (v1.5) Importing a library of exercises with hierarchical muscle groups. ```json { "version": 1.5, "libraryName": "Compound Lifts", "author": "Strength Coach", "exercises": [ { "name": "Deadlift", "capabilities": ["weight", "reps"], "muscleGroups": { "primary": { "Legs": ["Glutes", "Hamstrings"], "Back": ["Lower Back", "Lats"] }, "secondary": { "Core": ["Abs"], "Arms": ["Forearms"] } }, "equipment": ["Barbell"], "defaultSets": [ { "reps": 5, "suggestedWeight": 100 } ] }, { "name": "Farmer's Walk", "capabilities": ["weight", "distance"], "muscleGroups": { "primary": { "Back": ["Traps"], "Core": ["Abs", "Obliques"] }, "secondary": { "Arms": ["Forearms"], "Legs": ["Calves"] } }, "equipment": ["Dumbbells"], "defaultSets": [ { "suggestedWeight": 30, "distance": 50, "distanceUnit": "m" } ] } ] } ``` ## Complete Example 3: Single Exercise Import (v1.5) ```json { "version": 1.5, "name": "Barbell Back Squat", "capabilities": ["weight", "reps"], "muscleGroup": "Legs", "equipment": ["Barbell", "Squat Rack"], "description": "Compound lower body movement. Keep chest up, break at hips and knees simultaneously.", "doublesVolume": false, "defaultSets": [ { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60 }, { "reps": 5, "suggestedWeight": 60 } ] } ``` ## Complete Example 4: History Export (v1.1) ```json { "version": "1.1", "exportDate": "2026-01-30T14:00:00.000Z", "appVersion": "2.7.1", "dateRange": { "from": "2026-01-28", "to": "2026-01-30" }, "unitPreference": "kg", "volumeAnalytics": { "metric": "effectiveVolumeKg", "anchorDate": "2026-01-30", "windows": [ { "windowDays": 7, "current": 9850, "previous": 8200, "deltaPercent": 20.1, "status": "comparable" }, { "windowDays": 14, "current": 18050, "previous": 16400, "deltaPercent": 10.1, "status": "comparable" } ], "trends": [ { "windowDays": 7, "rollingWindowDays": 3, "points": [ { "date": "2026-01-28", "effectiveVolume": 9850, "rollingAverage": 9850 } ] } ], "records": { "lifetime": { "highestWeeklyVolume": { "value": 33000, "date": "2026-01-21" }, "highestDailyVolume": { "value": 9850, "date": "2026-01-28" }, "mostSetsInDay": { "value": 14, "date": "2026-01-28" } }, "exportRange": { "highestWeeklyVolume": { "value": 9850, "date": "2026-01-30" }, "highestDailyVolume": { "value": 9850, "date": "2026-01-28" }, "mostSetsInDay": { "value": 14, "date": "2026-01-28" } } } }, "sessions": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "date": "2026-01-28T00:00:00.000Z", "startTime": "2026-01-28T09:05:00.000Z", "endTime": "2026-01-28T10:15:00.000Z", "durationMinutes": 70.0, "notes": "Push day - felt strong", "isComplete": true, "analytics": { "strainScore": 42.3, "totalVolume": 9850, "hardSetCount": 14, "failureSetCount": 2, "trainingLevel": "intermediate", "strainZone": "productive" }, "exercises": [ { "name": "Bench Press", "category": "Chest", "capabilities": ["weight", "reps"], "muscleGroups": { "primary": { "Chest": ["Middle Chest"] }, "secondary": { "Arms": ["Triceps"] } }, "equipment": ["Barbell", "Bench"], "doublesVolume": false, "sets": [ { "setNumber": 1, "timestamp": "2026-01-28T09:05:00.000Z", "weight": { "kg": 60, "lb": 132.28 }, "reps": 10, "duration": null, "distance": null, "notes": null, "isWarmup": true, "isFailure": false, "isPR": false, "restSeconds": null }, { "setNumber": 2, "timestamp": "2026-01-28T09:10:00.000Z", "weight": { "kg": 80, "lb": 176.37 }, "reps": 8, "duration": null, "distance": null, "notes": null, "isWarmup": false, "isFailure": false, "isPR": false, "restSeconds": null }, { "setNumber": 3, "timestamp": "2026-01-28T09:20:00.000Z", "weight": { "kg": 80, "lb": 176.37 }, "reps": 6, "duration": null, "distance": null, "notes": null, "isWarmup": false, "isFailure": true, "isPR": false, "restSeconds": null } ] } ], "timerLogs": [ { "timestamp": "2026-01-28T09:08:00.000Z", "duration": 120, "timerType": "rest" } ] } ] } ``` --- ## Quick Reference ### Minimal Valid Program (v1.6) ```json { "version": 1.6, "collectionName": "My Program", "workouts": [ { "workoutName": "Day 1", "exercises": [ { "name": "Squat", "sets": [{ "reps": 5, "suggestedWeight": 60 }] } ] } ] } ``` ### Minimal Valid Exercise (v1.5) ```json { "version": 1.5, "name": "Squat" } ``` ### Import URL Schemes - Programs: `intrvl://import?url=` - Single exercise: `intrvl://import-exercise?url=` ## Documentation - [Program Collection Spec](https://intrvl.app/integrate/): Full v1.6 specification - [Exercise Spec](https://intrvl.app/docs/exercise-spec/): Exercise import/export v1.5 - [History Export Spec](https://intrvl.app/docs/history-export/): Training data export v1.1 - [Analytics Dashboard](https://intrvl.app/analytics/): Import history exports for visual review - [Program Builder](https://intrvl.app/program-builder/): Interactive program creation tool - [Sample Programs](https://intrvl.app/programs/): Downloadable example programs ## Optional - [Training Analytics](https://intrvl.app/training-analytics/): How Intrvl calculates Effective Volume and Strain Score - [Research](https://intrvl.app/research/): Evidence-based training principles - [Blog](https://intrvl.app/blog/): Training tips and product updates