# NIP-4e: Workout Events

**Last Updated:** 2025-03-26  
**Status:** Draft  
**Related To:** Nostr Integration, Workout Data Structure, Social Sharing

## Purpose

This document defines the technical specification for storing and sharing workout data through the Nostr protocol. It details the event kinds, data structures, and implementation guidelines for exercise templates, workout templates, and workout records. This specification serves as the foundation for POWR's Nostr integration and ensures consistent, interoperable workout data across the Nostr ecosystem.

`draft` `optional`

This specification defines workout events for fitness tracking. These workout events support both planning (templates) and recording (completed activities).

## Event Kinds

### Event Kind Selection Rationale

The event kinds in this NIP follow Nostr protocol conventions:

- **Exercise and Workout Templates** (33401, 33402) use parameterized replaceable event kinds (30000+) because:
  - They represent content that may be updated or improved over time
  - The author may want to replace previous versions with improved ones
  - They need the `d` parameter to distinguish between different templates by the same author
  - Multiple versions shouldn't accumulate in clients' storage

- **Workout Records** (1301) use a standard event kind (0-9999) because:
  - They represent a chronological feed of activity that shouldn't replace previous records
  - Each workout is a unique occurrence that adds to a user's history
  - Users publish multiple records over time, creating a timeline
  - They're conceptually similar to notes (kind 1) but with structured fitness data

### Exercise Template (kind: 33401)
Defines reusable exercise definitions. These should remain public to enable discovery and sharing. The `content` field contains detailed form instructions and notes.

#### Format

The format uses an _addressable event_ of `kind:33401`.

The `.content` of these events SHOULD be detailed instructions for proper exercise form. It is required but can be an empty string.

The list of tags are as follows:

* `d` (required) - universally unique identifier (UUID). Generated by the client creating the exercise template.
* `title` (required) - Exercise name
* `format` (required) - Defines data structure for exercise tracking (possible parameters: `weight`, `reps`, `rpe`, `set_type`)
* `format_units` (required) - Defines units for each parameter (possible formats: "kg", "count", "0-10", "warmup|normal|drop|failure")
* `equipment` (required) - Equipment type (possible values: `barbell`, `dumbbell`, `bodyweight`, `machine`, `cardio`)
* `difficulty` (optional) - Skill level (possible values: `beginner`, `intermediate`, `advanced`)
* `imeta` (optional) - Media metadata for form demonstrations following NIP-92 format
* `t` (optional, repeated) - Hashtags for categorization such as muscle group or body movement (possible values: `chest`, `legs`, `push`, `pull`)

```
{
  "id": <32-bytes lowercase hex-encoded SHA-256 of the serialized event data>,
  "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
  "created_at": <Unix timestamp in seconds>,
  "kind": 33401,
  "content": "<detailed form instructions and notes>",
  "tags": [
    ["d", "<UUID>"],
    ["title", "<exercise name>"],
    ["format", "<parameter>", "<parameter>", "<parameter>", "<parameter>"],
    ["format_units", "<unit>", "<unit>", "<unit>", "<unit>"],
    ["equipment", "<equipment type>"],
    ["difficulty", "<skill level>"],
    ["imeta", 
      "url <url to demonstration media>",
      "m <media type>",
      "dim <dimensions>",
      "alt <alt text>"
    ],
    ["t", "<hashtag>"],
    ["t", "<hashtag>"],
    ["t", "<hashtag>"]
  ]
}
```

### Workout Template (kind: 33402)
Defines a complete workout plan. The `content` field contains workout notes and instructions. Workout templates can prescribe specific parameters while leaving others configurable by the user performing the workout.

#### Format

The format uses an _addressable event_ of `kind:33402`.

The `.content` of these events SHOULD contain workout notes and instructions. It is required but can be an empty string.

The list of tags are as follows:

* `d` (required) - universally unique identifier (UUID). Generated by the client creating the workout template.
* `title` (required) - Workout name
* `type` (required) - Type of workout (possible values: `strength`, `circuit`, `emom`, `amrap`)
* `exercise` (required, repeated) - Exercise reference and prescription. Format: ["exercise", "<kind>:<pubkey>:<d-tag>", "<relay-url>", ...parameters matching exercise template format]
* `rounds` (optional) - Number of rounds for repeating formats
* `duration` (optional) - Total workout duration in seconds
* `interval` (optional) - Duration of each exercise portion in seconds (for timed workouts)
* `rest_between_rounds` (optional) - Rest time between rounds in seconds
* `t` (optional, repeated) - Hashtags for categorization

```
{
  "id": <32-bytes lowercase hex-encoded SHA-256 of the serialized event data>,
  "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
  "created_at": <Unix timestamp in seconds>,
  "kind": 33402,
  "content": "<workout notes and instructions>",
  "tags": [
    ["d", "<UUID>"],
    ["title", "<workout name>"],
    ["type", "<workout type>"],
    ["rounds", "<number of rounds>"],
    ["duration", "<duration in seconds>"],
    ["interval", "<interval in seconds>"],
    ["rest_between_rounds", "<rest time in seconds>"],
    ["exercise", "<kind>:<pubkey>:<d-tag>", "<relay-url>", "<param1>", "<param2>", "<param3>", "<param4>"],
    ["exercise", "<kind>:<pubkey>:<d-tag>", "<relay-url>", "<param1>", "<param2>", "<param3>", "<param4>"],
    ["t", "<hashtag>"],
    ["t", "<hashtag>"]
  ]
}
```

