syntax-workout-core 0.1.0

Workout tree algebra — represent any physical workout as a recursive tree
Documentation

syntax-workout-sdk

Workout tree algebra -- represent any physical workout as a recursive tree.

crates.io npm PyPI CI License

Install

Rust

[dependencies]
syntax-workout-core = "0.1"

Node.js

npm install @syntax-workout/sdk

Python

pip install syntax-workout-sdk

Core concept

Every workout is a tree of Nodes. Leaf nodes are individual sets; inner nodes group them into exercises, blocks, sessions, days, weeks, phases, and programs.

Program
  Week
    Day
      Session ("Upper Hypertrophy")
        Block (Sequential)           -- straight sets
          Exercise ("Bench Press")
            Set [100kg x 5]
            Set [100kg x 5]
        Block (Parallel)             -- superset
          Exercise ("DB Row")
            Set [30kg x 10]
          Exercise ("Lateral Raise")
            Set [12.5kg x 15]
        Block (Circuit {rounds: 3})  -- circuit
          Exercise ("Squat")
            Set [60kg x 15]
          Exercise ("Push-up")
            Set [20 reps]
          Exercise ("Plank")
            Set [60s]

Each Node carries a kind, a payload, optional children, and open-ended metadata.

Quick example

Rust (builder API)

use syntax_workout_core::builder::*;
use syntax_workout_core::{ExecutionMode, Intensity};
use syntax_workout_core::measure::WeightUnit;

let workout = WorkoutBuilder::new("w1")
    .sport("strength")
    .date("2026-03-29")
    .root(session("Upper Hypertrophy", |s| {
        s.block(ExecutionMode::Parallel, |b| {
            b.name("Superset A")
             .rest(90.0)
             .exercise("DB Row", |e| {
                 e.set(vec![weight(30.0, WeightUnit::Kg), reps(10)], Some(rpe(8.0)));
             })
             .exercise("Incline Press", |e| {
                 e.set(vec![weight(25.0, WeightUnit::Kg), reps(12)], None);
             });
        });
    }))
    .build();

let json = serde_json::to_string_pretty(&workout).unwrap();

Node.js (parse + validate)

import { readFileSync } from 'fs';
import { parseWorkout, validateWorkout, countSets } from '@syntax-workout/sdk';

const json = readFileSync('examples/strength/supersets.json', 'utf-8');

// Parse and round-trip through Rust types
const workout = JSON.parse(parseWorkout(json));
console.log(workout.sport); // "strength"

// Validate only (returns error strings, empty = valid)
const errors = validateWorkout(json);

// Count total sets
const sets = countSets(json);

Python (parse + validate)

import syntax_workout_sdk

json_str = open("examples/strength/supersets.json").read()

# Parse into Python dict
workout = syntax_workout_sdk.parse_workout(json_str)
print(workout["sport"])  # "strength"

# Validate only
errors = syntax_workout_sdk.validate_workout(json_str)

# Count sets
count = syntax_workout_sdk.count_sets(json_str)

ExecutionMode

Controls how children of a Block node are performed.

Mode Meaning Example
Sequential Finish all sets of exercise A, then B Straight sets
Parallel Alternate sets across exercises Supersets, giant sets
Circuit { rounds: N } Cycle through all exercises N times Circuit training
Custom(String) User-defined AMRAP, EMOM

Measure variants

Variant Fields Example
Reps u32 Reps(10)
Weight value: f64, unit: Kg|Lbs Weight { 80.0, Kg }
Distance value: f64, unit: Meters|Kilometers|Miles Distance { 5.0, Km }
Duration seconds: f64 Duration { 180.0 }
Pace per: DistanceUnit, seconds: f64 Pace { Km, 330.0 }
HeartRate bpm: u32 HeartRate { 145 }
Calories u32 Calories(350)
Custom name: String, value: Value Custom { "elevation", 150 }

Intensity variants

Variant Fields Example
PercentOfMax f64 (0.0-1.0) PercentOfMax(0.80)
RPE f64 (1-10) RPE(8.5)
RIR u32 RIR(2)
Bodyweight -- Bodyweight
Custom name: String, value: Value Custom { "zone", 3 }

Examples

See examples/ for JSON workout files covering strength, endurance, and mixed modalities.

License

MIT OR Apache-2.0