Content Repo Shapes: aerobeat-content-core and aerobeat-tool-content-authoring¶
This document turns the approved Content-lane architecture into concrete day-one repo recommendations for the first two repos in the lane:
aerobeat-content-coreas the canonical owner of durable authored-content contractsaerobeat-tool-content-authoringas the first concrete Tool-lane product that authors, validates, migrates, packages, and inspects that content
The goal is not to over-design a future platform. The goal is to make repo creation safe by defining what belongs in each repo on day one, what explicitly stays out, and how CLI/headless and optional editor UX share one service layer.
Architecture position¶
These repo shapes assume the six-core model already documented elsewhere:
aerobeat-content-coreowns the durable content language:Song,Set,Chart,Workout, shared chart-envelope contracts, ids, manifests, schema/version rules, shared validators, registry/query interfaces, and workout resolution contracts.aerobeat-tool-coreowns shared tool-side operational models, progress/result DTOs, and other tool-common contracts.aerobeat-tool-content-authoringis a concrete Tool-lane product built on top ofaerobeat-content-coreandaerobeat-tool-core.aerobeat-feature-coreand concreteaerobeat-feature-*repos consume content contracts and own runtime interpretation, scoring, spawning, and presentation systems such as 2D lanes and 3D portals.
If a repo shape below conflicts with that ownership model, the ownership model wins.
Day-one recommendation: aerobeat-content-core¶
Purpose¶
aerobeat-content-core should be created as a dependency-light contract repo. It is the durable source of truth for authored content shapes shared by runtime, tools, tests, and packages.
It should answer: "What is valid AeroBeat content?" not "How does the user author it?" and not "How does the runtime render or score it?"
Day-one directory shape¶
aerobeat-content-core/
├── interfaces/
│ ├── chart_loader.gd
│ ├── content_registry.gd
│ ├── content_migration.gd
│ └── workout_resolution.gd
├── data_types/
│ ├── content_id.gd
│ ├── song.gd
│ ├── set.gd
│ ├── chart.gd
│ ├── workout.gd
│ ├── chart_envelope.gd
│ ├── content_package_manifest.gd
│ ├── content_reference.gd
│ └── content_query.gd
├── validators/
│ ├── content_validation_result.gd
│ ├── content_validation_issue.gd
│ └── content_package_validator.gd
├── globals/
│ ├── aero_content_schema.gd
│ ├── content_feature.gd
│ ├── content_difficulty.gd
│ └── interaction_family.gd
├── fixtures/
│ ├── package_minimal_boxing/
│ │ ├── manifest.json
│ │ ├── songs/song-demo.json
│ │ ├── sets/song-demo-opening-round.json
│ │ ├── charts/song-demo-boxing-medium.json
│ │ └── workouts/demo-workout.json
│ └── invalid_missing_song_ref/
├── tests/
│ ├── test_content_manifest_contract.gd
│ ├── test_content_reference_validation.gd
│ └── test_workout_resolution_contract.gd
├── plugin.cfg
├── LICENSE.md
├── README.md
└── addons.jsonc
The exact filenames can evolve, but the shape categories should not: contracts in interfaces/, durable records in data_types/, shared structural validation in validators/, stable enums/constants in globals/, and canonical examples in fixtures/ + tests/.
Day-one core files and what they mean¶
Durable record contracts¶
data_types/song.gd- canonical
Songcontract - audio/timing authority, metadata, licensing references, global tags
data_types/set.gd- canonical
Setcontract - package-local composition links for one exact playable slice, including song/chart/environment selections and optional coaching overlays
data_types/chart.gd- canonical
Chartcontract - difficulty, interaction family, input-profile compatibility fields, event stream envelope
data_types/workout.gd- canonical
Workoutcontract - session sequencing through ordered
setIdreferences plus workout-level metadata data_types/chart_envelope.gd- shared top-level chart shape used by all modes
data_types/content_package_manifest.gd- package boundary contract for distribution/import/indexing
Support contracts¶
data_types/content_id.gd- stable typed ids and/or helper structure for
songId,setId,chartId,workoutId,packageId data_types/content_reference.gd- explicit reference object shape used across packages, workouts, manifests, and registry results
data_types/content_query.gd- query/filter/result-key shape used by registry lookup contracts
Interfaces¶
interfaces/chart_loader.gd- defines how a consumer asks for chart content by id/path/reference
- should return shared contracts, not feature-local runtime objects
interfaces/content_registry.gd- defines query and lookup semantics for songs, sets, charts, workouts, and resources
- should describe the interface, not storage or network implementation
interfaces/content_migration.gd- defines migration contract and migration report/result semantics
interfaces/workout_resolution.gd- resolves workout steps into a concrete playable chart selection without owning runtime playback
Shared structural validation¶
validators/content_validation_result.gd- stable validation report shape consumable by tools, runtime, tests, and CI
validators/content_validation_issue.gd- issue category, severity, path/reference, and machine-readable code contract
validators/content_package_validator.gd- shared structural validator for ids, references, required fields, manifest integrity, and workout resolution legality
Global enums/constants¶
globals/aero_content_schema.gd- schema ids, schema families, version constants, and compatibility helpers
globals/content_feature.gd- stable feature ids such as active
boxingandflow, with room for future feature ids later globals/content_difficulty.gd- canonical difficulty vocabulary
globals/interaction_family.gd- stable interaction-family vocabulary such as
gesture_2d,tracked_6dof,hybrid
Example resources and tests¶
fixtures/package_minimal_boxing/*- one tiny but real package proving the contract works end-to-end for a single set/chart/workout path
fixtures/invalid_missing_song_ref/*- one intentionally broken package for validator regression coverage
tests/*- contract tests proving ids, references, manifest rules, and workout resolution semantics
Day-one ownership boundaries¶
aerobeat-content-core should own:
- canonical content records
- shared chart envelope
- content ids, references, and manifest primitives
- registry/query interfaces and lookup semantics
- schema/version identifiers and migration interfaces
- shared structural validation contracts and validators
- canonical fixtures and contract tests for the shared content language
aerobeat-content-core should depend on:
- no other AeroBeat core repo by default
- only vendor/test dependencies needed to run contract tests
aerobeat-content-core must not own:
- editor UX
- CLI command parsing or terminal presentation
- backend upload/download workflow state
- import adapters for third-party file formats
- feature scoring rules
- mode-specific semantic validation that belongs in feature repos
- 2D lane renderers, 3D portal systems, spawn systems, or any other content-consuming runtime visuals
- Godot scenes whose main job is authoring UI or runtime presentation
Day-one non-goals for aerobeat-content-core¶
Do not try to ship all future content infrastructure in the first cut.
Explicit non-goals:
- no registry server or hosted catalog service
- no validator SaaS or background worker service
- no moderation/publishing pipeline
- no web upload flow
- no mode-specific editor plugins
- no cloud sync/index implementation
- no package installer UI
- no runtime caching/streaming optimization layer
- no replacement for feature-local payload semantics
The first repo should be boring in the best way: stable contracts, clean tests, and small fixtures.
Day-one recommendation: aerobeat-tool-content-authoring¶
Purpose¶
aerobeat-tool-content-authoring should be the first concrete Tool-lane repo for authoring and operating on canonical content.
It is not the owner of the content schema. It is the owner of the workflows that humans and automation use to create, inspect, validate, migrate, package, and transform content that already conforms to aerobeat-content-core.
Day-one directory shape¶
aerobeat-tool-content-authoring/
├── interfaces/
│ ├── authoring_service.gd
│ ├── package_build_service.gd
│ └── import_export_service.gd
├── services/
│ ├── authoring/
│ │ ├── set_authoring_service.gd
│ │ ├── workout_authoring_service.gd
│ │ └── chart_authoring_service.gd
│ ├── validation/
│ │ ├── validate_package_service.gd
│ │ └── validate_chart_service.gd
│ ├── migration/
│ │ └── migrate_content_service.gd
│ ├── packaging/
│ │ └── build_content_package_service.gd
│ ├── importers/
│ │ ├── audio_metadata_import_service.gd
│ │ └── external_chart_import_service.gd
│ └── registry/
│ └── refresh_content_index_service.gd
├── cli/
│ ├── main.gd
│ ├── commands/
│ │ ├── validate_command.gd
│ │ ├── migrate_command.gd
│ │ ├── package_command.gd
│ │ ├── import_command.gd
│ │ └── inspect_command.gd
│ └── formatters/
│ ├── plain_text_output.gd
│ └── json_output.gd
├── editor/
│ ├── plugins/
│ │ └── content_authoring_plugin.gd
│ ├── docks/
│ ├── inspectors/
│ └── view_models/
├── mappers/
│ ├── content_error_mapper.gd
│ └── validation_report_mapper.gd
├── tests/
│ ├── test_validate_command.gd
│ ├── test_build_content_package_service.gd
│ └── test_editor_uses_shared_services.gd
├── plugin.cfg
├── LICENSE.md
├── README.md
└── addons.jsonc
This repo shape intentionally separates service logic from entrypoint surfaces.
services/is the canonical workflow layer.cli/is one thin headless surface over those services.editor/is an optional interactive surface over those same services.
Shared-service rule: one workflow layer, many entrypoints¶
This is the most important Tool-lane rule for this repo:
CLI/headless and editor/interactive workflows should call the same service layer.
That means:
cli/commands/validate_command.gdshould callservices/validation/validate_package_service.gd- an editor dock "Validate Package" action should call that same validation service
cli/commands/migrate_command.gdand any editor migration wizard should both callservices/migration/migrate_content_service.gd- package building from CI should call the same
services/packaging/build_content_package_service.gdused by any desktop packaging UI
The service layer should accept and return stable DTOs/contracts from aerobeat-content-core and aerobeat-tool-core, not editor widget state.
Day-one core files and what they mean¶
Interfaces¶
interfaces/authoring_service.gd- common service boundary for creating/updating canonical content records
interfaces/package_build_service.gd- package assembly interface used by both automation and UI
interfaces/import_export_service.gd- import/export contract for external format adapters
Services¶
services/authoring/set_authoring_service.gd- create/update set records from tool actions while preserving package-local composition rules
services/authoring/workout_authoring_service.gd- create/update workout records
services/authoring/chart_authoring_service.gd- create/update charts while preserving canonical ids/reference rules
services/validation/validate_package_service.gd- run shared structural validation and return normalized reports
services/validation/validate_chart_service.gd- focused validation path for a single chart/package slice
services/migration/migrate_content_service.gd- apply approved schema migrations and emit migration results/reports
services/packaging/build_content_package_service.gd- assemble canonical package outputs from authored records/resources
services/importers/audio_metadata_import_service.gd- import audio metadata into canonical
Songfields services/importers/external_chart_import_service.gd- translate external chart source formats into canonical content-core records
services/registry/refresh_content_index_service.gd- rebuild or refresh a local tool-side index/cache while respecting content-core registry semantics
CLI/headless surface¶
cli/main.gd- single command entrypoint for headless usage
cli/commands/validate_command.gd- validate package/path/id and emit text or JSON
cli/commands/migrate_command.gd- run migrations non-interactively
cli/commands/package_command.gd- build package artifacts in CI or local automation
cli/commands/import_command.gd- import approved external source material into canonical records
cli/commands/inspect_command.gd- inspect manifests/records/ids without GUI requirements
Optional editor surface¶
editor/plugins/content_authoring_plugin.gd- plugin bootstrap only
editor/docks/*- views for charts/sets/workouts/package inspection
editor/inspectors/*- record inspectors/editors
editor/view_models/*- UI-facing state that adapts service DTOs for presentation
Editor code should orchestrate services and present results. It should not become a second schema or validation engine.
Day-one ownership boundaries¶
aerobeat-tool-content-authoring should own:
- concrete authoring workflows
- CLI/headless command wiring
- optional editor UX
- import/export adapters
- package-building workflows
- local indexing/inspection helpers for tool usage
- mapping shared validation/migration results into user-facing diagnostics
aerobeat-tool-content-authoring should depend on:
aerobeat-content-corefor durable content contracts, ids, manifests, validators, and workout resolution interfacesaerobeat-tool-corefor tool-common DTOs, progress models, operation-state contracts, and shared tool-side interfaces- possibly concrete
aerobeat-feature-*repos later for mode-specific authoring helpers, but not on day one unless a real use case requires it
aerobeat-tool-content-authoring must not own:
- canonical definitions of
Song,Set,Chart, orWorkout - the shared chart envelope contract
- feature runtime visuals such as 2D lanes or 3D portals
- gameplay scoring/runtime execution logic
- backend moderation queue state unless that work is explicitly split into another tool repo or shared tool-core model
Day-one non-goals for aerobeat-tool-content-authoring¶
Explicit non-goals:
- no requirement for editor UX before the repo is useful
- no separate ingestion-only repo yet
- no hosted web service requirement
- no replacement of
aerobeat-tool-core - no feature/runtime rendering system
- no ownership transfer of schema definitions out of
aerobeat-content-core - no assumption that all future authoring needs belong in one forever-repo
The first cut should be headless-capable immediately and editor-capable optionally.
Recommended first command surface for the tool repo¶
To keep the headless requirement real, day one should include a minimal command surface such as:
validate <path-or-package-id>migrate <path> --target-schema <schema>package build <source> --output <dir>import audio-metadata <audio-file> --out <song-record>inspect manifest <path>inspect workout <workout-id-or-path>
The exact CLI syntax can vary, but these workflow categories should exist quickly so CI, automation, and non-GUI contributors can use the repo without waiting for editor UX.
Dependency and ownership summary¶
aerobeat-content-core¶
- Depends on: no other AeroBeat core repo by default
- Owned concerns: durable content contracts and shared structural rules
- Must not own: authoring UX, import pipelines, runtime visuals, scoring/runtime behavior
aerobeat-tool-content-authoring¶
- Depends on:
aerobeat-content-core,aerobeat-tool-core - Owned concerns: authoring, validation orchestration, migration workflows, packaging, import/export, inspection, CLI/headless surface, optional editor UX
- Must not own: canonical content schema, runtime presentation systems, feature scoring/runtime rules
Concrete split to preserve on day one¶
If a new file is being proposed, the routing rule should be:
- Put it in
aerobeat-content-corewhen it defines the durable meaning of content shared across runtime and tools. - Put it in
aerobeat-tool-content-authoringwhen it defines a workflow that creates, edits, validates, migrates, packages, imports, or inspects that content. - Put it in
aerobeat-feature-*when it is a runtime consumer or visualizer of content, including 2D lanes, 3D portals, spawn systems, scoring flow, or view realization.
That split is what keeps the first repos from collapsing back into a blob.
Repo-creation recommendation¶
The docs are now concrete enough to support this sequence:
- create/stand up
aerobeat-content-corewith the day-one contract shape above - land fixtures and contract tests there before building bigger tooling
- create
aerobeat-tool-content-authoringwith a shared service layer and a minimal CLI/headless surface - add optional editor UX only as a thin layer on top of those services
That is the smallest clean shape that matches the approved architecture and keeps ownership aligned with the six-core model.