### Workout Record (kind: 1301)
Records a completed workout session. The `content` field contains notes about the workout.

#### Format

The format uses a standard event of `kind:1301`.

The `.content` of these events SHOULD contain notes about the workout experience. It is required but can be an empty string.

The list of tags are as follows:

* `d` (required) - universally unique identifier (UUID). Generated by the client creating the workout record.
* `title` (required) - Workout name
* `type` (required) - Type of workout (possible values: `strength`, `circuit`, `emom`, `amrap`)
* `exercise` (required, repeated) - Exercise reference and completion data. Format: ["exercise", "<kind>:<pubkey>:<d-tag>", "<relay-url>", ...parameters matching exercise template format]
* `start` (required) - Unix timestamp in seconds for workout start
* `end` (required) - Unix timestamp in seconds for workout end
* `completed` (required) - Boolean indicating if workout was completed as planned
* `rounds_completed` (optional) - Number of rounds completed
* `interval` (optional) - Duration of each exercise portion in seconds (for timed workouts)
* `template` (optional) - Reference to the workout template used, if any. Format: ["template", "<kind>:<pubkey>:<d-tag>", "<relay-url>"]
* `pr` (optional, repeated) - Personal Record achieved during workout. Format: "<kind>:<pubkey>:<d-tag>,<metric>,<value>"
* `t` (optional, repeated) - Hashtags for categorization

```
{
  "id": <32-bytes lowercase hex-encoded SHA-256 of the serialized event data>,
  "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
  "created_at": <Unix timestamp in seconds>,
  "kind": 1301,
  "content": "<workout notes>",
  "tags": [
    ["d", "<UUID>"],
    ["title", "<workout name>"],
    ["type", "<workout type>"],
    ["rounds_completed", "<number of rounds completed>"],
    ["start", "<Unix timestamp in seconds>"],
    ["end", "<Unix timestamp in seconds>"],
    
    ["exercise", "<kind>:<pubkey>:<d-tag>", "<relay-url>", "<weight>", "<reps>", "<rpe>", "<set_type>"],
    ["exercise", "<kind>:<pubkey>:<d-tag>", "<relay-url>", "<weight>", "<reps>", "<rpe>", "<set_type>"],
    
    ["template", "<kind>:<pubkey>:<d-tag>", "<relay-url>"],
    ["pr", "<kind>:<pubkey>:<d-tag>,<metric>,<value>"],
    ["completed", "<true/false>"],
    ["t", "<hashtag>"],
    ["t", "<hashtag>"]
  ]
}
```

## Exercise Parameters

### Standard Parameters and Units
* `weight` - Load in kilograms (kg). Empty string for bodyweight exercises, negative values for assisted exercises
* `reps` - Number of repetitions (count)
* `rpe` - Rate of Perceived Exertion (0-10):
  - RPE 10: Could not do any more reps, technical failure
  - RPE 9: Could maybe do 1 more rep
  - RPE 8: Could definitely do 1 more rep, maybe 2
  - RPE 7: Could do 2-3 more reps
* `duration` - Time in seconds
* `set_type` - Set classification (possible values: `warmup`, `normal`, `drop`, `failure`)

Additional parameters can be defined in exercise templates in the `format_units` tag as needed for specific activities (e.g., distance, heartrate, intensity).

## Workout Types and Terminology

This specification provides examples of common workout structures but is not limited to these types. The format is extensible to support various training methodologies while maintaining consistent data structure.

### Common Workout Types

#### Strength
Traditional strength training focusing on sets and reps with defined weights. Typically includes warm-up sets, working sets, and may include techniques like drop sets or failure sets.

#### Circuit
Multiple exercises performed in sequence with minimal rest between exercises and defined rest periods between rounds. Focuses on maintaining work rate through prescribed exercises.

#### EMOM (Every Minute On the Minute)
Time-based workout where specific exercises are performed at the start of each minute. Rest time is whatever remains in the minute after completing prescribed work.

#### AMRAP (As Many Rounds/Reps As Possible)
Time-capped workout where the goal is to complete as many rounds or repetitions as possible of prescribed exercises while maintaining proper form.

## Set Types

### Normal Sets
Standard working sets that count toward volume and progress tracking.

### Warm-up Sets
Preparatory sets using submaximal weights. These sets are not counted in metrics or progress tracking.

### Drop Sets
Sets performed immediately after a working set with reduced weight. These are counted in volume calculations but tracked separately for progress analysis.

### Failure Sets
Sets where technical failure was reached before completing prescribed reps. These sets are counted in metrics but marked to indicate intensity/failure was reached.

