Repository navigation
RFC: full agnostic CLI core — iOS to labelle-ios, backend identity, target names, SDL (RFC #406 final phase) #471
Description
Status: draft, awaiting the owner's decisions (§6). This is the final phase of RFC #406: a CLI core with no platform, store or backend knowledge. It makes RFC #466 §9 concrete.
Owner decisions already taken (2026-09-27):
- iOS is extracted into a new provider, labelle-ios, the way Android went to labelle-android.
- This phase starts in parallel with the web phase (RFC: web/wasm leaves the CLI core (RFC #406, web phase) #466). Items marked NOW touch no file that A2 (feat: browser-watch supervision for labelle run --watch (RFC #466 PR A2) #470) or B edit.
The research is read-only, against origin/main:
| Repo | Commit |
|---|---|
| cli | e2e0e85 (A1 merged) |
| assembler | b239c9d |
| sokol | c704505 |
| bgfx | 11a6865 |
| sdl | 8bb6ddd |
| android | e14fa5b |
| FP | f1eea93 |
A2 is the open PR cli#470.
0. Findings that shape the plan
- iOS already depends on a provider, and none exists.
labelle ios …and--platform=iosboth go through target resolution, which refuses a target with no pinned owner (pipeline/args_resolve.zig:28-40,provider_targets.zig:53-83).- The registry has owners only for
androidandwasm. - So today iOS works only with a hand-made provider that owns
ios. There are no iOS users to break. - A provider's
replace runalready takes precedence over the core iOS branch (pipeline/run.zig:188-192runs before the.iosbranch at:327). - So labelle-ios can be built and used against today's CLI main (contract 1.3) with no CLI change.
- Only sokol builds iOS.
- sokol declares
.capabilities .ios,.platforms.iosand.frameworks.ios(backend.manifest.v2.zon:29-38,95,118-127). Its hook finds the SDK withxcrunand reads-Ddevice. - bgfx, raylib, sdl and wgpu declare no iOS.
- No repo has iOS CI, so the path has never run end to end on this toolchain line. The first iOS task is a spike, not a port.
- The legacy code also assumes
zig-out/bin/game(ios.zig:15), but the assembler names the exe after the project (assembler#362).
- sokol declares
- The assembler has already opened backend resolution.
.backend_packageaccepts any package (config.zig:1216-1228), and third-party backends go through the manifest (isEnumTagBacked,:1640-1660).- The enum is only a shorthand for first-party packages (
builtinProvider,:1430-1510), withdefault_backend = .bgfx(:1533). - What's missing is a way for the CLI to ask the assembler what a project resolves to.
- Latent bug that shows why that query is needed.
- The CLI names the target dir
@tagName(parsed.backend)_<target>(pipeline.zig:162). - The assembler uses
backendName()_<platform>(main.zig:270,root.zig:427), which is the package name. - A third-party
.backend_package = .{ .name = "acme" }project with no.backendgets.labelle/bgfx_desktopfrom the CLI and.labelle/acme_desktopfrom the assembler.
- The CLI names the target dir
- The assembler already validates backend × target: it derives
.wasm/.android/.iosrequirements from the platform (capabilities.zig:69-77) and checks them against the manifest (root/provider_contracts.zig). This is RFC: web/wasm leaves the CLI core (RFC #406, web phase) #466's D13 verification. The CLI needs no table. - Platform names are deep in the assembler; the CLI needs them only through the shared schema.
- The assembler has a
Platformenum (config.zig:72),Capability.{wasm,android,ios},AssetCompression{desktop,android,ios,web}, andIosConfig(parsed, but never read by codegen). - It also has about 40
cfg.platformbranches in codegen and the manifest splices. - The CLI can go agnostic without rewriting the assembler's codegen. Making the codegen target-generic is a separate assembler RFC (D8).
- The assembler has a
- The SDL move has a discovery gap.
- Hooks come only from
.plugins(provider_dispatch.zig:150). The resolved backend package isn't discovered as a provider. - SDL2 is needed by the sdl backend and by the gamepad source that raylib, sokol and bgfx use.
- bgfx, raylib and sokol read
LABELLE_SDL2_LIB. labelle-sdl doesn't (it uses Homebrew or-Dsdl-prefix) and has no Windows CI. - FP sets
.gamepad = .none, so the SDL work cannot break FP.
- Hooks come only from
- Two allowlist entries are free.
stb_image_impl.cis flagged only by a comment naming bgfx, andstb_image.hby one upstream comment. Many other entries are test fixtures or comments only (§1e). - Allowlist count: 50 on main. feat: browser-watch supervision for labelle run --watch (RFC #466 PR A2) #470 (A2) brings it to 44. RFC: web/wasm leaves the CLI core (RFC #406, web phase) #466 §9 expects 32 after B.
1. Inventory (cli e2e0e85 unless noted)
1a. iOS
| Site | What | Fate |
|---|---|---|
src/cli/ios.zig (915 lines) |
handleIos build/xcode/run; simulator deploy (xcrun simctl list/boot/install/launch); Info.plist; LaunchScreen; pbxproj with DEVELOPMENT_TEAM; NEON simulator hint; -Ddevice/ReleaseFast build |
→ labelle-ios |
cli.zig:48,329-341,550-595 |
ios command parsing and help |
Delete |
args.zig:17 |
Command.ios_cmd |
Delete |
pipeline.zig:35,360-363 |
Legacy own-build branch | Delete |
pipeline/args_resolve.zig:100-104 |
labelle ios forces parsed.backend = .sokol |
Delete; no silent substitution (D5) |
pipeline/install.zig:283-303 |
#467 ios refusals (tests :319-346) |
Delete with the command |
pipeline/install.zig:349-386 |
legacyRunBranch(.wasm,.ios) |
Delete; noRunReplacement loses its legacy argument |
pipeline/run.zig:13,327-334,533-561 |
Simulator deploy branch; crossTargetLaunchSkipped |
Delete |
provider_dispatch.zig:22-27 |
"ios" reserved namespace |
Unreserve |
provider_hooks.zig:476 |
.launched_detached comment (mentions simctl) |
Scrub |
project_config.zig:108-133,440 |
Orientation, IosConfig, ios field |
→ providers/ios.json |
generate.zig, assembler_proc.zig, bundle.zig |
Comments, ASTC prepass for the forced backend | Scrub |
| Tests | provider_hooks_e2e.py:918-932, provider_targets_e2e.py:171-194 |
Rewrite: unknown command |
| Docs | docs/rfc-ios-platform.md |
→ labelle-ios |
| Assembler (stays for now) | build_zig.zig iOS header/SDK, manifest_v2_splice/ios.zig, Capability.ios, IosConfig |
.ios block "moved" hint (I4) |
docker.zig:57-70,227-313 |
xcode-frameworks for --docker --target=*-macos |
X3 |
1b. Backend identity (cli#432)
| Site | Hardcodes |
|---|---|
project_config.zig:32,36,81,356,382 |
Backend enum, default_backend = .bgfx, BGFX_VERSION (versions.zon .bgfx), backend_package |
compatibility.zig:10-13 |
wasm whitelist (B deletes it) |
pipeline.zig:162,261-262; pipeline/run.zig:72,269 |
Target dir and log from @tagName(backend) |
pipeline/generate.zig:108-113,149-156; assembler_proc.zig:191-263 |
--backend <tag> forwarded to astc and the assembler |
astc/cmd.zig:150,176-178; astc/capabilities.zig:78-100 |
Enum parse; texture_caps read only from an explicit backend_package (the shorthand gets conservative defaults) |
pipeline/install.zig:94-95; doctor.zig:183-200,243-258,352-370 |
Which backends want SDL2; backend label |
upgrade.zig:120-166,252-266,332+; update_check.zig:42-45 |
bgfx↔gfx pairing and pin rewrite |
| Fixtures only | pack.zig, progress.zig, status.zig, linux_desktop.zig, screenshot_format.zig, pipeline/screenshot.zig |
The assembler stays the registry of first-party backends: the Backend enum, builtinProvider, effectiveGamepad, parseBackend.
1c. Platform enum and shared schema
- CLI:
project_config.zig:37-66(Platform,AssetCompression.formatFor);provider_targets.zig:26-56(legacy: ?Platform);- the chore: pin labelle-assembler 0.105.0 #378 gate at
pipeline/install.zig:207-217; - the ASTC prepass;
parsed.platformchecks inpipeline.zig,build.zig,install.zig,run.ziganddocker.zig.
- Assembler:
ProjectConfig.platform,.asset_compression,.ios,.android(codegen keys), and--platformparsed into the enum. - FP uses:
.backend = .bgfx;.backend_packagebgfx 0.30.0;.gamepad = .none;.asset_compression = .{ .android = .astc, .web = .astc };.assembler_version;- an
.androidblock.
1d. SDL, docker, stb and help
sdl_provision.zig(329 lines): MinGW SDL2 2.30.11 download into~/.labelle/sdl2,autoWireEnv,stageSdl2DllBesideExe,sdl2LibDir.- Callers:
pipeline/install.zig:80-98(wants_sdl2);pipeline/build.zig:104-117(DLL staging from the mergedcompile_env);doctor.zig(--fix, lib/dll/headers/mixer);cli.zig:63.
config.zig:264-267:LABELLE_SDL2_LIBis deliberately unreserved (A1).- Also:
docker.zig(only the macOSxcode-frameworkssnippet after B);stb_image.*(finding 8); help text (help.zig:35,:117-118); comments inastc/cmd.zigand theOs.Taglist at:605.
1e. Allowlist after B (32 per #466 §9, to be recounted) and which PR removes each
| Entry | Reason left | Removed by |
|---|---|---|
agnostic_guard_test.zig |
Spells the forbidden table | Permanent |
astc/cmd.zig, cli/bundle.zig, cli/linux_desktop.zig, cli/pack.zig, cli/progress.zig, cli/status.zig, cli/screenshot_format.zig, cli/pipeline/screenshot.zig, cli/update_check.zig, cli/stb_image_impl.c |
Fixtures and comments | X1 (NOW) |
cli/stb_image.h |
Upstream comment | X2 (NOW) |
cli/ios.zig, cli/pipeline/args_resolve.zig, cli/provider_dispatch.zig, cli/args.zig, cli/pipeline/run.zig |
iOS and comments | I5 |
cli/docker.zig |
xcode-frameworks | X3 |
cli/compatibility.zig |
Android comment | X4 |
cli/sdl_provision.zig, cli/pipeline/build.zig, cli/pipeline/install.zig, cli/runner.zig, cli.zig, cli/help.zig |
SDL | S4 |
cli/assembler_proc.zig, cli/config.zig, cli/doctor.zig, cli/pipeline.zig, cli/pipeline/generate.zig, cli/project_config.zig, cli/upgrade.zig |
Backend and Platform enums | D4 / P3 |
2. Target architecture
labelle build --platform=ios -> core resolve (ios owner = labelle-ios)
-> assembler describe --target ios (backend pkg, target dir, asset format; refuses unsupported pairs)
-> [before build ios/device: env_file build_options {device=true}] (v0.2)
-> core zig build (sokol hook resolves the SDK via xcrun)
-> after build ios/app: <target_dir>/zig-out/ios/<Name>.app (Info.plist, LaunchScreen, icon, signing)
labelle run --platform=ios -> ... -> replace run ios/launch: simctl boot|install|launch --console-pty (or devicectl)
labelle bundle --platform=ios -> ... -> replace bundle ios/bundle: .app/.ipa
labelle ios doctor|devices|xcode|run (namespace unreserved in 4.0)
labelle build (desktop, gamepad, Windows) -> before generate sdl2/env: LABELLE_SDL2_LIB (cache_dir) -> after build sdl2/stage: SDL2.dll
Core keeps (generic):
- the
desktopcore target and host launch; - target resolution from strings;
- hook orchestration, the contract,
env_fileandcache_dir; - ASTC and bake;
- the macOS desktop bundler;
labelle-assembler describeas the single source of backend and target facts;install python;- the watch supervisor (A2).
Moves out:
- iOS → labelle-ios;
- SDL2 provisioning, doctor rows and DLL staging → an SDL provider (D2);
- backend identity, shorthand, bgfx↔gfx pairing and target validity → assembler;
IosConfig→providers/ios.json.
Deleted:
labelle ios;- the
Backend,PlatformandAssetCompressionmirrors; versions.zon .bgfx;doctor --fixSDL provisioning;--dockermacOS cross (D6);- the
labelle astc --backendenum (becomes--target).
3. Contract and schema changes
| Change | Where | Kind |
|---|---|---|
describe --project-root P --target T [--json]: {target_dir, backend:{name,id,repo,version,local_path}, asset_format, supported, reason?}. Offline and config-only; package_dir after install. Protocol 6 → 7 |
assembler main.zig + new describe.zig |
Additive |
generate --target <string> alias for --platform; an unknown name exits 2 with a clear message |
assembler | Additive |
upgrade backend [ver]: bumps .backend_package.version, with gfx pairing through version_floors |
assembler | Additive |
.asset_compression takes any identifier key; web is a warned alias for wasm; unknown keys ignored per target |
assembler | Additive |
.platform in project.labelle deprecated (the CLI always passes --target) |
assembler | Additive |
.ios block → "moved to providers/ios.json" pre-pass (the android_moved_keys.zig pattern) |
assembler | Breaking for .ios users, behind the pinned assembler_version |
Contract 1.4: env_file gains optional build_options: [{name,value}]. Owner-only, on before generate/before build only; appended as -Dname=value to the fingerprint pass and the compile; same conflict rules as #466 §3.2. For iOS -Ddevice (D3) |
cli | Additive, wire-gated |
doctor --fix forwarded to provider doctor commands |
cli | Additive |
Registry records for ios → labelle-ios, and for the SDL provider |
registry | Data |
The assembler's internal Platform, Capability.{wasm,android,ios} and the manifest .platforms stay; making them string-keyed is AS5, a separate assembler RFC (D8).
4. PR sequence
NOW means it can start immediately and touches no file that A2 (#470) or B edits. after X names the dependency.
Track X (CLI scrubs)
| # | Repo | Change | Guard | When |
|---|---|---|---|---|
| X1 | cli | Neutral fixture names (fixture_desktop, .backend = .null); comment scrubs; Os.Tag list without the Apple mobile tags; iconutil hint reworded |
−10 | NOW (only allowlist lines conflict, a trivial rebase) |
| X2 | cli | Move stb_image* to vendor/stb/ with unmodified bytes; include path; guard doc: "vendored third-party code lives outside src/" |
−1 | NOW; Windows CI must build it |
| X3 | cli | Refuse --docker --target=*-macos; delete setup_xcode_frameworks (D6) |
−1 | after B |
| X4 | cli | Help and compat text: --platform=<target> + labelle targets |
−1 | after B |
Track I (iOS)
| # | Repo | Change | When |
|---|---|---|---|
| I0 | labelle-sokol | CI: a macOS job building the example for aarch64-ios-simulator plus a compile-only -Ddevice=true build |
NOW |
| I1 | labelle-ios (new) | v0.1.0 (details below) | NOW, against CLI main (1.3) |
| I2 | registry | labelle-ios 0.1.0 record (targets: ["ios"], no namespace) |
after I1 |
| I3 | cli | Refuse labelle ios when the ios owner declares any build, run or bundle hook (the #468 bypass) |
after A2 |
| I4 | assembler | .ios "moved" hint |
after I1 fixes the settings schema |
| I5 | cli | Remove iOS from the core. Guard −5 | after B; CLI 4.0 |
| I6 | labelle-ios | v0.2.0: contract >=1.4.0 <1.5.0; ios namespace commands |
after CLI 3.1 (devices) and I5 (namespace) |
I1, labelle-ios v0.1.0:
- Manifest:
.name="ios", contract>=1.3.0 <1.4.0,.targets={"ios"}, no namespace yet (iosis reserved until I5). - Hooks:
app(after build): finds the single exe intarget_dir/zig-out/binand writeszig-out/ios/<Name>.app(Info.plist, LaunchScreen, AppIcon);launch(replace run):xcrun simctllist/boot/install/launch --console-pty, blocking so after-run semantics hold;run.args --device=<udid>;bundle(replace bundle): zips the simulator.app.
- Settings v1:
{schema_version:1, app_name, bundle_id, team_id, minimum_ios:"15.0", orientation, device_family:"1,2", simulator:{device:null}, destination:"simulator"}. - Tests:
- host unit tests;
- a fake-
xcrune2e on ubuntu, macOS and Windows; - a real-simulator job on
macos-latest: clean HOME, a sokol fixture pinnedlocal:, thenlabelle build/run --platform=ios --timeout, asserting a log line and a non-blanksimctl io screenshot.
- The first commit is the spike: does sokol iOS still build on Zig 0.16 with assembler 0.117?
I5, remove iOS from the core:
- Delete:
ios.zig,ios_cmd, the legacy branch, the forced sokol, the iosBypassarms,legacyRunBranch, the simulator branch,crossTargetLaunchSkippedplatforms,IosConfig/Orientation, and"ios"inreserved. - Tests:
labelle iosgives the unknown-command diagnostic with nothing generated;run --platform=ioswithout a replacement givesNoRunReplacement.
I6, labelle-ios v0.2.0:
- Commands:
doctor(Xcode, license, runtimes, backend capability),devices,xcode(pbxproj port) andrun. - Device builds: the 1.4
build_options {device:true}from abefore buildhook whendestination="device". - Signing: settings
signing.{identity,profile}, thencodesignplusxcrun devicectl;bundleproduces an.ipa.
Track D (backend identity) and track P (platform enum)
| # | Repo | Change | When |
|---|---|---|---|
| D1 | assembler | describe (protocol 7) and generate --target; tests for shorthand, explicit package, third-party package (finding 4), unsupported pair and offline |
NOW |
| D2 | assembler | upgrade backend with floors |
NOW |
| P1 | assembler | .asset_compression map with the web alias; .platform deprecation. FP's file keeps parsing |
NOW |
| R-A | assembler | Release (e.g. 0.118.0) | after D1, D2, P1 |
| D3a | cli | labelle astc resolves the backend package through describe (fixes texture caps for the shorthand) |
after A2 and R-A |
| D3 | cli 3.1 | Use describe when protocol ≥7: target dir (fixes finding 4), backend label, asset format, #378 gate → supported. Fall back to the enums otherwise. Plus contract 1.4 and doctor --fix forwarding |
after B |
| F | FP | Bump .assembler_version to R-A (optionally rename .web → .wasm); CI green on 3.1 |
after D3; before 4.0 is published |
| D4 | cli 4.0 | Delete Backend, default_backend, BGFX_VERSION, versions.zon .bgfx; stop forwarding --backend; upgrade all delegates to assembler upgrade backend; minimum protocol / default assembler ≥ R-A. Guard −4 |
after D3, F |
| P3 | cli 4.0 | Delete Platform, AssetCompression, target.legacy; remove the fallback. Guard −3 |
after D4, I5, S4 |
| AS5 | assembler | Separate RFC: string-keyed manifest targets | Independent |
Track S (SDL)
| # | Repo | Change | When |
|---|---|---|---|
| S0 | labelle-sdl | build.zig honours LABELLE_SDL2_LIB like bgfx, raylib and sokol; add a windows-latest CI job |
NOW |
| S1 | SDL provider (D2) | Port sdl_provision.zig (details below) |
NOW, against CLI main (1.3) |
| S2 | bgfx, raylib, sokol | When SDL2 is missing, fail with one line: "SDL2 not found: add the sdl2 provider, set LABELLE_SDL2_LIB, or .gamepad = .none" |
NOW |
| S3 | registry | SDL provider record | after S1 |
| S4 | cli 4.0 | Delete sdl_provision.zig, wants_sdl2, DLL staging, the doctor SDL rows, the LABELLE_SDL2_LIB unreserved entry and the SDL wording. Guard −6 |
after B and S3 |
S1, the SDL provider:
- Manifest:
.name="sdl2", namespacesdl2, contract>=1.3.0 <1.4.0, no targets. - Hooks:
env(before generate,desktop): when the project needs SDL2 on a Windows host, provision intocache_dir(lock plus atomic rename) and writeLABELLE_SDL2_LIB;stage(after build): copies SDL2.dll next to the exe.
- Commands:
doctor(lib, dll, headers, mixer;--fix) andinstall. - Tests: a clean-HOME
windows-latestgamepad build asserting the DLL sits beside the exe.
Final allowlist
agnostic_guard_test.zig only. Vendored stb lives outside src/.
5. Versioning and release train (recommended)
- CLI 2.1.0 (A1 + A2) and 3.0.0 (B): unchanged. Keep 3.0 frozen (D1).
- In parallel now:
- X1 and X2 (CLI patches);
- I0, I1 and I2 (labelle-ios 0.1.0 works on 2.1/3.0);
- S0 to S3;
- D1, D2 and P1, then assembler R-A;
- I3 right after A2.
- CLI 3.1.0 (additive): D3, D3a, contract 1.4, doctor
--fixforwarding, and deprecation lines forlabelle iosand core SDL provisioning. Then labelle-ios 0.2 and the registry record. - FP F, committed and green on 3.1 with the R-A pin.
- CLI 4.0.0 (breaking, "full agnostic"): I5, S4, D4, P3, X3, X4, plus
docs/migrating-to-4.0.md.
Why 4.0 rather than folding into 3.0: 3.0 is already gated on web 0.3 and FP, and mixing in the assembler floor and iOS would widen FP's breakage window.
6. Decisions for the owner (recommendation in bold)
| # | Decision | Recommendation |
|---|---|---|
| D1 | When iOS leaves the core | 4.0. Fold it into 3.0 only if labelle-ios 0.1 is validated before the 3.0 tag |
| D2 | How SDL is delivered | An explicit opt-in sdl2 provider in .plugins, hosted in labelle-sdl if the assembler accepts a provider-only plugin (spike), otherwise a new repo. The alternative, discovering backend packages as providers, is zero-config but forces provider pins on every bgfx project |
| D3 | iOS device builds | Contract 1.4 build_options via env_file (owner-only), not a full replace build |
| D4 | The .backend = .bgfx literal |
Keep it as assembler shorthand (no break; the CLI stops reading it) |
| D5 | Losing labelle ios' forced sokol |
No substitution; the assembler error names the backend and target. Optionally an assembler per-target backend map (.target_backends = .{ .ios = .sokol }) |
| D6 | --docker macOS cross |
Refuse it (desktop Linux and Windows cross stays) |
| D7 | stb | Move to vendor/, not a hash exemption |
| D8 | Assembler internal Platform/Capability |
Out of scope; separate assembler RFC (AS5) |
| D9 | asset_compression.web |
A warned alias kept indefinitely |
| D10 | doctor --fix |
Forward it to provider doctors |
7. Risks and acceptance
- FP (bgfx on desktop, Android and web):
- SDL: no impact (
.gamepad = .none). iOS: none. - The only exposure is the 4.0 assembler floor and schema, closed by F landing before 4.0 is published (FP installs "latest").
- P1 keeps
.webparsing, and 4.0 keeps.backend = .bgfx. - FP CI is Linux-only, so its Android and web jobs gate D3.
- SDL: no impact (
- Windows blind spot: the CLI's Windows CI never builds a game, and labelle-sdl has no Windows job.
- Acceptance needs S0/S1's
windows-latestclean-HOME gamepad build. - Plus a 4.0 Windows desktop acceptance: bgfx
.gamepad = .autowith the sdl2 provider, the DLL staged, and the case-insensitive merge ofLABELLE_SDL2_LIB/Path.
- Acceptance needs S0/S1's
project.labellecompatibility:- Old assembler pins keep old behaviour.
- 4.0 refuses assemblers below protocol 7 with one line naming
labelle upgrade assembler. - A
.iosblock gets the "moved" hint only afterassembler_versionis bumped.
- iOS signing and devices: no CI can sign.
- Automate the simulator on
macos-latestplus compile-only device builds. - Device run and store bundles need manual acceptance with a real device and team.
- Automate the simulator on
- Rot risk: iOS has never run end to end on Zig 0.16, so I1 opens with the spike.
- Local verification on the owner's Mac: Xcode 27.0 is installed, but the active developer directory is the Command Line Tools and the Xcode license isn't accepted. Before local simulator tests, run
sudo xcodebuild -license acceptandsudo xcode-select -s /Applications/Xcode.app, then install an iOS simulator runtime. - Clean-clone and clean-HOME acceptance (4.0):
- Fresh FP clone, empty HOME, no siblings: desktop, android and wasm all build, and
.labelle/bgfx_*names come fromdescribe. - A third-party
backend_packagefixture generates into.labelle/<pkg>_desktop. labelle iosand legacy SDL--fixgive their diagnostics.- The guard passes with a single entry.
- A sokol iOS fixture runs in the simulator via
local:labelle-ios and then via the registry pin.
- Fresh FP clone, empty HOME, no siblings: desktop, android and wasm all build, and
- Review budget (3 bot rounds): I5, S4 and D4/P3 are separate PRs.
Critical files
labelle-cli:src/agnostic_guard_test.zig,src/cli/ios.zig(withpipeline/install.zig,pipeline/run.zig),src/cli/project_config.zig(withpipeline.zig:162),src/cli/sdl_provision.zig(withdoctor.zig).labelle-assembler:src/config.zig,src/main.zig:205-321(describe/--target).
Activity
chore: neutral fixtures and comments in ten core files (RFC #471 X1) (#…
apotema commentedon Sep 28, 2026
Follow-on after this phase: making the engine platform-agnostic is tracked in labelle-toolkit/labelle-engine#902 (Android immersive mode → labelle-android, plus two small Android checks). It is sequenced after the CLI work.
https://claude.ai/code/session_01R2K5sJDL5Msn1uRTkybiDP
apotema commentedon Oct 1, 2026
Done: the CLI core is fully agnostic. labelle-cli v4.0.0 / v4.1.0 name no platform, store or backend, and the agnostic guard's allowlist is at its final state, the guard's own file only.
CLI
vendor/;--dockerrefuses macOS targets.labelle-assembler describe(protocol 7). TheBackendenum is gone, andupgrade alldelegates toassembler upgrade backend.labelle iosand the core iOS code are removed; iOS belongs to labelle-ios.sdl2provider (labelle-sdl) owns them.Platform/AssetCompressionmirrors are removed; targets are names.labelle doctor --fixis forwarded to provider doctors.build_optionsinenv_file, the RFC's "contract 1.4" row (D3).docs/migrating-to-4.0.md.Providers and packages
iosnamespace commands (doctor/devices/xcode/run), device builds viabuild_options, signing and.ipa. CI runs the device flow end to end on CLI 4.1.0. A real device and real signing still need manual acceptance.sdl2provider. All three desktop backends fail with one line when SDL2 is missing (S2, incl. labelle-sokol#35).describe,generate --target,upgrade backend, target-keyedasset_compression(D1, D2, P1), and the.ios"moved to providers/ios.json" hint (I4, #810).Follow-ups, out of this RFC