Workout Creation Tools CLI Surface¶
This document defines the current canonical CLI surface for the AeroBeat workout creation tools repo.
It extends the locked product and repo direction already captured in:
docs/architecture/workout-creation-tools-architecture.mddocs/architecture/content-repo-shapes.mddocs/architecture/content-lane-implementation-phases.mddocs/architecture/workout-package-storage-and-discovery.md
The goal of this document is to make the first CLI slice actionable without prematurely freezing low-level implementation details.
Purpose¶
The workout creation tools repo needs a headless-first surface that creators, CI, automation, and future GUI/editor flows can all rely on.
That CLI surface exists to support the package-authoring workflows already locked for the product:
- validate authored records and complete workout packages
- inspect package structure and resolved relationships
- repair safe structural/content problems through explicit fix flows
- migrate authored records between approved schema/layout versions
- package validated content into distributable outputs
- import approved source media and external authoring inputs into canonical package form
Locked CLI direction¶
Separate public tools early¶
The locked direction is to keep separate public CLI tools early, one per authored YAML domain or package-level workflow surface, rather than collapsing everything into one large primary CLI with a deep subcommand tree.
That means the public surface should stay visibly split across the current package domains:
workoutsongchartsetcoach-configenvironment
The exact executable names may evolve, but the domain split should remain explicit.
Public tool set¶
Package-orchestrator tool¶
The workout tool is the package-wide orchestrator because workout.yaml is the package root and owns the ordered setId list.
Its responsibilities include:
- package-wide validation orchestration
- package-wide repair orchestration
- package-wide migration orchestration when the whole package must move together
- package-wide packaging/build entrypoints
- package-home inspection of overall health, references, and topology
- routing package import workflows that affect package-level structure or multiple domains
Domain tools¶
The other public tools are domain-specific surfaces for authored records that live under the package root:
songchartsetcoach-configenvironment
Their primary job is to own domain-local workflows without pretending to be full-package authority.
Canonical executable naming direction¶
The repo should ship separate executables with names that make the split obvious.
Current canonical naming direction:
aerobeat-workoutaerobeat-songaerobeat-chartaerobeat-setaerobeat-coach-configaerobeat-environment
This document does not lock packaging/distribution details such as whether these are standalone wrappers, symlinked launchers, or thin entry scripts over a shared binary/runtime. It only locks the public CLI surface split.
Shared rules across all CLI tools¶
Command categories¶
The minimum durable workflow categories across the repo are:
validatefixinspectmigratepackageimport
Not every category belongs equally on every domain tool. The surface should stay honest about which commands are domain-local and which are package-level orchestration.
Validation rule¶
Plain validation must report problems, not silently mutate content.
If a package or record is invalid:
- validation should hard-error
- output should explain the problem in creator-friendly language
- machine-readable output should also be available for CI/automation
- fixable issues should direct the user toward explicit
fixflows
Fix rule¶
Repair is always explicit.
- broad repair should use
fix - narrower repair entrypoints may use more specific forms such as
fix-ids,fix-layout, or similar names when justified - validation must not auto-run repair as a hidden side effect
Accepted-vs-stored format rule¶
Import-oriented commands must preserve the locked distinction between:
- accepted source/import formats
- stored canonical package formats
That means import flows may accept broader source media types, but package storage must still converge on the locked canonical directions where applicable:
- song audio stored as
.ogg - coaching audio stored as
.ogg - coaching video stored as
.ogv - environment video stored as
.ogv - images stored as
.png - 3D environments stored as vanilla
.glb
Media normalization rule¶
When import or replacement commands handle media, they should route through the shared FFmpeg-backed normalization workflow where relevant before updating package references.
Output rule¶
Each public CLI tool should support at least:
- human-readable terminal output
- structured JSON output for automation
The document does not lock exact flags, but a conventional form such as --format text|json or --json is expected.
Package-level vs domain-level authority¶
workout validate is the package-wide validator¶
The central validation boundary is locked:
aerobeat-workout validateperforms full package validation- it walks
workout.yaml, orderedsetIdvalues, and the referenced song/chart/environment/coach-config records - it verifies package topology, cross-record id integrity, and package-level rules
- it may call the lower-level validators for referenced records internally
Domain validation is not secretly package validation¶
The domain tools must stay narrower:
aerobeat-song validatevalidates song-record shape, song-local rules, and directly referenced file existence relevant to the song domainaerobeat-chart validatevalidates chart-record shape and chart-local rulesaerobeat-set validatevalidates set-record shape and direct set-local reference integrityaerobeat-coach-config validatevalidates the workout package's single coaching domain recordaerobeat-environment validatevalidates environment-record shape and directly referenced environment media
Those commands may be used independently during authoring, but they do not imply whole-package health.
Baseline command surface by tool¶
aerobeat-workout¶
Purpose¶
Package-home surface for complete workout package workflows.
Baseline commands¶
validate <workout-path-or-package-dir>- run package-wide validation
- resolve and validate referenced sets, songs, charts, coach config, environments, and package layout rules
fix <workout-path-or-package-dir>- run package-wide safe structural/content repair after explicit user request
inspect <workout-path-or-package-dir>- show package metadata, ordered sets, high-level health, schema/tool provenance, and unresolved reference summaries
migrate <workout-path-or-package-dir> --target <schema-or-tool-version>- run package-wide migration when coordinated changes must happen across package records
package <workout-path-or-package-dir> --output <dir>- produce the distributable package artifact(s)
import <package-dir> ...- package-level import flows only when they create or update package-wide structure, bootstrap a package, or coordinate multiple domain changes
Clearly justified import-oriented commands¶
The package-level tool may own commands such as:
import package-shell <dir>- bootstrap a new package folder with canonical subfolders and starter files
import workout-metadata <source> <package-dir>- populate package-home metadata from an approved source when that workflow proves useful
This tool should not absorb every import case by default. Slot- and record-specific imports should stay on the domain tools when that keeps ownership cleaner.
aerobeat-song¶
Purpose¶
Own song-record authoring operations and canonical song-audio slot workflows.
Baseline commands¶
validate <song-yaml>fix <song-yaml>inspect <song-yaml>migrate <song-yaml> --target <schema-or-tool-version>import audio <source-file> --record <song-yaml>
Notes¶
import audioshould validate the source for song-audio use, normalize it into canonical stored.ogg, place it into the package media location, rename it to the normalized uid-suffixed pattern, update YAML references, and remove the superseded slotted asset on replacement.packageis not a baselinesongcommand because packaging is a package-level concern.
aerobeat-chart¶
Purpose¶
Own chart-record validation, migration, inspection, and import/conversion workflows for chart-authored data.
Baseline commands¶
validate <chart-yaml>fix <chart-yaml>inspect <chart-yaml>migrate <chart-yaml> --target <schema-or-tool-version>import <external-chart-source> --record <chart-yaml>
Notes¶
- Import here is justified because external chart conversion is a chart-domain workflow.
packageis not a baselinechartcommand.- Future chart testing helpers may exist later, but they are not locked as day-one baseline CLI surface in this document.
aerobeat-set¶
Purpose¶
Own set-record shape, exact package-local composition wiring, and structural repair of set-local references.
Baseline commands¶
validate <set-yaml>fix <set-yaml>inspect <set-yaml>migrate <set-yaml> --target <schema-or-tool-version>
Notes¶
- A set record links
songId,chartId,environmentId, and optionalcoachingOverlayId. - No baseline
packagecommand belongs here. - No separate baseline import command is required unless a real external source format for set composition emerges.
aerobeat-coach-config¶
Purpose¶
Own the workout package's single coaching-domain record and the workflow around coaching media slots.
Baseline commands¶
validate <coach-config-yaml>fix <coach-config-yaml>inspect <coach-config-yaml>migrate <coach-config-yaml> --target <schema-or-tool-version>import warmup-video <source-file> --record <coach-config-yaml>import cooldown-video <source-file> --record <coach-config-yaml>import overlay-audio <source-file> --record <coach-config-yaml> --overlay-id <id>
Notes¶
- Video imports should normalize accepted source video into canonical stored
.ogv. - Overlay audio imports should normalize accepted source audio into canonical stored
.ogg. - The tool should preserve the locked optional-all-or-nothing coaching model already documented elsewhere.
aerobeat-environment¶
Purpose¶
Own environment-record validation, inspection, migration, and environment-media import helpers.
Baseline commands¶
validate <environment-yaml>fix <environment-yaml>inspect <environment-yaml>migrate <environment-yaml> --target <schema-or-tool-version>import background-image <source-file> --record <environment-yaml>import background-video <source-file> --record <environment-yaml>import glb <source-file> --record <environment-yaml>
Notes¶
- Image imports should support the bounded crop/fit workflow already described in the architecture direction before canonical
.pngstorage. - Video imports should normalize to canonical stored
.ogv. - 3D environment imports should preserve the current locked vanilla
.glbstorage direction rather than reopening Draco/KTX2 work.
Public CLI boundary vs shared internal libraries¶
What is public¶
The public surface of the repo is the set of creator-facing/automation-facing CLI tools and their commands.
These public tools own:
- argument parsing and command routing
- terminal and JSON presentation
- exit codes
- user confirmation prompts where needed
- stable workflow naming visible to creators and CI
What stays internal¶
The repo should also keep a shared internal workflow layer that is not treated as the public CLI contract.
That internal layer should own reusable services such as:
- validation services
- fix/repair services
- migration services
- package assembly services
- import and normalization services
- package graph loading and reference resolution
- record read/write helpers
- file replacement and canonical naming helpers
- diagnostics/result DTO mapping
Why this boundary matters¶
This keeps the repo aligned with the already-locked rule that CLI and GUI/editor flows should call the same underlying services where possible.
The public CLI tools are separate because the workflow surfaces are separate. The implementation should still reuse shared services so the repo does not grow six unrelated repair engines.
Recommended internal shape¶
A practical first-pass internal split is:
cli/or equivalent launchers for each public toolservices/validation/services/fix/services/migration/services/packaging/services/import/services/package_graph/services/io/mappers/orformatters/for terminal/JSON output adaptation
The exact folders may change, but the architectural boundary should remain:
- public tool surfaces are separate
- shared workflow implementation is reused internally
Exit-code and automation expectations¶
Each tool should be safe for CI and scripting.
Baseline expectations:
- success exits non-zero only on actual failure
- validation failures return a failing exit code
- malformed CLI usage returns a distinct failing exit code
inspectcan be consumed by humans and JSON-based automation- package-wide workflows should emit enough machine-readable detail for future editor integration and CI summary generation
This document does not lock a full numeric exit-code matrix yet.
Non-goals for this slice¶
This CLI surface spec does not promise:
- one universal
aerobeatCLI hiding the domain split - full-package validation from every domain validator
- auto-repair during plain validation
- GUI/editor command parity in day-one syntax
- broad media-production tooling beyond bounded import/normalization workflows
- low-level parser/runtime implementation details
- current-scope KTX2 texture optimization or Draco-compressed GLB pipelines
Recommended implementation posture¶
Implementation should proceed in this order:
- stand up the shared internal service layer for validation, fix, migration, import, and packaging
- ship
aerobeat-workout validatefirst so package-wide orchestration is real early - ship the domain-local
validateandinspectcommands next - add explicit
fixflows rather than hidden repair behavior - add import commands for song audio, coaching media, environment media, and chart conversion
- add migration and packaging flows once the base package graph and canonical I/O are stable
That order preserves the most important locked boundary: the workout creation product is one repo and one product, but its CLI should still expose separate domain tools with a package-wide workout orchestrator surface.