## Examples

### Exercise Template
```
{
  "kind": 33401,
  "content": "Stand with feet hip-width apart, barbell over midfoot. Hinge at hips, grip bar outside knees. Flatten back, brace core. Drive through floor, keeping bar close to legs.\n\nForm demonstration: https://powr.me/exercises/deadlift-demo.mp4",
  "tags": [
    ["d", "<UUID-deadlift>"],
    ["title", "Barbell Deadlift"],
    ["format", "weight", "reps", "rpe", "set_type"],
    ["format_units", "kg", "count", "0-10", "warmup|normal|drop|failure"],
    ["equipment", "barbell"],
    ["difficulty", "intermediate"],
    ["imeta", 
      "url https://powr.me/exercises/deadlift-demo.mp4",
      "m video/mp4",
      "dim 1920x1080",
      "alt Demonstration of proper barbell deadlift form"
    ],
    ["t", "compound"],
    ["t", "legs"],
    ["t", "posterior"]
  ]
}
```

### EMOM Workout Template
```
{
  "kind": 33402,
  "content": "20 minute EMOM alternating between squats and deadlifts every 30 seconds. Scale weight as needed to complete all reps within each interval.",
  "tags": [
    ["d", "<UUID-emom-template>"],
    ["title", "20min Squat/Deadlift EMOM"],
    ["type", "emom"],
    ["duration", "1200"],
    ["rounds", "20"],
    ["interval", "30"],
    
    ["exercise", "33401:<pubkey>:<UUID-squat>", "<relay-url>", "", "5", "7", "normal"],
    ["exercise", "33401:<pubkey>:<UUID-deadlift>", "<relay-url>", "", "4", "7", "normal"],
    
    ["t", "conditioning"],
    ["t", "legs"]
  ]
}
```

### Circuit Workout Record
```
{
  "kind": 1301,
  "content": "Completed first round as prescribed. Second round showed form deterioration on deadlifts.",
  "tags": [
    ["d", "<UUID-workout-record>"],
    ["title", "Leg Circuit"],
    ["type", "circuit"],
    ["rounds_completed", "1.5"],
    ["start", "1706454000"],
    ["end", "1706455800"],
    
    ["exercise", "33401:<pubkey>:<UUID-squat>", "<relay-url>", "80", "12", "7", "normal"],
    ["exercise", "33401:<pubkey>:<UUID-deadlift>", "<relay-url>", "100", "10", "7", "normal"],
    
    ["exercise", "33401:<pubkey>:<UUID-squat>", "<relay-url>", "80", "12", "8", "normal"],
    ["exercise", "33401:<pubkey>:<UUID-deadlift>", "<relay-url>", "100", "4", "10", "failure"],
    
    ["completed", "false"],
    ["t", "legs"]
  ]
}
```

## Implementation Guidelines

1. All workout records MUST include accurate start and end times
2. Templates MAY prescribe specific parameters while leaving others as empty strings for user input
3. Records MUST include actual values for all parameters defined in exercise format
4. Failed sets SHOULD be marked with `failure` set_type
5. Records SHOULD be marked as `false` for completed if prescribed work wasn't completed
6. PRs SHOULD only be tracked in workout records, not templates
7. Exercise references MUST use the format "kind:pubkey:d-tag" to ensure proper attribution and versioning

## POWR App Implementation

The POWR app implements this NIP specification to provide a comprehensive workout tracking system with social sharing capabilities:

1. **Local-First Architecture**: All workout data is stored locally first, then optionally published to Nostr relays
2. **Exercise Template Library**: Users can create, share, and discover exercise templates
3. **Workout Planning**: Templates enable consistent workout planning with proper progression
4. **Workout Records**: Completed workouts are recorded with detailed performance metrics
5. **Social Sharing**: Users can share templates and achievements with the Nostr community
6. **Cross-Device Synchronization**: Workout history can be synchronized through Nostr relays

The implementation follows a three-tier approach to content publishing:
- **Local Only**: Private data stored only on the user's device
- **Publish to Relays**: Data published to Nostr relays but not explicitly shared socially
- **Social Sharing**: Published data with additional social metadata for discovery

## Related Documentation

- [Workout Completion Flow](../../features/workout/completion_flow.md) - Implementation of this NIP in the workout completion process
- [NDK Comprehensive Guide](../ndk/comprehensive_guide.md) - Guide to using the Nostr Development Kit
- [Social Architecture](../../features/social/architecture.md) - Architecture for social integration using Nostr
- [Project MVP and Targeted Rebuild](../../project/mvp_and_rebuild.md) - Overall project roadmap and priorities

## References

This NIP draws inspiration from:
- [NIP-01: Basic Protocol Flow Description](https://github.com/nostr-protocol/nips/blob/master/01.md)
- [NIP-52: Calendar Events](https://github.com/nostr-protocol/nips/blob/master/52.md)
- [NIP-92: Media Attachments](https://github.com/nostr-protocol/nips/blob/master/92.md#nip-92)
