{"id":40324791,"url":"https://github.com/tare/zwog","last_synced_at":"2026-01-20T07:34:38.388Z","repository":{"id":45493143,"uuid":"282536815","full_name":"tare/zwog","owner":"tare","description":"Grammar-based generation of structured cycling workouts","archived":false,"fork":false,"pushed_at":"2025-08-07T20:56:09.000Z","size":150,"stargazers_count":5,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-29T11:26:24.648Z","etag":null,"topics":["cycling","cycling-workouts","workout","workout-generator","workouts","zwift"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-25T22:42:44.000Z","updated_at":"2025-06-03T15:22:16.000Z","dependencies_parsed_at":"2025-01-03T23:33:58.530Z","dependency_job_id":null,"html_url":"https://github.com/tare/zwog","commit_stats":{"total_commits":78,"total_committers":1,"mean_commits":78.0,"dds":0.0,"last_synced_commit":"8b740248a82b43308efa21bcb933e6c58357bb7b"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tare/zwog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tare%2Fzwog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tare%2Fzwog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tare%2Fzwog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tare%2Fzwog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tare","download_url":"https://codeload.github.com/tare/zwog/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tare%2Fzwog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28598166,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T02:08:49.799Z","status":"ssl_error","status_checked_at":"2026-01-20T02:08:44.148Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cycling","cycling-workouts","workout","workout-generator","workouts","zwift"],"created_at":"2026-01-20T07:34:38.184Z","updated_at":"2026-01-20T07:34:38.379Z","avatar_url":"https://github.com/tare.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zwift workout generator\n\nHave you ever been frustrated by any WYSIWYG workout editor, such as the [Zwift Workout editor](https://zwift.com/news/12975-zwift-how-to-creating-a-custom-workout) and the [TrainingPeaks Workout Builder](https://help.trainingpeaks.com/hc/en-us/articles/235164967-Structured-Workout-Builder)?\n\nZWOG makes it easier to generate structured workouts using a syntax similar to the one used on [What's on Zwift?](https://whatsonzwift.com).\n\n### Installation\n\n#### PyPI\n\nInstall the latest stable version from PyPI\n\n```console\n$ pip install zwog\n```\n\n#### GitHub\n\nInstall the version from the main branch\n\n```console\n$ pip install git+https://github.com/tare/zwog.git\n```\n\n### Syntax\n\nThe basic building blocks are ramp intervals\n\n```\n10min from 30 to 60% FTP\n```\n\nand steady state intervals\n\n```\n2hrs 10min @ 60% FTP\n```\n\nInterval durations can be given in seconds (`sec`,`s`), minutes (`min`,`m`), and hours (`hrs`,`h`).\n\nMoreover, it is possible to create repeated intervals\n\n```\n4x 5min @ 95% FTP, 5min @ 85% FTP\n```\n\nFinally, a complete workout can be defined as follows\n\n```\n10min from 40 to 85% FTP\n3x 5min @ 95% FTP, 5min @ 86% FTP\n5min @ 50% FTP\n3x 5min @ 95% FTP, 5min @ 86% FTP\n10min from 75 to 55% FTP\n```\n\nThe parser is rather robust when it comes to newlines and other whitespaces.\n\n### Usage\n\nYou can use the command line application\n\n```console\n$ zwog --help\nusage: zwog [-h] -i INPUT_FILE [-o OUTPUT_FILE] [-a AUTHOR] [-n NAME]\n            [-c CATEGORY] [-s SUBCATEGORY] [-v]\n\nZwift workout generator\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -i INPUT_FILE, --input_file INPUT_FILE\n                        input filename\n  -o OUTPUT_FILE, --output_file OUTPUT_FILE\n                        output filename\n  -a AUTHOR, --author AUTHOR\n                        author name\n  -n NAME, --name NAME  workout name\n  -c CATEGORY, --category CATEGORY\n                        category\n  -s SUBCATEGORY, --subcategory SUBCATEGORY\n                        subcategory\n  -v, --version         show program's version number and exit\n```\n\nor call it from Python\n\n```python\nimport zwog\n\nworkout_text = \"15min from 10 to 50% FTP 5min from 50 to 70% FTP 2x 0.5hrs @ 100% FTP, 0.5hrs @ 50% FTP, 10min from 80 to 90% FTP 2min @ 50% FTP\\n2min @ 50% FTP\\n 10min @ 50% FTP, 10min @ 60% FTP 10min from 50 to 10% FTP\"\nworkout = zwog.ZWOG(workout_text)\nworkout.save_zwo('workout.xml')\nprint(workout)\nprint(f\"{round(workout.tss)} TSS\")\n```\n\n### Limitations\n\n- Only the [ZWO file format](https://github.com/h4l/zwift-workout-file-reference/blob/master/zwift_workout_file_tag_reference.md) is supported currently\n- Workout files have to be uploaded [manually](https://zwiftinsider.com/load-custom-workouts/) to Zwift\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftare%2Fzwog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftare%2Fzwog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftare%2Fzwog/lists"}