Repository navigation
feat: eject backends, ecs adapters, and gui plugins to labelle-assembler - #150
Conversation
Stage 1 of #147. The raylib backend now lives in the labelle-assembler repo (see labelle-toolkit/labelle-assembler#5 / its feat/absorb-backends branch) and is populated into a new ~/.labelle/packages/assembler/{ver}/ cache slot via fetchAssemblerWithFallback, mirroring the existing CLI fetch path. ensureCache now populates both the cli and assembler cache slots; the assembler slot is keyed on cfg.assembler_version (falling back to labelle_version) so it can version independently once Phase 3 of RFC #122 is rolled out everywhere. The embedded generator/ module is kept in lockstep with labelle-assembler src/ — it's still compiled as a dep for types and GUI resolution even though the CLI spawns the external assembler binary for code generation. The raylib example's project.labelle gains an assembler_version local: override so dev-mode resolution finds raylib in the sibling labelle-assembler checkout. The remaining backends (bgfx, sdl, sokol, wgpu) still live here; the resolver falls back to the cli cache slot for them until their stages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stage 2 of #147. The sokol backend now lives in labelle-assembler (see its feat/absorb-backends branch). The Stage 1 plumbing handles resolution — no CLI code changes needed. Also updates the sibling-path references in gui/sokol-imgui/build.zig and gui/raylib-imgui/build.zig (missed in Stage 1) to point at labelle-assembler/backends/. These GUI plugins are not exercised by any current test and don't build standalone today (unrelated imgui-zig hash mismatch — a symptom of the coupling this refactor addresses), but the paths are updated for consistency with the new layout. examples/sokol/project.labelle gets the assembler_version local: override so dev-mode resolution finds sokol in the sibling repo. Three backends remain in this repo: bgfx, sdl, wgpu. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two fixes to unblock end-to-end verification of backends that still resolve from the CLI cache slot during the staged migration: 1. bgfx and wgpu examples had .engine_version = "local:../../../engine" which predates the engine repo rename. Point them at labelle-engine. 2. Both examples also declared plugin deps on labelle-pathfinding and labelle-physics that don't exist as sibling repos here — drop them. They weren't providing anything these examples actually use. Also adds .assembler_version = "local:.../labelle-assembler" to both so they participate in the new cache slot alongside raylib and sokol. Mirrors the silent assembler-slot probe from labelle-assembler (a2525a0) into generator/src/cache.zig to keep the two trees in lockstep. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stage 3 of #147. Pure file move — plumbing from Stage 1 handles resolution. Two backends remain: sdl and wgpu. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stage 4 of #147. Pure file move. One backend remains: wgpu. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stage 5 of #147 — the last backend. labelle-cli/backends/ is empty and the directory is removed from the filesystem. All five backends (raylib, sokol, bgfx, sdl, wgpu) now live in labelle-assembler/backends/. Next stage: drop the CLI-slot fallback in resolveBundledPackage and stop populating backends/ into the cli cache slot — they're now pure dead code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mirrors labelle-assembler 83ef543: resolveBundledPackage no longer probes the CLI cache slot for backends (all five now live in the assembler), and populateCliCache/fetchCliPackages drop the "backends" subdir entry. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stage 7 of #147. Moves ecs/ (zig-ecs, zflecs, mr-ecs) to labelle-assembler. Mirrors the resolver flip from resolveCliPackage to resolveBundledPackage in the embedded generator. Removes the "zig-ecs adapter tests" step from CI — it now runs in labelle-assembler's CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stage 8 of #147 — the final move. Ejects the five GUI plugins to labelle-assembler (see its feat/absorb-backends 530c2c4). With gui gone, the companion directory under labelle-cli is empty and the entire cli cache slot is dead. Removes from src/cli/cache.zig: - fetchCliWithFallback() — no more cli subdirs to populate - the ensureCache call that probed isCliCached Updates src/cli/install.zig: - `labelle install cli <ver>` becomes `labelle install assembler <ver>` - bulk install of framework packages now ensures the assembler slot Mirrors the corresponding deletions (resolveCliPackage, populateCliCache, fetchCliPackages, isCliCached, validateCache check) from labelle-assembler in the embedded generator and its root.zig exports. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR SummaryMedium Risk Overview CI is updated to treat Reviewed by Cursor Bugbot for commit 7a941c6. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Code Review
This pull request restructures the LaBelle engine by migrating backend, ECS, and GUI components from a CLI-bundled model to an assembler-based distribution system, resulting in the removal of legacy backend implementations and updates to project configuration schemas. The generator's cache resolution and CLI installation logic have been refactored to support this new model. Reviewer feedback highlights opportunities to increase robustness by validating version fallbacks and improving debuggability by logging warnings when expected subdirectories are missing during cache population or fetching.
| pub fn resolveBundledPackage(allocator: std.mem.Allocator, cli_version: []const u8, assembler_version: ?[]const u8, project_dir: ?[]const u8, subpath: []const u8) ![]const u8 { | ||
| const asm_ver = assembler_version orelse cli_version; | ||
| return resolveAssemblerPackage(allocator, asm_ver, project_dir, subpath); | ||
| } |
There was a problem hiding this comment.
The resolveBundledPackage function is designed to handle the migration from cli_version to assembler_version. However, the logic const asm_ver = assembler_version orelse cli_version; assumes that if assembler_version is null, cli_version is a valid fallback. This might be fragile if cli_version is not provided or is empty. Consider adding a validation check to ensure asm_ver is not empty before proceeding.
| const src_path = try std.fs.path.join(allocator, &.{ companion_dir, subdir }); | ||
| defer allocator.free(src_path); | ||
|
|
||
| if (!dirExists(src_path)) continue; |
There was a problem hiding this comment.
| const src = try std.fs.path.join(allocator, &.{ tmp_dir, subdir }); | ||
| defer allocator.free(src); | ||
|
|
||
| if (!dirExists(src)) continue; |
The docker-build and versions-integration jobs invoke the CLI end-to-end with init + generate. With backends/ecs/gui moved to labelle-assembler, the default assembler_version that `labelle init` writes (v0.2.0) points to a released binary that pre-dates this refactor and still looks for backends in labelle-cli — so the test project fails to generate with "template not found". Fix both jobs by checking out labelle-assembler as a sibling, building it in-place, pointing LABELLE_ASSEMBLER at the fresh binary, and passing --assembler-version="local:../../labelle-assembler" to labelle init so the generated project.labelle resolves backends against the sibling repo. The checkout is temporarily pinned to the paired feat/absorb-backends branch — revert to main once labelle-toolkit/labelle-assembler#7 merges. The three test project.labelle fixtures (plugin-manifest-test, gui-plugin-test, nuklear-plugin-test) also gain the assembler_version local: override so they resolve correctly in monorepo dev. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Implements CLI-side of the #147 refactor by ejecting runtime content (backends/ECS adapters/GUI plugins) from this repo into labelle-assembler, leaving this repository focused on CLI tooling + the embedded generator/types.
Changes:
- Switch cache/install flows from
cli-bundled runtime packages toassembler-bundled runtime packages (with local-sibling fallback tolabelle-assembler). - Update embedded generator resolution to use the assembler cache slot (
packages/assembler/...) for backends/ECS/gui. - Update examples to pin
assembler_version(and fix some local engine path references), and trim CI steps that now live in the assembler repo.
Reviewed changes
Copilot reviewed 93 out of 96 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/cli/install.zig | Renames install target from cli to assembler and updates caching messages/commands accordingly. |
| src/cli/cache.zig | Ensures cache population uses assembler runtime package slot and looks for a labelle-assembler sibling repo. |
| generator/src/root.zig | Updates backend template resolution to use bundled package resolution (assembler slot). |
| generator/src/deps_linker.zig | Resolves backend/ECS dependency link targets from the assembler cache slot. |
| generator/src/cache.zig | Introduces assembler cache slot resolution/checking/population and remote fetch from labelle-assembler. |
| generator/src/build_files.zig | Updates ZON path fallback generation to resolve backends/ECS from the assembler cache slot. |
| examples/wgpu/project.labelle | Pins .assembler_version and updates local engine_version to labelle-engine; removes unused plugin deps. |
| examples/sokol/project.labelle | Pins .assembler_version for sibling dev resolution. |
| examples/raylib/project.labelle | Pins .assembler_version for sibling dev resolution. |
| examples/bgfx/project.labelle | Pins .assembler_version and updates local engine_version to labelle-engine; removes unused plugin deps. |
| .github/workflows/ci.yml | Removes zig-ecs adapter test step (moved to assembler CI). |
| gui/sokol-imgui/src/adapter.zig | Removed (migrated to labelle-assembler). |
| gui/sokol-imgui/build.zig.zon | Removed (migrated to labelle-assembler). |
| gui/sokol-imgui/build.zig | Removed (migrated to labelle-assembler). |
| gui/simple-sokol/src/adapter.zig | Removed (migrated to labelle-assembler). |
| gui/simple-sokol/build.zig.zon | Removed (migrated to labelle-assembler). |
| gui/simple-sokol/build.zig | Removed (migrated to labelle-assembler). |
| gui/simple-raylib/src/adapter.zig | Removed (migrated to labelle-assembler). |
| gui/simple-raylib/build.zig.zon | Removed (migrated to labelle-assembler). |
| gui/simple-raylib/build.zig | Removed (migrated to labelle-assembler). |
| gui/raylib-imgui/src/adapter.zig | Removed (migrated to labelle-assembler). |
| gui/raylib-imgui/build.zig.zon | Removed (migrated to labelle-assembler). |
| gui/raylib-imgui/build.zig | Removed (migrated to labelle-assembler). |
| gui/clay/src/adapter.zig | Removed (migrated to labelle-assembler). |
| gui/clay/build.zig.zon | Removed (migrated to labelle-assembler). |
| gui/clay/build.zig | Removed (migrated to labelle-assembler). |
| ecs/zig-ecs/test/adapter_test.zig | Removed (migrated to labelle-assembler). |
| ecs/zig-ecs/src/adapter.zig | Removed (migrated to labelle-assembler). |
| ecs/zig-ecs/build.zig.zon | Removed (migrated to labelle-assembler). |
| ecs/zig-ecs/build.zig | Removed (migrated to labelle-assembler). |
| ecs/zflecs/src/adapter.zig | Removed (migrated to labelle-assembler). |
| ecs/zflecs/build.zig.zon | Removed (migrated to labelle-assembler). |
| ecs/zflecs/build.zig | Removed (migrated to labelle-assembler). |
| ecs/mr-ecs/src/adapter.zig | Removed (migrated to labelle-assembler). |
| ecs/mr-ecs/build.zig.zon | Removed (migrated to labelle-assembler). |
| ecs/mr-ecs/build.zig | Removed (migrated to labelle-assembler). |
| backends/wgpu/templates/desktop.txt | Removed (migrated to labelle-assembler). |
| backends/wgpu/src/window.zig | Removed (migrated to labelle-assembler). |
| backends/wgpu/src/input.zig | Removed (migrated to labelle-assembler). |
| backends/wgpu/src/audio.zig | Removed (migrated to labelle-assembler). |
| backends/wgpu/example/main.zig | Removed (migrated to labelle-assembler). |
| backends/wgpu/example/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/wgpu/example/build.zig | Removed (migrated to labelle-assembler). |
| backends/wgpu/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/wgpu/build.zig | Removed (migrated to labelle-assembler). |
| backends/sokol/templates/mobile.txt | Removed (migrated to labelle-assembler). |
| backends/sokol/templates/desktop.txt | Removed (migrated to labelle-assembler). |
| backends/sokol/src/window.zig | Removed (migrated to labelle-assembler). |
| backends/sokol/src/stb_image_impl.c | Removed (migrated to labelle-assembler). |
| backends/sokol/src/input.zig | Removed (migrated to labelle-assembler). |
| backends/sokol/src/audio.zig | Removed (migrated to labelle-assembler). |
| backends/sokol/example/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/sokol/example/build.zig | Removed (migrated to labelle-assembler). |
| backends/sokol/example/assets/characters_frames.zon | Removed (migrated to labelle-assembler). |
| backends/sokol/example/assets/characters_animations.zon | Removed (migrated to labelle-assembler). |
| backends/sokol/example/assets/characters.bmp | Removed (migrated to labelle-assembler). |
| backends/sokol/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/sokol/build.zig | Removed (migrated to labelle-assembler). |
| backends/sdl/templates/desktop.txt | Removed (migrated to labelle-assembler). |
| backends/sdl/src/window.zig | Removed (migrated to labelle-assembler). |
| backends/sdl/src/sdl.zig | Removed (migrated to labelle-assembler). |
| backends/sdl/src/input.zig | Removed (migrated to labelle-assembler). |
| backends/sdl/src/audio.zig | Removed (migrated to labelle-assembler). |
| backends/sdl/example/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/sdl/example/build.zig | Removed (migrated to labelle-assembler). |
| backends/sdl/example/assets/characters.bmp | Removed (migrated to labelle-assembler). |
| backends/sdl/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/sdl/build.zig | Removed (migrated to labelle-assembler). |
| backends/raylib/templates/wasm.txt | Removed (migrated to labelle-assembler). |
| backends/raylib/templates/desktop.txt | Removed (migrated to labelle-assembler). |
| backends/raylib/src/window.zig | Removed (migrated to labelle-assembler). |
| backends/raylib/src/input.zig | Removed (migrated to labelle-assembler). |
| backends/raylib/src/gfx.zig | Removed (migrated to labelle-assembler). |
| backends/raylib/src/audio.zig | Removed (migrated to labelle-assembler). |
| backends/raylib/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/raylib/build.zig | Removed (migrated to labelle-assembler). |
| backends/bgfx/templates/desktop.txt | Removed (migrated to labelle-assembler). |
| backends/bgfx/src/window.zig | Removed (migrated to labelle-assembler). |
| backends/bgfx/src/input.zig | Removed (migrated to labelle-assembler). |
| backends/bgfx/src/audio.zig | Removed (migrated to labelle-assembler). |
| backends/bgfx/example/main.zig | Removed (migrated to labelle-assembler). |
| backends/bgfx/example/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/bgfx/example/build.zig | Removed (migrated to labelle-assembler). |
| backends/bgfx/build.zig.zon | Removed (migrated to labelle-assembler). |
| backends/bgfx/build.zig | Removed (migrated to labelle-assembler). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Assembler-bundled packages (backends, ecs, gui) | ||
| if (!try isAssemblerCached(allocator, cfg.labelle_version)) { | ||
| try missing.append(allocator, try std.fmt.allocPrint(allocator, "assembler {s}", .{cfg.labelle_version})); | ||
| } |
There was a problem hiding this comment.
validateCache checks the assembler cache using cfg.labelle_version, but the assembler packages are keyed by cfg.assembler_version (with cfg.labelle_version only as a fallback when assembler_version is unset). This will report missing packages / trigger unnecessary fetches when assembler_version differs from labelle_version. Use the same version selection logic as resolveBundledPackage (e.g., asm_ver = cfg.assembler_version orelse cfg.labelle_version) for both the cache check and the missing-string message.
| // Resolve backend path — prefer assembler cache (migrating), fall back to CLI cache | ||
| var backend_subpath_buf: [128]u8 = undefined; | ||
| const backend_subpath = std.fmt.bufPrint(&backend_subpath_buf, "backends/{s}", .{backend_name}) catch unreachable; | ||
| const backend_path = try cache.resolveCliPackage(allocator, cfg.labelle_version, game_dir, backend_subpath); | ||
| const backend_path = try cache.resolveBundledPackage(allocator, cfg.labelle_version, cfg.assembler_version, game_dir, backend_subpath); |
There was a problem hiding this comment.
The comment says this resolves from the assembler cache and then falls back to the CLI cache, but the code only calls resolveBundledPackage -> resolveAssemblerPackage (no CLI cache fallback path exists here). Either implement the stated fallback (if still needed during migration) or update the comment so it matches the actual behavior.
Mirrors labelle-assembler aa69c1b. Addresses PR #150 review feedback from Cursor Bugbot (high severity) and Copilot. validateCache in the embedded generator was keying the assembler-slot check on cfg.labelle_version, but the live ensureCache in src/cli/cache.zig uses cfg.assembler_version orelse cfg.labelle_version. When the two differ, validateCache would report the wrong package as missing. Match ensureCache's selection. Also drops a stale comment in loadBackendTemplate that still described the removed "prefer assembler, fall back to CLI" fallback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e966b41. Configure here.
0.3.0 is the first assembler release to bundle backends, ecs adapters, and gui plugins (see labelle-toolkit/labelle-assembler#7). New projects created via \`labelle init\` after this commit will pin to 0.3.0 and auto-download the right binary on first generate. Safe for CI on this branch because both docker-build and versions-integration jobs pass \`--assembler-version="local:..."\` to \`labelle init\`, which overrides the default. Follow-up after labelle-assembler#7 merges: - Cut labelle-assembler v0.3.0 release on GitHub - Revert the CI assembler checkout pin from feat/absorb-backends to main (commit 3f5bc3c) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
labelle-toolkit/labelle-assembler#7 is merged and v0.4.0 is tagged with the absorbed runtime content (backends, ecs, gui). This commit: 1. Drops the temporary feat/absorb-backends pin on the assembler checkout in ci.yml — CI now resolves against the default branch (main), which has the merged content. 2. Updates DEFAULT_ASSEMBLER_VERSION from 0.3.0 to 0.4.0. The 0.3.0 bump in commit 6526383 was wrong: v0.3.0 already existed before this refactor (the "animations directory scanning" release) and does not contain the absorbed packages. v0.4.0 is the first release that does. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Summary
Implements the CLI side of #147. Moves all runtime content (5 backends, 3 ECS adapters, 5 GUI plugins) out of this repo into labelle-assembler. After this change, labelle-cli is pure tooling: the
labellebinary, the embedded generator (still compiled for ProjectConfig types + GUI resolution), debug plugin, examples, and docs.Paired with labelle-toolkit/labelle-assembler#7 which absorbs the same content.
Why
Fixes the problems laid out in #147:
assembler_versioninproject.labelle, which is decoupledlocal:../labelle-clireferences drag in backend source — fixes the sokol-zig hash fragility (chore: pin sokol-zig dependency to a specific commit instead of master #146) that triggered this refactorDirectory changes
Deleted from this repo:
backends/(raylib, sokol, bgfx, sdl, wgpu)ecs/(zig-ecs, zflecs, mr-ecs)gui/(clay, raylib-imgui, simple-raylib, simple-sokol, sokol-imgui)Code changes
src/cli/cache.zig: removedfetchCliWithFallbackand theensureCacheprobe ofisCliCached. The CLI now only populates the assembler cache slot from the siblinglabelle-assemblerrepo.src/cli/install.zig:labelle install cli <ver>renamed tolabelle install assembler <ver>.generator/src/: mirrored every change tolabelle-assembler/src/(this tree is still compiled for types + GUI resolution).examples/raylib/project.labelleandexamples/sokol/project.labelle: added.assembler_version = "local:../../../labelle-assembler"so dev-mode resolution finds backends in the sibling repo.examples/bgfx/project.labelleandexamples/wgpu/project.labelle: drive-by fixes — pointed staleenginereferences atlabelle-engine, dropped dead plugin deps, addedassembler_version..github/workflows/ci.yml: removed thezig-ecs adapter testsstep (it runs in labelle-assembler's CI now).Commits (staged for review)
feat: eject raylib backend— Stage 1feat: eject sokol backend— Stage 2 (+ drive-by fix to gui/{raylib,sokol}-imgui backend paths)fix: bgfx/wgpu examples reference correct sibling repos— unblocks end-to-end regression testsfeat: eject bgfx backend— Stage 3feat: eject sdl backend— Stage 4feat: eject wgpu backend— Stage 5 (last backend)refactor: drop dead backend fallback in embedded generator— Stage 6 cleanupfeat: eject ecs adapters— Stage 7feat: eject gui plugins + drop dead cli cache machinery— Stage 8 (final)Test plan
zig build testpassesLABELLE_ASSEMBLERpointing at the paired branch's binarylabelle-assembler/backends/...andlabelle-assembler/ecs/...Ordering
Merge order matters. labelle-toolkit/labelle-assembler#7 should land first. Before the assembler PR is merged and a new
DEFAULT_ASSEMBLER_VERSIONis cut, users on main who generate with the default (non-local) assembler will still see the old layout and this PR's CLI will fail to find migrated content.For dev work (monorepo sibling layout with
local:paths) the two branches can be reviewed and tested together without special ordering.Closes #147.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com