RFC-001: Exercise Data Model Specification
Status: Draft Version: 0.1.0 Date: 2025-09-02 Authors: VITNESS Team Category: Standards Track
Abstract
This specification defines a standardized data model for exercise information to enable interoperability and data portability across fitness applications and platforms. This RFC focuses on how to structure exercise data rather than dictating specific taxonomies, allowing platforms to maintain their own naming conventions while ensuring compatibility.
1. Introduction
1.1. Background
The fitness industry suffers from severe data fragmentation where each platform maintains incompatible exercise definitions, muscle group mappings, and categorization systems. This creates user lock-in, developer inefficiency, and ecosystem fragmentation.
1.2. Goals
This specification aims to:
- Define structural requirements for exercise data interchange
- Enable seamless data migration between fitness applications
- Support platform-specific taxonomies through extension mechanisms
- Establish versioning strategies for long-term ecosystem health
- Provide reference JSON Schema implementation
1.3. Scope
In Scope:
- Core exercise data structure and required fields
- Extension mechanisms for platform-specific data
- JSON Schema definitions and validation rules
- Versioning and migration strategies
- Reference examples and implementation guidance
Out of Scope:
- Specific exercise taxonomies or naming conventions
- Workout programming (future RFC-006)
- User progress tracking (future RFC-007)
- Authentication/authorization mechanisms
2. Terminology
- Exercise: A distinct movement or activity performed for fitness purposes
- Canonical Data: Standardized identifying information (name, slug, aliases)
- Classification: Structural categorization data (type, movement, mechanics, etc.)
- Extension: Platform-specific data that doesn't break interoperability
- Schema Version: Semantic version indicating data model compatibility
3. Core Structural Requirements
3.1. Required Fields
All compliant exercise data MUST include these fields:
{
"schemaVersion": "1.0.0",
"exerciseId": "550e8400-e29b-41d4-a716-446655440000",
"canonical": {
"name": "Back Squat",
"slug": "back-squat"
},
"classification": {
"exerciseType": "strength",
"movement": "squat",
"mechanics": "compound",
"force": "push",
"level": "intermediate"
},
"targets": {
"primary": [
{ "id": "mus.quadriceps", "name": "Quadriceps", "categoryId": "cat.legs" }
]
},
"metrics": {
"primary": { "type": "reps", "unit": "count" }
},
"metadata": {
"createdAt": "2025-09-02T15:00:00Z",
"updatedAt": "2025-09-02T15:00:00Z",
"status": "active"
}
}
3.2. Optional Standard Fields
Commonly supported optional fields that enhance interoperability:
{
"equipment": {
"required": [
{ "id": "eq.barbell", "name": "Barbell" },
{ "id": "eq.rack", "name": "Power Rack" }
],
"optional": [
{ "id": "eq.belt", "name": "Lifting Belt" }
]
},
"constraints": {
"contraindications": ["Acute knee injury without professional clearance"],
"prerequisites": ["Bodyweight squat competency"],
"progressions": ["High-bar back squat", "Paused back squat"],
"regressions": ["Goblet squat", "Box squat"]
},
"relations": [
{ "type": "alternate", "targetId": "urn:slug:front-squat" },
{ "type": "regression", "targetId": "urn:slug:goblet-squat" }
],
"media": [
{
"type": "video",
"uri": "https://cdn.example.com/exercises/back-squat.mp4",
"caption": "Side view, full-depth demo"
}
]
}
3.3. Extension Mechanisms
Two extension points for platform-specific data:
3.3.1. Attributes (Structured Extensions)
For common extensions that may become standardized:
{
"attributes": {
"x:vitness.barPathHint": "midfoot → midfoot",
"x:vitness.stanceWidth": "shoulder-width"
}
}
3.3.2. Extensions (Platform-Specific)
For complex platform-unique data structures:
{
"extensions": {
"x:vitness.tempo": { "eccentric": 3, "isometric": 1, "concentric": 1 },
"x:vitness.rangeOfMotion": { "standard": "hip-crease below knee" }
}
}
4. Reference Types and Structures
4.1. Canonical Information
{
"canonical": {
"name": "Back Squat",
"slug": "back-squat",
"aliases": ["Barbell Back Squat", "BB Back Squat"],
"localized": [
{ "lang": "sr", "name": "Сквот са шипком" },
{ "lang": "es", "name": "Sentadilla trasera", "aliases": ["Sentadilla con barra atrás"] }
]
}
}
4.2. Classification Structure
{
"classification": {
"exerciseType": "strength",
"movement": "squat",
"mechanics": "compound",
"force": "push",
"level": "intermediate",
"unilateral": false,
"kineticChain": "closed",
"tags": ["bilateral","hipDominant"]
}
}
4.3. Target Muscles
{
"targets": {
"primary": [
{ "id": "mus.quadriceps", "name": "Quadriceps", "categoryId": "cat.legs" }
],
"secondary": [
{ "id": "mus.hamstrings", "name": "Hamstrings", "categoryId": "cat.legs" },
{ "id": "mus.erectorSpinae", "name": "Erector Spinae", "categoryId": "cat.back" }
]
}
}
4.4. Equipment References
{
"equipment": {
"required": [
{ "id": "eq.barbell", "name": "Barbell" },
{ "id": "eq.rack", "name": "Power Rack" }
],
"optional": [
{ "id": "eq.belt", "name": "Lifting Belt" }
]
}
}
4.5. Metrics and Measurements
{
"metrics": {
"primary": { "type": "reps", "unit": "count" },
"secondary": [
{ "type": "weight", "unit": "lb" },
{ "type": "tempo", "unit": "count" },
{ "type": "rpe", "unit": "count" }
]
}
}
5. Versioning and Compatibility
5.1. Schema Versioning
Following semantic versioning:
- Major: Breaking changes to required fields
- Minor: New optional fields or enum values
- Patch: Documentation, validation updates
5.2. Compatibility Rules
- All data valid in version X.Y.Z must remain valid in X.Y+1.0
- New required fields must provide sensible defaults
- Deprecated fields remain functional for entire major version
- Migration paths must be documented for major version changes
5.3. Schema Evolution Example
Version 1.0.0 → 1.1.0 (Adding optional field):
{
"schemaVersion": "1.1.0",
"exerciseId": "550e8400-e29b-41d4-a716-446655440000",
"canonical": { "name": "Back Squat", "slug": "back-squat" },
"classification": {
"exerciseType": "strength",
"movement": "squat",
"mechanics": "compound",
"force": "push",
"level": "intermediate"
},
"newOptionalField": {
"feature": "value"
}
}
6. Implementation Guidance
6.1. Platform Integration
Platforms implementing this standard should:
- Maintain Internal Models: Keep existing taxonomies and domain models
- Export Compliance: Provide data in RFC-001 format for portability
- Import Translation: Map incoming RFC-001 data to internal structures
- Extension Usage: Use
extensionsnamespace for platform-specific data
6.2. Data Migration Workflow
graph LR
A[Platform A] --> B[RFC-001 Export]
B --> C[Validation]
C --> D[Platform B Import]
D --> E[Internal Mapping]
- Source platform exports exercises in RFC-001 format
- Data validation against JSON Schema
- Target platform imports and maps to internal model
- Custom extensions handled based on platform capabilities
6.3. Discovery Mechanism
TODO: Evaluate need for well-known discovery endpoint:
GET /.well-known/fitness-data-spec
Potential response structure:
{
"spec_version": "1.0.0",
"provider": "Platform Name",
"supported_extensions": ["namespace:field1", "namespace:field2"],
"export_endpoint": "/api/exercises/export/rfc001"
}
7. Security and Privacy Considerations
- This specification defines data format only
- Implementations must validate against JSON Schema
- User-generated content in extensions should be sanitized
- Follow standard security practices for data transmission
8. JSON Schema Reference
Complete JSON Schema available at:
- Exercise:
/specification/schemas/exercises/v1.0.0/exercise.schema.json - Equipment:
/specification/schemas/equipment/v1.0.0/equipment.schema.json - Muscle:
/specification/schemas/muscle/v1.0.0/muscle.schema.json
8.1. Validation
Validate with Ajv (Draft 2020-12):
npx ajv -s specification/schemas/exercises/v1.0.0/exercise.schema.json \
-d specification/schemas/exercises/v1.0.0/exercise.example.json
# Additional examples (optional):
npx ajv -s specification/schemas/exercises/v1.0.0/exercise.schema.json \
-d specification/schemas/exercises/v1.0.0/exercise.example.cardio.json
npx ajv -s specification/schemas/exercises/v1.0.0/exercise.schema.json \
-d specification/schemas/exercises/v1.0.0/exercise.example.mobility.json
npx ajv -s specification/schemas/exercises/v1.0.0/exercise.schema.json \
-d specification/schemas/exercises/v1.0.0/exercise.example.machine.json
npx ajv -s specification/schemas/exercises/v1.0.0/exercise.schema.json \
-d specification/schemas/exercises/v1.0.0/exercise.example.unilateral.json
9. Example Implementation
9.1. Complete Back Squat Export
Based on reference implementation (/specification/schemas/exercises/v1.0.0/exercise.example.json):
{
"schemaVersion": "1.0.0",
"exerciseId": "550e8400-e29b-41d4-a716-446655440000",
"canonical": {
"name": "Back Squat",
"slug": "back-squat",
"aliases": ["Barbell Back Squat", "BB Back Squat"],
"localized": [
{ "lang": "sr", "name": "Сквот са шипком" },
{ "lang": "es", "name": "Sentadilla trasera", "aliases": ["Sentadilla con barra atrás"] }
]
},
"classification": {
"exerciseType": "strength",
"movement": "squat",
"mechanics": "compound",
"force": "push",
"level": "intermediate",
"unilateral": false,
"kineticChain": "closed",
"tags": ["bilateral","hipDominant"]
},
"targets": {
"primary": [
{ "id": "mus.quadriceps", "name": "Quadriceps", "categoryId": "cat.legs" }
],
"secondary": [
{ "id": "mus.hamstrings", "name": "Hamstrings", "categoryId": "cat.legs" },
{ "id": "mus.erectorSpinae", "name": "Erector Spinae", "categoryId": "cat.back" }
]
},
"equipment": {
"required": [
{ "id": "eq.barbell", "name": "Barbell" },
{ "id": "eq.rack", "name": "Power Rack" }
],
"optional": [
{ "id": "eq.belt", "name": "Lifting Belt" }
]
},
"constraints": {
"contraindications": ["Acute knee injury without professional clearance"],
"prerequisites": ["Bodyweight squat competency"],
"progressions": ["High-bar back squat", "Paused back squat"],
"regressions": ["Goblet squat", "Box squat"]
},
"relations": [
{ "type": "alternate", "targetId": "urn:slug:front-squat" },
{ "type": "regression", "targetId": "urn:slug:goblet-squat" }
],
"metrics": {
"primary": { "type": "reps", "unit": "count" },
"secondary": [
{ "type": "weight", "unit": "lb" },
{ "type": "tempo", "unit": "count" },
{ "type": "rpe", "unit": "count" }
]
},
"media": [
{
"type": "video",
"uri": "https://cdn.example.com/exercises/back-squat.mp4",
"caption": "Side view, full-depth demo",
"license": "CC BY 4.0",
"attribution": "Vitness"
}
],
"attributes": {
"x:vitness.barPathHint": "midfoot → midfoot",
"x:vitness.stanceWidth": "shoulder-width"
},
"extensions": {
"x:vitness.tempo": { "eccentric": 3, "isometric": 1, "concentric": 1 },
"x:vitness.rangeOfMotion": { "standard": "hip-crease below knee" }
},
"metadata": {
"createdAt": "2025-09-02T15:00:00Z",
"updatedAt": "2025-09-02T15:00:00Z",
"status": "active",
"source": "vitness.core",
"version": "1.0.0"
}
}
9.2. Platform Import Mapping (TypeScript Example)
Generic TypeScript example showing how a platform might import RFC-001 data:
interface RFC001Exercise {
schemaVersion: string;
exerciseId: string;
canonical: {
name: string;
slug: string;
aliases?: string[];
localized?: Array<{
lang: string;
name: string;
aliases?: string[];
}>;
};
classification: {
exerciseType: string;
movement: string;
mechanics: string;
force: string;
level: string;
unilateral?: boolean;
kineticChain?: string;
tags?: string[];
};
// ... other fields
attributes?: Record<string, any>;
extensions?: Record<string, any>;
}
// Platform-specific import mapping
function importExercise(rfc001Data: RFC001Exercise) {
// Map required fields to internal structure
const exercise = {
id: rfc001Data.exerciseId,
name: rfc001Data.canonical.name,
slug: rfc001Data.canonical.slug,
type: rfc001Data.classification.exerciseType,
movement: rfc001Data.classification.movement,
mechanics: rfc001Data.classification.mechanics,
primaryMuscles: rfc001Data.targets?.primary?.map(m => ({
id: m.id,
name: m.name
})) || []
};
// Handle platform-specific extensions
if (rfc001Data.extensions?.['x:vitness.tempo']) {
exercise.tempo = rfc001Data.extensions['x:vitness.tempo'];
}
// Handle common attributes
if (rfc001Data.attributes?.['x:vitness.stanceWidth']) {
exercise.stanceWidth = rfc001Data.attributes['x:vitness.stanceWidth'];
}
return exercise;
}
// Example usage with Back Squat data
const backSquatRFC001 = { /* RFC-001 data from example above */ };
const internalExercise = importExercise(backSquatRFC001);
10. References
Conformance
Conforming Producers:
- MUST emit JSON that validates against the Exercise schema for the declared
schemaVersion. - MUST use UUIDv4 for all identifiers in production data (e.g.,
exerciseIdand any referenced IDs). Example short IDs shown in this RFC are illustrative only. - MUST populate all required fields and respect enumerations and structure.
- SHOULD include RFC 3339 UTC timestamps in
metadataand maintain accurate lifecycle fields.
Conforming Consumers:
- MUST validate incoming exercise data against the appropriate schema version.
- MUST ignore unknown keys in
attributesandextensions.
- SHOULD tolerate additional optional fields introduced in newer minor versions.
- SHOULD reject data with missing required fields or invalid enumerations.
Compatibility:
- Optional fields added in minor versions MUST NOT break consumers; consumers SHOULD ignore unknown optional fields.
- New required fields are a MAJOR change and require coordinated upgrades.
Additional resources:
- Identifier and UUID policy:
/specification/README.md#identifiers-ids - i18n and slug conventions:
/specification/i18n-and-slugs.md - Metrics pairing guidance:
/specification/metrics-guide.md - Extension policy and registry guide:
/specification/extension-registry.md - Discovery endpoint:
/specification/discovery.md
10.1. Normative References
Copyright Notice
Copyright (c) 2025 VITNESS.
This document is subject to the rights, licenses and restrictions contained in the VITNESS Open Standards License Agreement. See /specification/VITNESS Open Standards License Agreement.md.