From 55bca1991d670240b476f5c797a4a3276fc20171 Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 09:49:14 +0100 Subject: [PATCH 01/12] feat: add devenv shell configuration alongside nix flake Phase 1 of the nixflakes -> devenv migration. Adds devenv.nix, devenv.yaml, devenv.lock, and .envrc without touching the existing flake, so both systems work side by side during the cutover. The four C/C++ derivations (zig 0.16.0, cimgui, rmlui, rmlui-bridge) are ported verbatim from flake.nix, as are the ZIGCRAFT_DYNAMIC_LINKER and ZIGCRAFT_RUNTIME_LIBRARY_PATH computations consumed by build.zig and the robustness integration test. Base devenv.nix exposes the common foundation (zig, sdl3, vulkan, cimgui, rmlui, freetype, pkg-config, glslang). Three additive profiles mirror the previous devShells: - default: zls + mesa + weston + kcov + shellcheck (local dev; .envrc activates it automatically via 'use devenv --profile default') - unit: kcov + shellcheck (lean CI CPU shell, no mesa/weston/zls) - graphics: mesa + weston + shellcheck (CI graphics shell) Spike-verified: full 'zig build' links zigcraft/benchmark/robust-demo inside 'devenv shell --profile unit', env vars export correctly, and IN_NIX_SHELL=impure is set so scripts/run_benchmark.sh is unaffected. Signed-off-by: MichaelFisher1997 --- .envrc | 7 + .gitignore | 2 + devenv.lock | 82 ++++++++++ devenv.nix | 433 ++++++++++++++++++++++++++++++++++++++++++++++++++++ devenv.yaml | 3 + 5 files changed, 527 insertions(+) create mode 100644 .envrc create mode 100644 devenv.lock create mode 100644 devenv.nix create mode 100644 devenv.yaml diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..856d3cae --- /dev/null +++ b/.envrc @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +eval "$(devenv direnvrc)" + +# Local developers get the full default shell (zls, mesa, weston, kcov). +# CI overrides this with --profile unit or --profile graphics. +use devenv --profile default diff --git a/.gitignore b/.gitignore index 4f5cf621..66a6b269 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ result node_modules/ __pycache__/ .direnv/ +.devenv/ +.devenv.flake.nix *-profile* test_output.txt benchmark_results*.json diff --git a/devenv.lock b/devenv.lock new file mode 100644 index 00000000..3205ac3b --- /dev/null +++ b/devenv.lock @@ -0,0 +1,82 @@ +{ + "nodes": { + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1784939196, + "owner": "cachix", + "repo": "devenv", + "rev": "60b80be9e10ea07ff79c44a39741a75afd74f6a9", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1784288435, + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "43b3c1ab9d40fb1dbb008f451988a91e375825e9", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1784796856, + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e2587caef70cea85dd97d7daab492899902dbf5d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": [ + "git-hooks" + ] + } + } + }, + "root": "root", + "version": 7 +} diff --git a/devenv.nix b/devenv.nix new file mode 100644 index 00000000..56e90e61 --- /dev/null +++ b/devenv.nix @@ -0,0 +1,433 @@ +{ pkgs, lib, config, ... }: + +let + zig_version = "0.16.0"; + + # The Nix glibc is newer than the host glibc on non-NixOS CI runners + # (Blacksmith/GitHub Ubuntu). Binaries linked against nixpkgs libraries + # must be launched via the nixpkgs dynamic loader with the matching + # library path. build.zig:addRunArtifact consumes these to wrap every + # Run step; src/integration_test_robustness.zig mirrors the pattern. + nix_dynamic_linker = + if pkgs.stdenv.isLinux then pkgs.stdenv.cc.bintools.dynamicLinker else ""; + + nix_runtime_library_path = + if pkgs.stdenv.isLinux then pkgs.lib.makeLibraryPath [ + pkgs.glibc + pkgs.stdenv.cc.cc.lib + pkgs.sdl3 + pkgs.vulkan-loader + pkgs.mesa + cimgui + rmluiBridge + rmlui + pkgs.freetype + ] else ""; + + zig_sources = { + x86_64-linux = { + url = "https://ziglang.org/download/${zig_version}/zig-x86_64-linux-${zig_version}.tar.xz"; + hash = "sha256-cOSWZKdDdLSLUebz/fv0N/Y5XUJQkFBYi9SavlK6PQA="; + }; + + aarch64-linux = { + url = "https://ziglang.org/download/${zig_version}/zig-aarch64-linux-${zig_version}.tar.xz"; + hash = "sha256-6ksJv7IuxvbGzqxXq2PvtrRuF6sI0h9p86SLOOFTTxc="; + }; + + x86_64-darwin = { + url = "https://ziglang.org/download/${zig_version}/zig-x86_64-macos-${zig_version}.tar.xz"; + hash = "sha256-A4dVftGHe8ai4YAsg5GVO63bp2CBh2MBxSL1KXe1K6c="; + }; + + aarch64-darwin = { + url = "https://ziglang.org/download/${zig_version}/zig-aarch64-macos-${zig_version}.tar.xz"; + hash = "sha256-sj1w3qqHm1wtSG7TMW9+qlPoSs9vycx0feFSRQ1AFIk="; + }; + }; + + zig_source = zig_sources.${pkgs.system}; + + zig_tarball = pkgs.fetchurl { + url = zig_source.url; + hash = zig_source.hash; + }; + + zig = pkgs.stdenvNoCC.mkDerivation { + pname = "zig"; + version = zig_version; + src = zig_tarball; + + dontUnpack = true; + dontConfigure = true; + dontBuild = true; + + installPhase = '' + mkdir -p $out + tar -xJf ${zig_tarball} -C $out --strip-components=1 + mkdir -p $out/bin + cp $out/zig $out/bin/zig + ''; + + meta = { + mainProgram = "zig"; + platforms = builtins.attrNames zig_sources; + }; + }; + + cimgui = pkgs.stdenv.mkDerivation rec { + pname = "cimgui"; + version = "1.92.7-docking"; + + src = pkgs.fetchFromGitHub { + owner = "cimgui"; + repo = "cimgui"; + rev = "d3f0c2f4a7d4d116ef908295b971a36bdfdafe27"; + hash = "sha256-CsnoCFSzAibhUz2ffbGQcxczzhpQKpz9WJoRYbNH+kc="; + fetchSubmodules = true; + }; + + nativeBuildInputs = [ pkgs.pkg-config ]; + buildInputs = [ pkgs.sdl3 pkgs.vulkan-headers ]; + + dontConfigure = true; + + cimguiBackendHeader = pkgs.writeText "cimgui_backend.h" '' + #pragma once + #include + #include + #include + + #ifdef __cplusplus + extern "C" { + #endif + + typedef struct ZigCraftImGuiVulkanInitInfo { + VkInstance instance; + VkPhysicalDevice physical_device; + VkDevice device; + VkQueue queue; + uint32_t queue_family; + VkDescriptorPool descriptor_pool; + VkRenderPass render_pass; + uint32_t min_image_count; + uint32_t image_count; + VkSampleCountFlagBits msaa_samples; + } ZigCraftImGuiVulkanInitInfo; + + bool ZigCraft_ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); + bool ZigCraft_ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); + void ZigCraft_ImGui_ImplSDL3_NewFrame(void); + void ZigCraft_ImGui_ImplSDL3_Shutdown(void); + + bool ZigCraft_ImGui_ImplVulkan_Init(const ZigCraftImGuiVulkanInitInfo* info); + void ZigCraft_ImGui_ImplVulkan_NewFrame(void); + void ZigCraft_ImGui_ImplVulkan_RenderDrawData(void* draw_data, VkCommandBuffer command_buffer); + void ZigCraft_ImGui_ImplVulkan_Shutdown(void); + + void ZigCraft_ImGui_CreateContext(void); + void ZigCraft_ImGui_DestroyContext(void); + void ZigCraft_ImGui_StyleColorsDark(void); + void ZigCraft_ImGui_NewFrame(void); + bool ZigCraft_ImGui_Begin(const char* name); + bool ZigCraft_ImGui_Checkbox(const char* label, bool* value); + void ZigCraft_ImGui_SameLine(void); + void ZigCraft_ImGui_TextUnformatted(const char* text); + void ZigCraft_ImGui_End(void); + void ZigCraft_ImGui_Render(void); + void* ZigCraft_ImGui_GetDrawData(void); + + #ifdef __cplusplus + } + #endif + ''; + + cimguiBackendSource = pkgs.writeText "cimgui_backend.cpp" '' + #include "cimgui_backend.h" + #include "imgui.h" + #include "backends/imgui_impl_sdl3.h" + #include "backends/imgui_impl_vulkan.h" + + bool ZigCraft_ImGui_ImplSDL3_InitForVulkan(SDL_Window* window) { + return ImGui_ImplSDL3_InitForVulkan(window); + } + + bool ZigCraft_ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { + return ImGui_ImplSDL3_ProcessEvent(event); + } + + void ZigCraft_ImGui_ImplSDL3_NewFrame(void) { + ImGui_ImplSDL3_NewFrame(); + } + + void ZigCraft_ImGui_ImplSDL3_Shutdown(void) { + ImGui_ImplSDL3_Shutdown(); + } + + bool ZigCraft_ImGui_ImplVulkan_Init(const ZigCraftImGuiVulkanInitInfo* info) { + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = info->instance; + init_info.PhysicalDevice = info->physical_device; + init_info.Device = info->device; + init_info.QueueFamily = info->queue_family; + init_info.Queue = info->queue; + init_info.DescriptorPool = info->descriptor_pool; + init_info.PipelineInfoMain.RenderPass = info->render_pass; + init_info.MinImageCount = info->min_image_count; + init_info.ImageCount = info->image_count; + init_info.PipelineInfoMain.MSAASamples = info->msaa_samples; + return ImGui_ImplVulkan_Init(&init_info); + } + + void ZigCraft_ImGui_ImplVulkan_NewFrame(void) { + ImGui_ImplVulkan_NewFrame(); + } + + void ZigCraft_ImGui_ImplVulkan_RenderDrawData(void* draw_data, VkCommandBuffer command_buffer) { + ImGui_ImplVulkan_RenderDrawData(static_cast(draw_data), command_buffer); + } + + void ZigCraft_ImGui_ImplVulkan_Shutdown(void) { + ImGui_ImplVulkan_Shutdown(); + } + + void ZigCraft_ImGui_CreateContext(void) { + ImGui::CreateContext(); + } + + void ZigCraft_ImGui_DestroyContext(void) { + ImGui::DestroyContext(); + } + + void ZigCraft_ImGui_StyleColorsDark(void) { + ImGui::StyleColorsDark(); + } + + void ZigCraft_ImGui_NewFrame(void) { + ImGui::NewFrame(); + } + + bool ZigCraft_ImGui_Begin(const char* name) { + return ImGui::Begin(name); + } + + bool ZigCraft_ImGui_Checkbox(const char* label, bool* value) { + return ImGui::Checkbox(label, value); + } + + void ZigCraft_ImGui_SameLine(void) { + ImGui::SameLine(); + } + + void ZigCraft_ImGui_TextUnformatted(const char* text) { + ImGui::TextUnformatted(text); + } + + void ZigCraft_ImGui_End(void) { + ImGui::End(); + } + + void ZigCraft_ImGui_Render(void) { + ImGui::Render(); + } + + void* ZigCraft_ImGui_GetDrawData(void) { + return ImGui::GetDrawData(); + } + ''; + + cimguiCompatSource = pkgs.writeText "cimgui_compat.c" '' + #include + #include + + extern int __isoc99_vsscanf(const char* str, const char* format, va_list args); + + int __isoc23_sscanf(const char* str, const char* format, ...) { + va_list args; + va_start(args, format); + int result = __isoc99_vsscanf(str, format, args); + va_end(args); + return result; + } + ''; + + buildPhase = '' + runHook preBuild + cxxflags="-std=c++17 -O2 -fPIC -I. -Iimgui -Iimgui/backends $(pkg-config --cflags sdl3) -I${pkgs.vulkan-headers}/include" + $CXX $cxxflags -c cimgui.cpp -o cimgui.o + $CXX $cxxflags -c imgui/imgui.cpp -o imgui.o + $CXX $cxxflags -c imgui/imgui_draw.cpp -o imgui_draw.o + $CXX $cxxflags -c imgui/imgui_demo.cpp -o imgui_demo.o + $CXX $cxxflags -c imgui/imgui_tables.cpp -o imgui_tables.o + $CXX $cxxflags -c imgui/imgui_widgets.cpp -o imgui_widgets.o + $CXX $cxxflags -c imgui/backends/imgui_impl_sdl3.cpp -o imgui_impl_sdl3.o + $CXX $cxxflags -c imgui/backends/imgui_impl_vulkan.cpp -o imgui_impl_vulkan.o + cp ${cimguiBackendHeader} cimgui_backend.h + $CXX $cxxflags -I. -c ${cimguiBackendSource} -o cimgui_backend.o + $CC -O2 -fPIC -c ${cimguiCompatSource} -o cimgui_compat.o + ar rcs libcimgui.a cimgui.o imgui.o imgui_draw.o imgui_demo.o imgui_tables.o imgui_widgets.o imgui_impl_sdl3.o imgui_impl_vulkan.o cimgui_backend.o cimgui_compat.o + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/lib/pkgconfig $out/include/cimgui $out/include/cimgui/imgui + cp cimgui.h cimconfig.h $out/include/cimgui/ + cp imgui/imgui.h imgui/imconfig.h imgui/imgui_internal.h $out/include/cimgui/imgui/ + cp imgui/imstb_rectpack.h imgui/imstb_textedit.h imgui/imstb_truetype.h $out/include/cimgui/imgui/ + cp ${cimguiBackendHeader} $out/include/cimgui/cimgui_backend.h + cp imgui/backends/imgui_impl_sdl3.h imgui/backends/imgui_impl_vulkan.h $out/include/cimgui/imgui/ + cp libcimgui.a $out/lib/libcimgui.a + cat > $out/lib/pkgconfig/cimgui.pc < $out/lib/pkgconfig/zigcraft-rmlui-bridge.pc < Date: Sat, 25 Jul 2026 09:56:33 +0100 Subject: [PATCH 02/12] ci: add setup-devenv action, migrate weston/zig-cache, add zigcraft task Phase 2a of the nixflakes -> devenv migration. Adds the devenv setup composite action and migrates the two actions that referenced nix shells or flake files. - .github/actions/setup-devenv: new action installing Nix (preserving the Determinate primary + cachix fallback pattern), wiring the devenv Cachix cache (pull-only), adding the devenv CLI, and caching on hashFiles(devenv.nix, devenv.yaml, devenv.lock). - start-weston: input nix-shell (default .#ci-graphics) renamed to devenv-profile (default graphics); 'nix develop ... --command weston' becomes 'devenv shell --profile ... -- weston'. - setup-zig-cache: cache key switches from hashFiles(flake.nix, flake.lock) to hashFiles(devenv.nix, devenv.yaml, devenv.lock). - devenv.nix: new tasks.zigcraft replacing the former packages.default / 'nix build -L' -- builds the Debug x86_64-linux binary and bakes the nixpkgs runtime rpath via patchelf. patchelf added to base packages. Verified: devenv info registers the zigcraft task; actionlint (full-repo scan) reports no errors on the touched actions. Signed-off-by: MichaelFisher1997 --- .github/actions/setup-devenv/action.yml | 74 ++++++++++++++++++++++ .github/actions/setup-zig-cache/action.yml | 4 +- .github/actions/start-weston/action.yml | 12 ++-- devenv.nix | 27 +++++++- 4 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 .github/actions/setup-devenv/action.yml diff --git a/.github/actions/setup-devenv/action.yml b/.github/actions/setup-devenv/action.yml new file mode 100644 index 00000000..395a5723 --- /dev/null +++ b/.github/actions/setup-devenv/action.yml @@ -0,0 +1,74 @@ +name: Setup devenv +description: Install Nix (primary/fallback), devenv CLI, and restore the devenv shell cache + +inputs: + cache-key-prefix: + description: Prefix for the cache primary key + required: false + default: devenv + cache-paths: + description: Paths to cache + required: false + default: ~/.cache/nix + +runs: + using: composite + steps: + - name: Mark devenv setup start + shell: bash + run: | + START=$(date +%s) + echo "SETUP_NIX_START=$START" >> "$GITHUB_ENV" + echo "devenv setup start: $(date -u +%Y-%m-%dT%H:%M:%SZ)" + + - name: Install Nix (primary) + id: nix_install_primary + continue-on-error: true + uses: DeterminateSystems/nix-installer-action@v16 + + - name: Install Nix (fallback) + if: steps.nix_install_primary.outcome == 'failure' + uses: cachix/install-nix-action@v31 + with: + extra_nix_config: | + experimental-features = nix-command flakes + + - name: Verify Nix installation + shell: bash + run: nix --version + + # The devenv project publishes prebuilt closures to its own Cachix cache. + # Pulling from it avoids building devenv and its module dependencies. + # Public cache: no authToken needed; skipPush because we only pull. + - name: Configure devenv Cachix cache + uses: cachix/cachix-action@v16 + with: + name: devenv + skipPush: true + + - name: Install devenv + shell: bash + run: nix profile add nixpkgs#devenv + + - name: Verify devenv installation + shell: bash + run: devenv version + + - name: Cache Nix Store + continue-on-error: true + uses: nix-community/cache-nix-action@v7 + with: + primary-key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('devenv.nix', 'devenv.yaml', 'devenv.lock') }} + restore-prefixes-first-match: ${{ inputs.cache-key-prefix }}-${{ runner.os }}- + paths: ${{ inputs.cache-paths }} + + - name: Mark devenv setup complete + shell: bash + run: | + END=$(date +%s) + START=${SETUP_NIX_START:-$END} + { + echo "### devenv Setup" + echo "- Duration: $((END - START))s" + echo "- Cache key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('devenv.nix', 'devenv.yaml', 'devenv.lock') }}" + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/actions/setup-zig-cache/action.yml b/.github/actions/setup-zig-cache/action.yml index 1cc2b34a..82d707e0 100644 --- a/.github/actions/setup-zig-cache/action.yml +++ b/.github/actions/setup-zig-cache/action.yml @@ -33,9 +33,9 @@ runs: path: | ${{ github.workspace }}/${{ inputs.global-cache-dir }} ${{ github.workspace }}/${{ inputs.local-cache-dir }} - key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('build.zig', 'build.zig.zon', 'flake.nix', 'flake.lock') }}-${{ hashFiles('src/**', 'modules/**', 'libs/**', 'assets/shaders/**') }} + key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('build.zig', 'build.zig.zon', 'devenv.nix', 'devenv.yaml', 'devenv.lock') }}-${{ hashFiles('src/**', 'modules/**', 'libs/**', 'assets/shaders/**') }} restore-keys: | - ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('build.zig', 'build.zig.zon', 'flake.nix', 'flake.lock') }}- + ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('build.zig', 'build.zig.zon', 'devenv.nix', 'devenv.yaml', 'devenv.lock') }}- ${{ inputs.cache-key-prefix }}-${{ runner.os }}- - name: Summarize Zig cache diff --git a/.github/actions/start-weston/action.yml b/.github/actions/start-weston/action.yml index 4bd71040..890ef408 100644 --- a/.github/actions/start-weston/action.yml +++ b/.github/actions/start-weston/action.yml @@ -2,10 +2,10 @@ name: Start Weston description: Start a headless Weston compositor and wait for the Wayland socket inputs: - nix-shell: + devenv-profile: required: false - default: .#ci-graphics - description: Nix shell containing weston + default: graphics + description: devenv profile containing weston runtime-dir: required: false default: /tmp/runtime-runner @@ -46,10 +46,10 @@ runs: chmod 700 "${{ inputs.runtime-dir }}" export XDG_RUNTIME_DIR="${{ inputs.runtime-dir }}" - echo "Realizing ${{ inputs.nix-shell }} before starting Weston" - nix develop "${{ inputs.nix-shell }}" --command true + echo "Realizing devenv profile ${{ inputs.devenv-profile }} before starting Weston" + devenv shell --profile "${{ inputs.devenv-profile }}" -- true - nix develop "${{ inputs.nix-shell }}" --command weston \ + devenv shell --profile "${{ inputs.devenv-profile }}" -- weston \ --socket="${{ inputs.socket }}" \ --backend=headless-backend.so \ --width=1280 \ diff --git a/devenv.nix b/devenv.nix index 56e90e61..2e009b7e 100644 --- a/devenv.nix +++ b/devenv.nix @@ -374,6 +374,19 @@ let rmlui pkgs.freetype ]; + + # rpath baked into the distributed binary so it finds nixpkgs libs when run + # outside a devenv shell. Mirrors the postFixup of the former flake + # packages.default derivation. + artifact_runtime_rpath = pkgs.lib.makeLibraryPath [ + pkgs.sdl3 + pkgs.vulkan-loader + pkgs.stdenv.cc.cc.lib + cimgui + rmluiBridge + rmlui + pkgs.freetype + ]; in { languages.zig = { @@ -386,13 +399,25 @@ in # pick the lean CPU shell (--profile unit) or the graphics shell # (--profile graphics). Local devs get the full shell via the # `default` profile, which .envrc activates automatically. - packages = [ pkgs.pkg-config pkgs.glslang ] ++ commonBuildInputs; + packages = [ pkgs.pkg-config pkgs.glslang pkgs.patchelf ] ++ commonBuildInputs; env = { ZIGCRAFT_DYNAMIC_LINKER = nix_dynamic_linker; ZIGCRAFT_RUNTIME_LIBRARY_PATH = nix_runtime_library_path; }; + # Replaces the former flake packages.default / `nix build -L`. Produces a + # relocatable zigcraft binary at the given prefix (default ./dist) with the + # nixpkgs runtime libraries baked into its rpath. Invoked by CI as + # `devenv shell --profile unit -- devenv tasks run zigcraft`. + tasks.zigcraft.exec = '' + set -euo pipefail + out="''${1:-$PWD/dist}" + zig build -Doptimize=Debug -Dtarget=x86_64-linux-gnu --prefix "$out" + patchelf --add-rpath ${artifact_runtime_rpath} "$out/bin/zigcraft" + echo "Built zigcraft -> $out/bin/zigcraft" + ''; + enterShell = '' echo "Zig ${zig_version} + SDL3 Dev Environment (devenv)" echo "Compiler: $(zig version)" From c7e62023dd846472bc1d70a9db5e965f453688ab Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 10:02:17 +0100 Subject: [PATCH 03/12] ci: migrate build.yml from nix flake to devenv Phase 2b. All build.yml jobs now use devenv: - fmt: 'devenv shell --profile unit -- zig fmt --check src/ modules/' - build: 'devenv shell --profile unit -- devenv tasks run zigcraft' replaces 'nix build -L'; artifact copied from dist/bin/zigcraft (task output) instead of result/bin/zigcraft (flake symlink). - unit-test-matrix: unit profile for the test matrix, phase5-gate, and phase5-stress-gate. - integration-test: graphics profile for test-integration, world smoke test, and phase5-visual-gate. Path filters (push, pull_request, dorny/paths-filter) now key on devenv.nix/devenv.yaml/devenv.lock and .github/actions/setup-devenv/** instead of flake.nix/flake.lock and .github/actions/setup-nix/**. platform-build (Windows/macOS) is unchanged: it never used Nix. Signed-off-by: MichaelFisher1997 --- .github/workflows/build.yml | 55 +++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29930567..6351381b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,9 +12,10 @@ on: - "docs/benchmarks/**" - "build.zig" - "build.zig.zon" - - "flake.nix" - - "flake.lock" - - ".github/actions/setup-nix/**" + - "devenv.nix" + - "devenv.yaml" + - "devenv.lock" + - ".github/actions/setup-devenv/**" - ".github/actions/setup-zig-cache/**" - ".github/actions/setup-lavapipe/**" - ".github/vulkan/**" @@ -31,9 +32,10 @@ on: - "docs/benchmarks/**" - "build.zig" - "build.zig.zon" - - "flake.nix" - - "flake.lock" - - ".github/actions/setup-nix/**" + - "devenv.nix" + - "devenv.yaml" + - "devenv.lock" + - ".github/actions/setup-devenv/**" - ".github/actions/setup-zig-cache/**" - ".github/actions/setup-lavapipe/**" - ".github/vulkan/**" @@ -88,9 +90,10 @@ jobs: - 'docs/benchmarks/**' - 'build.zig' - 'build.zig.zon' - - 'flake.nix' - - 'flake.lock' - - '.github/actions/setup-nix/**' + - 'devenv.nix' + - 'devenv.yaml' + - 'devenv.lock' + - '.github/actions/setup-devenv/**' - '.github/actions/setup-zig-cache/**' - '.github/actions/setup-lavapipe/**' - '.github/vulkan/**' @@ -112,11 +115,11 @@ jobs: with: ref: ${{ inputs.ref }} - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Check Zig formatting - run: nix develop .#ci-unit --command zig fmt --check src/ modules/ + run: devenv shell --profile unit -- zig fmt --check src/ modules/ build: permissions: @@ -135,19 +138,19 @@ jobs: run: | echo "No build-relevant changes detected. Skipping binary build." - - name: Setup Nix + - name: Setup devenv if: needs.changes.outputs.code_changes == 'true' - uses: ./.github/actions/setup-nix + uses: ./.github/actions/setup-devenv - name: Build if: needs.changes.outputs.code_changes == 'true' - run: nix build -L + run: devenv shell --profile unit -- devenv tasks run zigcraft - name: Prepare Artifact if: needs.changes.outputs.code_changes == 'true' run: | mkdir -p dist - cp -L result/bin/zigcraft dist/zigcraft-linux + cp -L dist/bin/zigcraft dist/zigcraft-linux - name: Upload Artifact if: needs.changes.outputs.code_changes == 'true' @@ -178,9 +181,9 @@ jobs: run: | echo "No build-relevant changes detected. Skipping unit tests." - - name: Setup Nix + - name: Setup devenv if: needs.changes.outputs.code_changes == 'true' - uses: ./.github/actions/setup-nix + uses: ./.github/actions/setup-devenv - name: Setup Zig cache if: needs.changes.outputs.code_changes == 'true' @@ -195,15 +198,15 @@ jobs: name: Unit Test (${{ matrix.optimize }}) timeout: 25m log-file: unit-test-${{ matrix.optimize }}.log - command: nix develop .#ci-unit --command zig build -Doptimize=${{ matrix.optimize }} test + command: devenv shell --profile unit -- zig build -Doptimize=${{ matrix.optimize }} test - name: Run Phase 5 compact LOD gate if: needs.changes.outputs.code_changes == 'true' && matrix.optimize == 'Debug' - run: nix develop .#ci-unit --command zig build phase5-gate + run: devenv shell --profile unit -- zig build phase5-gate - name: Run bounded Phase 5 streaming stress gate if: needs.changes.outputs.code_changes == 'true' && matrix.optimize == 'Debug' - run: nix develop .#ci-unit --command zig build phase5-stress-gate -Dphase5-stress-iterations=64 + run: devenv shell --profile unit -- zig build phase5-stress-gate -Dphase5-stress-iterations=64 - name: Upload unit test log if: failure() @@ -247,9 +250,9 @@ jobs: run: | echo "No build-relevant changes detected. Skipping integration tests." - - name: Setup Nix + - name: Setup devenv if: needs.changes.outputs.code_changes == 'true' - uses: ./.github/actions/setup-nix + uses: ./.github/actions/setup-devenv - name: Setup Zig cache if: needs.changes.outputs.code_changes == 'true' @@ -272,7 +275,7 @@ jobs: name: Integration Test timeout: 25m log-file: integration-test.log - command: nix develop .#ci-graphics --command zig build test-integration -Dskip-present=true + command: devenv shell --profile graphics -- zig build test-integration -Dskip-present=true - name: Run world load smoke test (headless) if: needs.changes.outputs.code_changes == 'true' @@ -281,7 +284,7 @@ jobs: name: World Smoke Test timeout: 15m log-file: world-smoke-test.log - command: nix develop .#ci-graphics --command zig build run -Dsmoke-test=true -Dskip-present=true + command: devenv shell --profile graphics -- zig build run -Dsmoke-test=true -Dskip-present=true env: XDG_RUNTIME_DIR: /tmp/runtime-runner WAYLAND_DISPLAY: headless @@ -295,7 +298,7 @@ jobs: name: Phase 5 Visual Motion and Saved-World Reload Gate timeout: 35m log-file: phase5-visual-gate.log - command: nix develop .#ci-graphics --command zig build phase5-visual-gate + command: devenv shell --profile graphics -- zig build phase5-visual-gate env: XDG_RUNTIME_DIR: /tmp/runtime-runner WAYLAND_DISPLAY: headless From d3a144d5ea56ad3830ecd2c42919201764080b04 Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 10:11:06 +0100 Subject: [PATCH 04/12] ci: migrate remaining workflows from nix flake to devenv Phase 2c. All remaining CI workflows now use the devenv composite action and the unit/graphics profiles: - workflow-validation: shell syntax + shellcheck via unit profile; the former 'nix flake check --no-build' gate becomes 'devenv info >/dev/null' which validates the devenv.nix configuration evaluates. Path filters key on devenv.nix/devenv.yaml/devenv.lock. - coverage: kcov + zig build test via unit profile. - sanitize: ASAN test matrix via unit profile. - profiling: fixed-world benchmark capture via graphics profile. - visual-test: menu screenshot capture via graphics profile (the ad-hoc 'nix shell nixpkgs#imagemagick' for golden comparison is retained since Nix remains installed). - security: gitleaks/trivy ad-hoc 'nix run nixpkgs#...' retained; the former 'nix flake show --json' dependency-graph artifact is replaced by a devenv configuration snapshot (devenv.lock) uploaded as 'devenv-configuration'. - benchmark: suite, phase5-stress-gate, and GPU culling captures via the unit/graphics profiles; provenance strings updated from 'pinned Nix flake'/'Nix environment' to 'pinned devenv inputs'/'devenv profile'. - opencode, opencode-pr, opencode-audit, opencode-test-writer: setup-only, swapped to the devenv composite action. - labeler.yml: build label triggers on devenv.nix/devenv.yaml/devenv.lock. Verified: actionlint (full-repo scan) reports no errors. Signed-off-by: MichaelFisher1997 --- .github/labeler.yml | 5 +++-- .github/workflows/benchmark.yml | 18 +++++++++--------- .github/workflows/coverage.yml | 8 ++++---- .github/workflows/opencode-audit.yml | 4 ++-- .github/workflows/opencode-pr.yml | 4 ++-- .github/workflows/opencode-test-writer.yml | 4 ++-- .github/workflows/opencode.yml | 4 ++-- .github/workflows/profiling.yml | 6 +++--- .github/workflows/sanitize.yml | 6 +++--- .github/workflows/security.yml | 18 +++++++++--------- .github/workflows/visual-test.yml | 6 +++--- .github/workflows/workflow-validation.yml | 22 ++++++++++++---------- 12 files changed, 54 insertions(+), 51 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 41557b16..d68f9028 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -34,5 +34,6 @@ build: - any-glob-to-any-file: - "build.zig" - "build.zig.zon" - - "flake.nix" - - "flake.lock" + - "devenv.nix" + - "devenv.yaml" + - "devenv.lock" diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 08402a65..85f1c583 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -78,9 +78,9 @@ jobs: run: | printf 'Skipping benchmark: no benchmark-relevant paths changed and run-benchmark label is absent.\n' - - name: Setup Nix + - name: Setup devenv if: steps.gate.outputs.run == 'true' - uses: ./.github/actions/setup-nix + uses: ./.github/actions/setup-devenv - name: Setup Zig cache if: steps.gate.outputs.run == 'true' @@ -104,7 +104,7 @@ jobs: name: Benchmark timeout: ${{ github.event_name == 'schedule' && '55m' || github.event_name == 'workflow_dispatch' && '55m' || '20m' }} log-file: benchmark.log - command: mkdir -p "$MESA_SHADER_CACHE_DIR" && nix develop .#ci-graphics --command bash scripts/run_benchmark.sh --duration "$BENCHMARK_DURATION" --presets low,medium,high --scenarios stationary,traversal,rapid-turn,teleport-eviction --compact-modes off,auto --benchmark-world overworld --output-dir benchmark-results --per-preset-timeout 600 + command: mkdir -p "$MESA_SHADER_CACHE_DIR" && devenv shell --profile graphics -- bash scripts/run_benchmark.sh --duration "$BENCHMARK_DURATION" --presets low,medium,high --scenarios stationary,traversal,rapid-turn,teleport-eviction --compact-modes off,auto --benchmark-world overworld --output-dir benchmark-results --per-preset-timeout 600 env: XDG_RUNTIME_DIR: /tmp/runtime-runner WAYLAND_DISPLAY: headless @@ -115,9 +115,9 @@ jobs: # captures are longer acceptance evidence, not synthetic fixtures. BENCHMARK_DURATION: ${{ github.event_name == 'schedule' && '60' || github.event_name == 'workflow_dispatch' && github.event.inputs.duration || '5' }} ZIGCRAFT_BENCHMARK_GPU_ADAPTER: Lavapipe (Mesa software Vulkan) - ZIGCRAFT_BENCHMARK_GPU_DRIVER: Mesa Lavapipe supplied by the pinned Nix environment + ZIGCRAFT_BENCHMARK_GPU_DRIVER: Mesa Lavapipe supplied by the pinned devenv profile ZIGCRAFT_BENCHMARK_RUNNER: blacksmith-2vcpu-ubuntu-2404 GitHub Actions runner - ZIGCRAFT_BENCHMARK_ZIG_TOOLCHAIN: Zig 0.16.0 supplied by the pinned Nix flake + ZIGCRAFT_BENCHMARK_ZIG_TOOLCHAIN: Zig 0.16.0 supplied by the pinned devenv inputs - name: Run Phase 5 long-session streaming stress gate if: steps.gate.outputs.run == 'true' @@ -126,7 +126,7 @@ jobs: name: Phase 5 Streaming Stress timeout: 15m log-file: phase5-streaming-stress.log - command: nix develop .#ci-unit --command zig build phase5-stress-gate -Dphase5-stress-iterations="$PHASE5_STRESS_ITERATIONS" + command: devenv shell --profile unit -- zig build phase5-stress-gate -Dphase5-stress-iterations="$PHASE5_STRESS_ITERATIONS" env: # The scheduled run is longer by operation count, never by a flaky # elapsed-time threshold. PR feedback stays bounded. @@ -145,7 +145,7 @@ jobs: name: GPU Culling Baseline Sources timeout: 32m log-file: gpu-culling-benchmark.log - command: mkdir -p "$MESA_SHADER_CACHE_DIR" && nix develop .#ci-graphics --command bash -c 'scripts/run_benchmark.sh --duration 60 --presets extreme --scenarios traversal --compact-modes auto --gpu-culling off --gpu-culling-threshold 128 --benchmark-fixture gpu-culling-scale --benchmark-horizon-distance 4096 --benchmark-lod-memory-budget-mb 2048 --benchmark-require-gpu-candidates 1024 --benchmark-world flat --output-dir gpu-culling-results/cpu --per-preset-timeout 900 && scripts/run_benchmark.sh --duration 60 --presets extreme --scenarios traversal --compact-modes auto --gpu-culling on --gpu-culling-threshold 128 --benchmark-fixture gpu-culling-scale --benchmark-horizon-distance 4096 --benchmark-lod-memory-budget-mb 2048 --benchmark-require-gpu-candidates 1024 --benchmark-world flat --output-dir gpu-culling-results/gpu --per-preset-timeout 900' + command: mkdir -p "$MESA_SHADER_CACHE_DIR" && devenv shell --profile graphics -- bash -c 'scripts/run_benchmark.sh --duration 60 --presets extreme --scenarios traversal --compact-modes auto --gpu-culling off --gpu-culling-threshold 128 --benchmark-fixture gpu-culling-scale --benchmark-horizon-distance 4096 --benchmark-lod-memory-budget-mb 2048 --benchmark-require-gpu-candidates 1024 --benchmark-world flat --output-dir gpu-culling-results/cpu --per-preset-timeout 900 && scripts/run_benchmark.sh --duration 60 --presets extreme --scenarios traversal --compact-modes auto --gpu-culling on --gpu-culling-threshold 128 --benchmark-fixture gpu-culling-scale --benchmark-horizon-distance 4096 --benchmark-lod-memory-budget-mb 2048 --benchmark-require-gpu-candidates 1024 --benchmark-world flat --output-dir gpu-culling-results/gpu --per-preset-timeout 900' env: XDG_RUNTIME_DIR: /tmp/runtime-runner WAYLAND_DISPLAY: headless @@ -153,9 +153,9 @@ jobs: SDL_AUDIODRIVER: dummy ZIGCRAFT_SAFE_MODE: "1" ZIGCRAFT_BENCHMARK_GPU_ADAPTER: Lavapipe (Mesa software Vulkan) - ZIGCRAFT_BENCHMARK_GPU_DRIVER: Mesa Lavapipe supplied by the pinned Nix environment + ZIGCRAFT_BENCHMARK_GPU_DRIVER: Mesa Lavapipe supplied by the pinned devenv profile ZIGCRAFT_BENCHMARK_RUNNER: blacksmith-2vcpu-ubuntu-2404 GitHub Actions runner - ZIGCRAFT_BENCHMARK_ZIG_TOOLCHAIN: Zig 0.16.0 supplied by the pinned Nix flake + ZIGCRAFT_BENCHMARK_ZIG_TOOLCHAIN: Zig 0.16.0 supplied by the pinned devenv inputs - name: Validate fresh CPU-vs-GPU culling pair if: steps.gate.outputs.run == 'true' && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.capture_gpu_culling == 'true')) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 66ded952..096b7f3b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,8 +23,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Setup Zig cache uses: ./.github/actions/setup-zig-cache @@ -38,7 +38,7 @@ jobs: # kcov currently provides the stable line-coverage signal for Zig tests; # branch coverage and required thresholds are deferred until a baseline exists. set +e - nix develop .#ci-unit --command kcov \ + devenv shell --profile unit -- kcov \ --include-path=src,modules,libs \ --exclude-path=.zig-cache,zig-cache,assets,docs \ coverage/kcov \ @@ -47,7 +47,7 @@ jobs: set -e if [ "$kcov_status" -ne 0 ]; then echo "::warning::kcov exited with status $kcov_status; rerunning tests without instrumentation to distinguish coverage tooling failures from test failures" - nix develop .#ci-unit --command zig build test + devenv shell --profile unit -- zig build test fi - name: Upload coverage artifact diff --git a/.github/workflows/opencode-audit.yml b/.github/workflows/opencode-audit.yml index ac4a2b0b..1744160d 100644 --- a/.github/workflows/opencode-audit.yml +++ b/.github/workflows/opencode-audit.yml @@ -45,8 +45,8 @@ jobs: - name: Configure git identity run: bash scripts/configure_git_identity.sh "opencode[bot]" "opencode[bot]@users.noreply.github.com" - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Ensure automated-audit label exists run: bash scripts/ensure_label.sh "automated-audit" "Issues found by automated opencode audit scans" "1D76DB" diff --git a/.github/workflows/opencode-pr.yml b/.github/workflows/opencode-pr.yml index d296b371..0973fa4c 100644 --- a/.github/workflows/opencode-pr.yml +++ b/.github/workflows/opencode-pr.yml @@ -58,8 +58,8 @@ jobs: env: GH_TOKEN: ${{ github.token }} - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Prepare opencode cache run: bash scripts/prepare_opencode_cache.sh diff --git a/.github/workflows/opencode-test-writer.yml b/.github/workflows/opencode-test-writer.yml index ac151548..8966adb5 100644 --- a/.github/workflows/opencode-test-writer.yml +++ b/.github/workflows/opencode-test-writer.yml @@ -75,9 +75,9 @@ jobs: BASE_BRANCH: ${{ steps.select-module.outputs.base_branch }} run: bash scripts/verify_pat_push_permissions.sh - - name: Setup Nix + - name: Setup devenv if: steps.check-existing.outputs.skip != 'true' - uses: ./.github/actions/setup-nix + uses: ./.github/actions/setup-devenv - name: Load test writer prompt if: steps.check-existing.outputs.skip != 'true' diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml index bb08aa73..30e2c670 100644 --- a/.github/workflows/opencode.yml +++ b/.github/workflows/opencode.yml @@ -35,8 +35,8 @@ jobs: git config user.name "${GITHUB_ACTOR}" git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Prepare opencode cache run: mkdir -p /tmp/opencode-cache && echo "XDG_CACHE_HOME=/tmp/opencode-cache" >> "$GITHUB_ENV" diff --git a/.github/workflows/profiling.yml b/.github/workflows/profiling.yml index 09850391..6699e457 100644 --- a/.github/workflows/profiling.yml +++ b/.github/workflows/profiling.yml @@ -23,8 +23,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Setup Zig cache uses: ./.github/actions/setup-zig-cache @@ -45,7 +45,7 @@ jobs: log-file: profiling.log command: | mkdir -p profiling-artifacts - nix develop .#ci-graphics --command zig build benchmark -Doptimize=ReleaseFast -Dbenchmark-preset=medium -Dbenchmark-duration=10 -Dbenchmark-output=profiling-artifacts/fixed-world-profile.json + devenv shell --profile graphics -- zig build benchmark -Doptimize=ReleaseFast -Dbenchmark-preset=medium -Dbenchmark-duration=10 -Dbenchmark-output=profiling-artifacts/fixed-world-profile.json ruby -rjson -e ' profile = JSON.parse(File.read("profiling-artifacts/fixed-world-profile.json")) duration_us = (profile.fetch("duration_s").to_f * 1_000_000).to_i diff --git a/.github/workflows/sanitize.yml b/.github/workflows/sanitize.yml index ac6108c6..2a60e203 100644 --- a/.github/workflows/sanitize.yml +++ b/.github/workflows/sanitize.yml @@ -23,8 +23,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Setup Zig cache uses: ./.github/actions/setup-zig-cache @@ -37,7 +37,7 @@ jobs: name: Sanitizer Unit Test (${{ matrix.optimize }}) timeout: 35m log-file: sanitize-${{ matrix.optimize }}.log - command: nix develop .#ci-unit --command zig build -Dsanitize=address -Doptimize=${{ matrix.optimize }} test + command: devenv shell --profile unit -- zig build -Dsanitize=address -Doptimize=${{ matrix.optimize }} test - name: Upload sanitizer log if: failure() diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index e295043d..4a4e4283 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -43,8 +43,8 @@ jobs: with: fetch-depth: 0 - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Scan working tree for secrets if: github.event_name != 'schedule' @@ -60,11 +60,11 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - - name: Record flake dependency graph - run: nix flake show --json > nix-flake-show.json + - name: Record devenv configuration snapshot + run: cp devenv.lock devenv-configuration.json - name: Scan filesystem run: | @@ -73,11 +73,11 @@ jobs: env: TRIVY_CACHE_DIR: /tmp/trivy-cache - - name: Upload flake dependency graph + - name: Upload devenv configuration snapshot uses: actions/upload-artifact@v7 with: - name: nix-flake-show - path: nix-flake-show.json + name: devenv-configuration + path: devenv-configuration.json retention-days: 7 sbom: diff --git a/.github/workflows/visual-test.yml b/.github/workflows/visual-test.yml index b9a5dfe5..faacaf06 100644 --- a/.github/workflows/visual-test.yml +++ b/.github/workflows/visual-test.yml @@ -26,8 +26,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Start headless Wayland compositor uses: ./.github/actions/start-weston @@ -78,7 +78,7 @@ jobs: name: Visual Test timeout: 20m log-file: build-output.log - command: nix develop .#ci-graphics --command zig build run -Dscreenshot-path=screenshot.png -Dskip-present=true + command: devenv shell --profile graphics -- zig build run -Dscreenshot-path=screenshot.png -Dskip-present=true env: ZIG_GLOBAL_CACHE_DIR: /tmp/zig-cache-global XDG_RUNTIME_DIR: /tmp/runtime-runner diff --git a/.github/workflows/workflow-validation.yml b/.github/workflows/workflow-validation.yml index d60f0fb2..086984b2 100644 --- a/.github/workflows/workflow-validation.yml +++ b/.github/workflows/workflow-validation.yml @@ -8,8 +8,9 @@ on: - ".github/actions/**" - "scripts/*.sh" - ".shellcheckrc" - - "flake.nix" - - "flake.lock" + - "devenv.nix" + - "devenv.yaml" + - "devenv.lock" pull_request: branches: [dev] paths: @@ -17,8 +18,9 @@ on: - ".github/actions/**" - "scripts/*.sh" - ".shellcheckrc" - - "flake.nix" - - "flake.lock" + - "devenv.nix" + - "devenv.yaml" + - "devenv.lock" concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -44,8 +46,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Setup Nix - uses: ./.github/actions/setup-nix + - name: Setup devenv + uses: ./.github/actions/setup-devenv - name: Parse workflow YAML run: | @@ -56,10 +58,10 @@ jobs: ruby -e 'require "yaml"; Dir[".github/actions/**/action.{yml,yaml}"].sort.each { |f| YAML.load_file(f); puts "OK #{f}" }' - name: Check shell script syntax - run: nix develop .#ci-unit --command bash -n scripts/*.sh + run: devenv shell --profile unit -- bash -n scripts/*.sh - name: Run ShellCheck - run: nix develop .#ci-unit --command shellcheck scripts/*.sh + run: devenv shell --profile unit -- shellcheck scripts/*.sh - - name: Check Nix flake metadata - run: nix flake check --no-build + - name: Validate devenv configuration + run: devenv info >/dev/null From bfaad989b7491b36e414bd6e25c0f8bdeb4e4982 Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 10:19:18 +0100 Subject: [PATCH 05/12] fix: use namespaced devenv task name zigcraft:build devenv task names require a 'namespace:name' format (every task is namespaced, e.g. myapp:build). The bare 'zigcraft' attribute registered in 'devenv info' but 'devenv shell' rejected it with Tasks(InvalidTaskName("zigcraft")) when the task runner validated on shell entry. Renamed to zigcraft:build; CI invocation updated to match. Verified: 'devenv shell --profile unit' enters cleanly and 'devenv tasks list' shows zigcraft:build. Signed-off-by: MichaelFisher1997 --- .github/workflows/build.yml | 2 +- devenv.nix | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6351381b..c9097faa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -144,7 +144,7 @@ jobs: - name: Build if: needs.changes.outputs.code_changes == 'true' - run: devenv shell --profile unit -- devenv tasks run zigcraft + run: devenv shell --profile unit -- devenv tasks run zigcraft:build - name: Prepare Artifact if: needs.changes.outputs.code_changes == 'true' diff --git a/devenv.nix b/devenv.nix index 2e009b7e..b585a87a 100644 --- a/devenv.nix +++ b/devenv.nix @@ -409,8 +409,8 @@ in # Replaces the former flake packages.default / `nix build -L`. Produces a # relocatable zigcraft binary at the given prefix (default ./dist) with the # nixpkgs runtime libraries baked into its rpath. Invoked by CI as - # `devenv shell --profile unit -- devenv tasks run zigcraft`. - tasks.zigcraft.exec = '' + # `devenv shell --profile unit -- devenv tasks run zigcraft:build`. + tasks."zigcraft:build".exec = '' set -euo pipefail out="''${1:-$PWD/dist}" zig build -Doptimize=Debug -Dtarget=x86_64-linux-gnu --prefix "$out" From e8fef393a829d5192b2cabfc0d3049c4866a6d90 Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 10:20:05 +0100 Subject: [PATCH 06/12] refactor: migrate dev scripts, pre-push hook, and shader error strings to devenv Phase 3. Updates the remaining non-CI invocation sites: Scripts (self-wrapping helpers): - run_phase5_visual_smoke.sh, capture_lighting_baselines.sh, capture_shadow_test.sh: 'nix develop --command zig build run' -> 'devenv shell --profile graphics -- zig build run'. - run_benchmark.sh: the IN_NIX_SHELL guard still works (devenv sets IN_NIX_SHELL=impure), so the direct-execution branch is unchanged; only the fallback wrapper switches from 'nix develop --command' to 'devenv shell --profile graphics --'. Git hook: - .githooks/pre-push: fmt check and full test suite now run through 'devenv shell --profile unit --' (self-contained; does not require direnv activation). Source: - gpu_mesher.zig, lpv_utils.zig, culling_system.zig: user-facing SPIR-V regeneration hint updated from 'nix develop --command zig build' to 'devenv shell zig build'. Signed-off-by: MichaelFisher1997 --- .githooks/pre-push | 4 ++-- modules/engine-graphics/src/lpv_utils.zig | 2 +- modules/engine-graphics/src/vulkan/culling_system.zig | 2 +- modules/world-runtime/src/gpu_mesher.zig | 2 +- scripts/capture_lighting_baselines.sh | 2 +- scripts/capture_shadow_test.sh | 2 +- scripts/run_benchmark.sh | 2 +- scripts/run_phase5_visual_smoke.sh | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.githooks/pre-push b/.githooks/pre-push index 9c82388d..e5e8a2c4 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -7,10 +7,10 @@ echo "To bypass these checks in an emergency, use: git push --no-verify" echo "" echo "[1/2] Checking formatting..." -nix develop --command zig fmt --check src/ +devenv shell --profile unit -- zig fmt --check src/ echo "[2/2] Running full test suite..." -nix develop --command zig build test +devenv shell --profile unit -- zig build test echo "" echo "=== All pre-push checks passed! ===" diff --git a/modules/engine-graphics/src/lpv_utils.zig b/modules/engine-graphics/src/lpv_utils.zig index 1a977ca3..b600efc1 100644 --- a/modules/engine-graphics/src/lpv_utils.zig +++ b/modules/engine-graphics/src/lpv_utils.zig @@ -37,7 +37,7 @@ pub fn createShaderModule(vk: c.VkDevice, path: []const u8, allocator: std.mem.A pub fn ensureShaderFileExists(path: []const u8) !void { fs.cwd().access(path, .{}) catch |err| { log.log.errWithTrace("LPV shader artifact missing: {s} ({})", .{ path, err }); - log.log.err("Run `nix develop --command zig build` to regenerate Vulkan SPIR-V shaders.", .{}); + log.log.err("Run `devenv shell zig build` to regenerate Vulkan SPIR-V shaders.", .{}); return err; }; } diff --git a/modules/engine-graphics/src/vulkan/culling_system.zig b/modules/engine-graphics/src/vulkan/culling_system.zig index 9319cd6b..94b41b94 100644 --- a/modules/engine-graphics/src/vulkan/culling_system.zig +++ b/modules/engine-graphics/src/vulkan/culling_system.zig @@ -555,7 +555,7 @@ fn loadShaderModule(vk: c.VkDevice, path: []const u8, allocator: std.mem.Allocat fn ensureShaderFileExists(path: []const u8) !void { fs.cwd().access(path, .{}) catch |err| { log.log.errWithTrace("Culling shader artifact missing: {s} ({})", .{ path, err }); - log.log.err("Run `nix develop --command zig build` to regenerate Vulkan SPIR-V shaders.", .{}); + log.log.err("Run `devenv shell zig build` to regenerate Vulkan SPIR-V shaders.", .{}); return err; }; } diff --git a/modules/world-runtime/src/gpu_mesher.zig b/modules/world-runtime/src/gpu_mesher.zig index e263851f..c0489ee8 100644 --- a/modules/world-runtime/src/gpu_mesher.zig +++ b/modules/world-runtime/src/gpu_mesher.zig @@ -431,7 +431,7 @@ fn slotOrMissing(slot: ?usize) i32 { fn ensureShaderFileExists(path: []const u8) !void { fs.cwd().access(path, .{}) catch |err| { log.log.errWithTrace("Mesh shader artifact missing: {s} ({})", .{ path, err }); - log.log.err("Run `nix develop --command zig build` to regenerate Vulkan SPIR-V shaders.", .{}); + log.log.err("Run `devenv shell zig build` to regenerate Vulkan SPIR-V shaders.", .{}); return err; }; } diff --git a/scripts/capture_lighting_baselines.sh b/scripts/capture_lighting_baselines.sh index 7e38eb84..1cf162c4 100755 --- a/scripts/capture_lighting_baselines.sh +++ b/scripts/capture_lighting_baselines.sh @@ -11,7 +11,7 @@ channel_ids=(0 1 2 3 9 12 13) for scene in "${scenes[@]}"; do mkdir -p "$output_dir/$scene" for i in "${!channels[@]}"; do - ZIGCRAFT_DEBUG_SHADER=${channel_ids[$i]} nix develop --command zig build run \ + ZIGCRAFT_DEBUG_SHADER=${channel_ids[$i]} devenv shell --profile graphics -- zig build run \ -Dskip-present \ -Dshadow-test-scene \ -Dshadow-test-variant="$scene" \ diff --git a/scripts/capture_shadow_test.sh b/scripts/capture_shadow_test.sh index 4b84566e..a64bad48 100755 --- a/scripts/capture_shadow_test.sh +++ b/scripts/capture_shadow_test.sh @@ -18,7 +18,7 @@ case "${out_path,,}" in esac mkdir -p "$(dirname "$out_path")" -nix develop --command zig build run \ +devenv shell --profile graphics -- zig build run \ -Dshadow-test-scene=true \ -Dshadow-test-variant="$variant" \ -Dscreenshot-path="$out_path" \ diff --git a/scripts/run_benchmark.sh b/scripts/run_benchmark.sh index 29ad657a..e7703bb8 100755 --- a/scripts/run_benchmark.sh +++ b/scripts/run_benchmark.sh @@ -119,7 +119,7 @@ for preset in "${preset_list[@]}"; do if [[ -n "${IN_NIX_SHELL:-}" ]]; then env "${benchmark_env[@]}" timeout --preserve-status "${per_preset_timeout}s" "${benchmark_cmd[@]}" else - env "${benchmark_env[@]}" timeout --preserve-status "${per_preset_timeout}s" nix develop --command "${benchmark_cmd[@]}" + env "${benchmark_env[@]}" timeout --preserve-status "${per_preset_timeout}s" devenv shell --profile graphics -- "${benchmark_cmd[@]}" fi python3 "$(dirname "$0")/benchmark_baseline.py" validate-result "$output_file" python3 "$(dirname "$0")/benchmark_baseline.py" stamp-compact "$output_file" "$compact_mode" diff --git a/scripts/run_phase5_visual_smoke.sh b/scripts/run_phase5_visual_smoke.sh index 9b95fbfb..27186803 100644 --- a/scripts/run_phase5_visual_smoke.sh +++ b/scripts/run_phase5_visual_smoke.sh @@ -60,7 +60,7 @@ capture() { ZIGCRAFT_LOD_GPU_CULLING_VALIDATE="$gpu_culling" \ ZIGCRAFT_DISABLE_LOD_MDI="$disable_lod_mdi" \ ZIGCRAFT_PHASE5_SETTLE_FRAMES="${PHASE5_VISUAL_SETTLE_FRAMES:-180}" \ - timeout --preserve-status "$timeout_budget" nix develop --command zig build run \ + timeout --preserve-status "$timeout_budget" devenv shell --profile graphics -- zig build run \ -Dskip-present \ -Dauto-preset=low \ -Dauto-world=flat \ From b92a9ac94c6fab053c488e4133635c6ca644d40e Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 10:29:43 +0100 Subject: [PATCH 07/12] docs: migrate all docs, skills, and prompts from nix to devenv Phase 4. Mechanical sweep of every developer-facing instruction file, replacing 'nix develop --command ' with 'devenv shell ' (and the CI-specific forms 'nix develop .#ci-unit/.#ci-graphics --command' with 'devenv shell --profile unit/graphics --'). Touched: AGENTS.md, README.md, CONTRIBUTING.md, docs/ (ci-test-guardrails, profiling, visual-test, benchmarks, lighting-phase0-baselines, ui-architecture, worldgen-biomes-and-terrain, lod-water-and-latency-steering-752, platform-ci), four headless-* agent skills, test-writer skill, pr-autopilot skill, both opencode commands, and the three .github/prompts review/audit/test-writer prompts. Prose adjusted where 'Nix'/'flake' appeared: README troubleshooting now references 'devenv update' instead of 'nix-channel --update'; CONTRIBUTING prerequisites list Nix + devenv + optional direnv; AGENTS.md intro now describes the unit/graphics profiles; capability blurbs say 'devenv' where they previously said 'Nix'. Remaining 'Nix' mentions are the accurate 'Nix-based'/'required by devenv' qualifiers. Signed-off-by: MichaelFisher1997 --- .agents/skills/headless-benchmark/SKILL.md | 12 ++--- .agents/skills/headless-crash-test/SKILL.md | 8 +-- .../headless-graphics-verification/SKILL.md | 12 ++--- .agents/skills/headless-screenshot/SKILL.md | 8 +-- .agents/skills/test-writer/SKILL.md | 28 +++++----- .github/prompts/audit.md | 14 ++--- .github/prompts/pr-review.md | 10 ++-- .github/prompts/test-writer.md | 14 ++--- .opencode/commands/issue-to-green-pr.md | 4 +- .opencode/commands/issue-to-pr.md | 4 +- .opencode/skills/pr-autopilot/SKILL.md | 12 ++--- AGENTS.md | 30 +++++------ CONTRIBUTING.md | 32 +++++------ README.md | 54 +++++++++---------- docs/benchmarks/README.md | 6 +-- docs/ci-test-guardrails.md | 6 +-- docs/lighting-phase0-baselines.md | 2 +- docs/lod-water-and-latency-steering-752.md | 2 +- docs/platform-ci.md | 2 +- docs/profiling.md | 2 +- docs/ui-architecture.md | 4 +- docs/visual-test/README.md | 2 +- docs/worldgen-biomes-and-terrain.md | 8 +-- 23 files changed, 139 insertions(+), 137 deletions(-) diff --git a/.agents/skills/headless-benchmark/SKILL.md b/.agents/skills/headless-benchmark/SKILL.md index 0438a8a0..c1ab2218 100644 --- a/.agents/skills/headless-benchmark/SKILL.md +++ b/.agents/skills/headless-benchmark/SKILL.md @@ -9,7 +9,7 @@ You run repeatable ZigCraft performance benchmarks without showing a window or s ## Hard Rules -- Always wrap commands in `nix develop --command`. +- Always wrap commands in `devenv shell`. - Always set a Bash tool timeout longer than the benchmark duration. Never run benchmarks without a timeout. - Use `zig build benchmark`; it is configured for offscreen graphics rendering and skip-present behavior. - Use `-Dbenchmark-preset=` when comparing graphics presets. Valid presets are `low`, `medium`, `high`, `ultra`, and `extreme`. @@ -21,7 +21,7 @@ You run repeatable ZigCraft performance benchmarks without showing a window or s Short smoke benchmark: ```bash -nix develop --command zig build benchmark -Dbenchmark-duration=5 -Dbenchmark-output=zig-out/benchmark-smoke.json +devenv shell zig build benchmark -Dbenchmark-duration=5 -Dbenchmark-output=zig-out/benchmark-smoke.json ``` Recommended Bash timeout: `60000` ms. @@ -29,7 +29,7 @@ Recommended Bash timeout: `60000` ms. Standard benchmark: ```bash -nix develop --command zig build benchmark -Dbenchmark-preset=medium -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-medium.json +devenv shell zig build benchmark -Dbenchmark-preset=medium -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-medium.json ``` Recommended Bash timeout: `120000` ms. @@ -37,7 +37,7 @@ Recommended Bash timeout: `120000` ms. Low preset benchmark: ```bash -nix develop --command zig build benchmark -Dbenchmark-preset=low -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-low.json +devenv shell zig build benchmark -Dbenchmark-preset=low -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-low.json ``` Recommended Bash timeout: `120000` ms. @@ -45,7 +45,7 @@ Recommended Bash timeout: `120000` ms. High preset benchmark: ```bash -nix develop --command zig build benchmark -Dbenchmark-preset=high -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-high.json +devenv shell zig build benchmark -Dbenchmark-preset=high -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-high.json ``` Recommended Bash timeout: `120000` ms. @@ -53,7 +53,7 @@ Recommended Bash timeout: `120000` ms. Release-style benchmark build: ```bash -nix develop --command zig build benchmark -Doptimize=ReleaseFast -Dbenchmark-preset=high -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-high-release.json +devenv shell zig build benchmark -Doptimize=ReleaseFast -Dbenchmark-preset=high -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-high-release.json ``` Recommended Bash timeout: `180000` ms. diff --git a/.agents/skills/headless-crash-test/SKILL.md b/.agents/skills/headless-crash-test/SKILL.md index 92f34741..9706bd1c 100644 --- a/.agents/skills/headless-crash-test/SKILL.md +++ b/.agents/skills/headless-crash-test/SKILL.md @@ -9,7 +9,7 @@ You are validating ZigCraft runtime stability in the background without disrupti ## Hard Rules -- Always wrap commands in `nix develop --command`. +- Always wrap commands in `devenv shell`. - Always set a Bash tool timeout. Never run an open-ended game command without a timeout. - Prefer `-Dskip-present` for runtime checks. It keeps full offscreen graphics rendering active while hiding the SDL window and skipping presentation. - Do not use visible monitor-placement flags for crash testing unless the user explicitly asks for a visible window. @@ -20,7 +20,7 @@ You are validating ZigCraft runtime stability in the background without disrupti Use this for a quick startup and world-load crash check: ```bash -nix develop --command zig build run -Dskip-present -Dauto-world=normal -Dstartup-diagnostic-seconds=5 +devenv shell zig build run -Dskip-present -Dauto-world=normal -Dstartup-diagnostic-seconds=5 ``` Recommended Bash timeout: `30000` ms. @@ -28,7 +28,7 @@ Recommended Bash timeout: `30000` ms. Use this for a longer stability check: ```bash -nix develop --command zig build run -Dskip-present -Dauto-world=normal -Dstartup-diagnostic-seconds=30 +devenv shell zig build run -Dskip-present -Dauto-world=normal -Dstartup-diagnostic-seconds=30 ``` Recommended Bash timeout: `60000` ms. @@ -36,7 +36,7 @@ Recommended Bash timeout: `60000` ms. Use this for the automated smoke mode: ```bash -nix develop --command zig build run -Dskip-present -Dsmoke-test +devenv shell zig build run -Dskip-present -Dsmoke-test ``` Recommended Bash timeout: `60000` ms. diff --git a/.agents/skills/headless-graphics-verification/SKILL.md b/.agents/skills/headless-graphics-verification/SKILL.md index 7a85c349..ece9ec6d 100644 --- a/.agents/skills/headless-graphics-verification/SKILL.md +++ b/.agents/skills/headless-graphics-verification/SKILL.md @@ -9,7 +9,7 @@ You verify graphics-related changes safely in the background using offscreen ren ## Hard Rules -- Always wrap commands in `nix develop --command`. +- Always wrap commands in `devenv shell`. - Always set Bash tool timeouts for every run command. - Use `-Dskip-present` for any command that launches the game unless the user explicitly requests a visible window. - Run `zig build test` for shader validation after shader or graphics code changes. @@ -20,7 +20,7 @@ You verify graphics-related changes safely in the background using offscreen ren Format changed Zig files: ```bash -nix develop --command zig fmt +devenv shell zig fmt ``` Recommended Bash timeout: `120000` ms. @@ -28,7 +28,7 @@ Recommended Bash timeout: `120000` ms. Build offscreen graphics mode: ```bash -nix develop --command zig build -Dskip-present +devenv shell zig build -Dskip-present ``` Recommended Bash timeout: `120000` ms. @@ -36,7 +36,7 @@ Recommended Bash timeout: `120000` ms. Run unit tests and shader validation: ```bash -nix develop --command zig build test +devenv shell zig build test ``` Recommended Bash timeout: `120000` ms. @@ -44,7 +44,7 @@ Recommended Bash timeout: `120000` ms. Run a bounded offscreen world-load check: ```bash -nix develop --command zig build run -Dskip-present -Dauto-world=normal -Dstartup-diagnostic-seconds=5 +devenv shell zig build run -Dskip-present -Dauto-world=normal -Dstartup-diagnostic-seconds=5 ``` Recommended Bash timeout: `30000` ms. @@ -52,7 +52,7 @@ Recommended Bash timeout: `30000` ms. Run a quick offscreen benchmark if performance may be affected: ```bash -nix develop --command zig build benchmark -Dbenchmark-duration=5 -Dbenchmark-output=zig-out/benchmark-smoke.json +devenv shell zig build benchmark -Dbenchmark-duration=5 -Dbenchmark-output=zig-out/benchmark-smoke.json ``` Recommended Bash timeout: `60000` ms. diff --git a/.agents/skills/headless-screenshot/SKILL.md b/.agents/skills/headless-screenshot/SKILL.md index c180afe0..6fa1dab2 100644 --- a/.agents/skills/headless-screenshot/SKILL.md +++ b/.agents/skills/headless-screenshot/SKILL.md @@ -9,7 +9,7 @@ You capture visual output from ZigCraft without opening a visible game window. ## Hard Rules -- Always wrap commands in `nix develop --command`. +- Always wrap commands in `devenv shell`. - Always set a Bash tool timeout. Screenshot commands can hang if rendering or world loading stalls. - Always include `-Dskip-present` unless the user explicitly requests a visible capture. - Use deterministic launch flags where possible (`-Dauto-world=normal`, `-Dshadow-test-scene`, or other existing scenario flags). @@ -20,7 +20,7 @@ You capture visual output from ZigCraft without opening a visible game window. General world screenshot: ```bash -nix develop --command zig build run -Dskip-present -Dauto-world=normal -Dscreenshot-path=screenshots/headless-capture.png -Dscreenshot-frame=120 +devenv shell zig build run -Dskip-present -Dauto-world=normal -Dscreenshot-path=screenshots/headless-capture.png -Dscreenshot-frame=120 ``` Recommended Bash timeout: `90000` ms. @@ -28,7 +28,7 @@ Recommended Bash timeout: `90000` ms. Delayed capture after world load: ```bash -nix develop --command zig build run -Dskip-present -Dauto-world=normal -Dscreenshot-path=screenshots/headless-capture.png -Dscreenshot-frame=180 -Dscreenshot-delay-seconds=3 +devenv shell zig build run -Dskip-present -Dauto-world=normal -Dscreenshot-path=screenshots/headless-capture.png -Dscreenshot-frame=180 -Dscreenshot-delay-seconds=3 ``` Recommended Bash timeout: `120000` ms. @@ -36,7 +36,7 @@ Recommended Bash timeout: `120000` ms. Shadow test scene capture: ```bash -nix develop --command zig build run -Dskip-present -Dshadow-test-scene -Dscreenshot-path=screenshots/shadow-test.png -Dscreenshot-frame=180 +devenv shell zig build run -Dskip-present -Dshadow-test-scene -Dscreenshot-path=screenshots/shadow-test.png -Dscreenshot-frame=180 ``` Recommended Bash timeout: `120000` ms. diff --git a/.agents/skills/test-writer/SKILL.md b/.agents/skills/test-writer/SKILL.md index e264b1fe..60007201 100644 --- a/.agents/skills/test-writer/SKILL.md +++ b/.agents/skills/test-writer/SKILL.md @@ -13,7 +13,7 @@ ZigCraft is a high-performance Minecraft-style voxel engine built with: - **Zig 0.16+** with strict memory management (explicit allocators, defer/errdefer) - **SDL3** for windowing and input - **Vulkan** for rendering (only backend, via RHI abstraction) -- **Nix** for reproducible builds (`nix develop --command zig build`) +- **devenv** for reproducible builds (`devenv shell zig build`) - **GLSL shaders** validated via glslangValidator - **Custom job system** for multithreaded world generation and meshing @@ -21,11 +21,11 @@ ZigCraft is a high-performance Minecraft-style voxel engine built with: | Command | Purpose | |---|---| -| `nix develop --command zig build test` | Unit tests + shader validation | -| `nix develop --command zig fmt src/ modules/` | Format code | -| `nix develop --command zig build test -- --test-filter "test name"` | Verify a specific new test is discovered and runnable | -| `nix develop --command zig build test-integration` | Integration smoke tests for game/graphics/runtime-adjacent changes | -| `nix develop --command zig build -Doptimize=ReleaseFast` | Release build | +| `devenv shell zig build test` | Unit tests + shader validation | +| `devenv shell zig fmt src/ modules/` | Format code | +| `devenv shell zig build test -- --test-filter "test name"` | Verify a specific new test is discovered and runnable | +| `devenv shell zig build test-integration` | Integration smoke tests for game/graphics/runtime-adjacent changes | +| `devenv shell zig build -Doptimize=ReleaseFast` | Release build | ### Project Structure (testing-relevant) @@ -198,9 +198,9 @@ You are running inside the opencode GitHub Action. The infrastructure auto-creat 1. Write your test files 2. Register new test files in `src/tests.zig` -3. Format: `nix develop --command zig fmt src/ modules/` -4. Run tests: `nix develop --command zig build test` โ€” ALL tests must pass, not just yours -5. Run at least one new test by filter: `nix develop --command zig build test -- --test-filter ""` +3. Format: `devenv shell zig fmt src/ modules/` +4. Run tests: `devenv shell zig build test` โ€” ALL tests must pass, not just yours +5. Run at least one new test by filter: `devenv shell zig build test -- --test-filter ""` 6. Self-review the diff and remove any fake, tautological, misleading, or unsafe test before committing 7. Count actual added `test "..."` declarations from your diff and keep the run within 3-8 total new tests 8. Commit your changes with message: `test: add {area} tests for {module}` @@ -214,11 +214,11 @@ The infrastructure will push the branch and create the PR automatically. - Tests MUST pass before committing. This is non-negotiable. - A filtered run for at least one newly added test MUST pass before committing. - The new tests MUST be semantically analyzed and executed by `zig build test`; do not rely on registrations that hide test blocks from the test runner. -- Format before commit: `nix develop --command zig fmt src/ modules/`. +- Format before commit: `devenv shell zig fmt src/ modules/`. - 3-8 tests per run across the whole PR, not per file. Quality over quantity. - If the module has no testable logic, stop without committing and note limitations. - Skip if nothing to test โ€” do not create trivial tests just to create a PR. -- For game, graphics, windowing-adjacent, or runtime initialization tests, run `nix develop --command zig build test-integration` when feasible and report if it was not feasible. +- For game, graphics, windowing-adjacent, or runtime initialization tests, run `devenv shell zig build test-integration` when feasible and report if it was not feasible. ## Stop Conditions @@ -260,8 +260,8 @@ The PR body should follow this format: - Functions or paths that still need tests and why ## Verification -- [x] `nix develop --command zig fmt src/ modules/` passes -- [x] `nix develop --command zig build test` passes (all tests, not just new ones) -- [x] `nix develop --command zig build test -- --test-filter "..."` passes for a newly added test +- [x] `devenv shell zig fmt src/ modules/` passes +- [x] `devenv shell zig build test` passes (all tests, not just new ones) +- [x] `devenv shell zig build test -- --test-filter "..."` passes for a newly added test - [x] No non-test source files were modified ``` diff --git a/.github/prompts/audit.md b/.github/prompts/audit.md index 3194c2cc..828db148 100644 --- a/.github/prompts/audit.md +++ b/.github/prompts/audit.md @@ -14,7 +14,7 @@ Perform a thorough audit of the `$MODULE_PATH/` directory in this codebase. Your **YOU MUST ONLY:** - Read source code files to understand the codebase -- Run read-only commands (`ls`, `cat`, `gh issue list`, `gh pr list`, `nix develop --command zig build test`) +- Run read-only commands (`ls`, `cat`, `gh issue list`, `gh pr list`, `devenv shell zig build test`) - Create EXACTLY ONE GitHub issue using `gh issue create` If you violate these rules, your output will be automatically reverted. No exceptions. @@ -31,14 +31,14 @@ ZigCraft is a high-performance Minecraft-style voxel engine built with: - **Zig 0.16+** with strict memory management (explicit allocators, defer/errdefer) - **SDL3** for windowing and input - **Vulkan** for rendering (only backend, via RHI abstraction) -- **Nix** for reproducible builds (`nix develop --command zig build`) +- **devenv** for reproducible builds (`devenv shell zig build`) - **GLSL shaders** validated via glslangValidator - **Custom job system** for multithreaded world generation and meshing Build commands available: -- `nix develop --command zig build test` โ€” unit tests + shader validation -- `nix develop --command zig fmt src/` โ€” format code -- `nix develop --command zig build -Doptimize=ReleaseFast` โ€” release build +- `devenv shell zig build test` โ€” unit tests + shader validation +- `devenv shell zig fmt src/` โ€” format code +- `devenv shell zig build -Doptimize=ReleaseFast` โ€” release build ## MODULE-SPECIFIC FOCUS @@ -89,7 +89,7 @@ Prioritize by impact. Check for: 2. Read each source file in the module, starting with the most critical ones (those dealing with GPU resources, memory, or concurrency) 3. For each file, trace the data flow: how are resources created, used, and destroyed? 4. Cross-reference with other modules if needed (e.g., check if callers of a function handle errors correctly) -5. If possible, run `nix develop --command zig build test` to check if existing tests pass +5. If possible, run `devenv shell zig build test` to check if existing tests pass 6. If you find a concrete issue, verify it by reading surrounding code to confirm it's a real problem, not a false positive ## ISSUE FORMAT @@ -138,7 +138,7 @@ Example criteria: - "All unit tests in `src/tests.zig` pass" - "No memory leaks detected when running with `zig build test`" - "The function returns correct results for edge cases: empty input, max values, negative values" -- "The fix has been verified with `nix develop --command zig build test`" +- "The fix has been verified with `devenv shell zig build test`" ## ๐Ÿ“š References - Link to any related issues, docs, or Zig standard library patterns that are relevant. diff --git a/.github/prompts/pr-review.md b/.github/prompts/pr-review.md index 8448c6f5..87d751a4 100644 --- a/.github/prompts/pr-review.md +++ b/.github/prompts/pr-review.md @@ -5,19 +5,19 @@ Use `gh pr diff $PR_NUMBER` and `gh pr view $PR_NUMBER` to examine the changes. Give full review coverage to PRs created by the automated test writer, especially PRs labeled `automated-test`, and verify whether any linked issues are fully addressed. -ZigCraft is a high-performance Minecraft-style voxel engine built with Zig, SDL3, and Vulkan. It uses Nix for dependency management, a custom RHI (Render Hardware Interface) abstraction layer, and a multithreaded job system for world generation and meshing. +ZigCraft is a high-performance Minecraft-style voxel engine built with Zig, SDL3, and Vulkan. It uses devenv for dependency management, a custom RHI (Render Hardware Interface) abstraction layer, and a multithreaded job system for world generation and meshing. **Tech Stack:** - Zig 0.16+ with strict memory management (explicit allocators, defer/errdefer) - SDL3 for windowing and input - Vulkan for rendering (only backend, via RHI abstraction) -- Nix for reproducible builds (`nix develop --command zig build`) +- devenv for reproducible builds (`devenv shell zig build`) - GLSL shaders validated via glslangValidator **Build Commands:** -- `nix develop --command zig build test` - Unit tests + shader validation -- `nix develop --command zig build test -- --test-filter "test name"` - Single test -- `nix develop --command zig fmt src/` - Format code +- `devenv shell zig build test` - Unit tests + shader validation +- `devenv shell zig build test -- --test-filter "test name"` - Single test +- `devenv shell zig fmt src/` - Format code **Prioritize review attention on:** - RHI/Vulkan correctness (buffer/texture handles, pipeline state, synchronization) diff --git a/.github/prompts/test-writer.md b/.github/prompts/test-writer.md index be9a3f6a..9f05e623 100644 --- a/.github/prompts/test-writer.md +++ b/.github/prompts/test-writer.md @@ -34,9 +34,9 @@ Also read existing nearby `*_tests.zig` files and the owning module `root.zig`/t Do not commit if any of these are true: -1. `nix develop --command zig build test` fails. +1. `devenv shell zig build test` fails. 2. The new test file is not actually discovered by `zig build test`. -3. A newly added test cannot be run by name with `nix develop --command zig build test -- --test-filter ""`. +3. A newly added test cannot be run by name with `devenv shell zig build test -- --test-filter ""`. 4. Any test depends on a real GPU, real Vulkan device, SDL window, display server, network, wall-clock timing, or nondeterministic scheduler behavior. 5. Any test calls Vulkan destroy/create/submit functions with null or fake handles unless the production function guarantees it returns before the Vulkan call. 6. The tests require modifying production code only to make private implementation details public. @@ -121,12 +121,12 @@ If review would reasonably return `MERGE WITH FIXES` or `DO NOT MERGE`, fix the ## VERIFICATION COMMANDS -Run all commands through Nix. +Run all commands through devenv. -1. Format: `nix develop --command zig fmt src/ modules/` -2. Run all unit tests: `nix develop --command zig build test` -3. Run at least one newly added test by exact or narrow filter: `nix develop --command zig build test -- --test-filter ""` -4. For tests touching game, graphics, windowing-adjacent, or runtime initialization code, also run: `nix develop --command zig build test-integration` +1. Format: `devenv shell zig fmt src/ modules/` +2. Run all unit tests: `devenv shell zig build test` +3. Run at least one newly added test by exact or narrow filter: `devenv shell zig build test -- --test-filter ""` +4. For tests touching game, graphics, windowing-adjacent, or runtime initialization code, also run: `devenv shell zig build test-integration` If `test-integration` is not feasible in the GitHub Action environment, do not guess. State the exact reason in the final message, but still require `zig build test` and the filtered test to pass before commit. diff --git a/.opencode/commands/issue-to-green-pr.md b/.opencode/commands/issue-to-green-pr.md index 424f4038..0285399b 100644 --- a/.opencode/commands/issue-to-green-pr.md +++ b/.opencode/commands/issue-to-green-pr.md @@ -13,8 +13,8 @@ Use this workflow: 3. Inspect the relevant code before editing. Preserve existing behavior outside the issue scope. 4. Implement everything needed to satisfy the issue, using the smallest correct changes. 5. Add or update tests when the change has testable behavior. -6. Format changed Zig files with `nix develop --command zig fmt `. -7. Sanity check with the most relevant commands, including `nix develop --command zig build test` unless there is a clear reason to run a narrower or broader verification. +6. Format changed Zig files with `devenv shell zig fmt `. +7. Sanity check with the most relevant commands, including `devenv shell zig build test` unless there is a clear reason to run a narrower or broader verification. 8. Create a branch if needed, commit the relevant changes with a conventional commit message, and open a pull request targeting `dev`. 9. Include `Fixes #` in the PR body so GitHub links and auto-closes the implemented issue when the PR merges. 10. Load and follow the `pr-autopilot` skill for the created PR. diff --git a/.opencode/commands/issue-to-pr.md b/.opencode/commands/issue-to-pr.md index f4e368ba..785068c0 100644 --- a/.opencode/commands/issue-to-pr.md +++ b/.opencode/commands/issue-to-pr.md @@ -13,8 +13,8 @@ Use this workflow: 3. Inspect the relevant code before editing. Preserve existing behavior outside the issue scope. 4. Implement everything needed to satisfy the issue, using the smallest correct changes. 5. Add or update tests when the change has testable behavior. -6. Format changed Zig files with `nix develop --command zig fmt `. -7. Sanity check with the most relevant commands, including `nix develop --command zig build test` unless there is a clear reason to run a narrower or broader verification. +6. Format changed Zig files with `devenv shell zig fmt `. +7. Sanity check with the most relevant commands, including `devenv shell zig build test` unless there is a clear reason to run a narrower or broader verification. 8. Create a branch if needed, commit the relevant changes with a conventional commit message, and open a pull request targeting `dev`. 9. Include `Fixes #` in the PR body so GitHub links and auto-closes the implemented issue when the PR merges. 10. Return the PR URL and a concise summary of the implementation and verification results. diff --git a/.opencode/skills/pr-autopilot/SKILL.md b/.opencode/skills/pr-autopilot/SKILL.md index 3c403094..362a23f6 100644 --- a/.opencode/skills/pr-autopilot/SKILL.md +++ b/.opencode/skills/pr-autopilot/SKILL.md @@ -17,7 +17,7 @@ Use this skill after creating a PR, or when the user explicitly asks you to moni - Do not use force push unless the user explicitly approves it. - Do not skip hooks or checks unless the user explicitly approves it. - Do not modify unrelated user changes in the worktree. -- Run all Zig build/test commands through `nix develop --command`. +- Run all Zig build/test commands through `devenv shell`. - Continue the loop until the PR is green and merged, or until blocked by permissions, merge conflicts requiring user judgment, missing secrets, unavailable runners, or an explicitly failing external requirement you cannot fix. - As soon as GitHub reports the PR is merged, stop immediately and ignore any still-running runners/checks for that PR. - Only enable or perform auto-merge when the user requested autonomous merge behavior for this PR or workflow. @@ -71,16 +71,16 @@ For failed checks: For ZigCraft, default verification includes: ```bash -nix develop --command zig fmt src/ -nix develop --command zig build test +devenv shell zig fmt src/ +devenv shell zig build test ``` Use additional checks when relevant: ```bash -nix develop --command zig build -Doptimize=ReleaseFast -nix develop --command zig build test-integration -nix develop --command zig build test-robustness +devenv shell zig build -Doptimize=ReleaseFast +devenv shell zig build test-integration +devenv shell zig build test-robustness ``` For runtime, graphics, screenshot, or benchmark failures, load the matching project skill: diff --git a/AGENTS.md b/AGENTS.md index e8a61990..b7822dc8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,31 +2,31 @@ ## Toolchain and commands -- Use Zig 0.16.0 through Nix. Wrap every Zig build/test/format command in `nix develop --command`; CI uses the narrower `.#ci-unit` and `.#ci-graphics` shells. +- Use Zig 0.16.0 through devenv. Wrap every Zig build/test/format command in `devenv shell`; CI uses the narrower `--profile unit` and `--profile graphics` profiles. - Build/run: ```bash - nix develop --command zig build - nix develop --command zig build run - nix develop --command zig build -Doptimize=ReleaseFast + devenv shell zig build + devenv shell zig build run + devenv shell zig build -Doptimize=ReleaseFast ``` - Format all Zig code, not only `src/` (the local hook is less strict than CI): ```bash - nix develop --command zig fmt src/ modules/ - nix develop --command zig fmt --check src/ modules/ + devenv shell zig fmt src/ modules/ + devenv shell zig fmt --check src/ modules/ ``` - `zig build test` is the broad suite: aggregate/module tests, fuzz roots, shader compilation/validation, SPIR-V size checks, shadow ABI checks, and Phase 5 policy tests. ```bash - nix develop --command zig build test - nix develop --command zig build test -Dtest-filter="name" + devenv shell zig build test + devenv shell zig build test -Dtest-filter="name" # Equivalent runtime-filter form: - nix develop --command zig build test -- --test-filter "name" + devenv shell zig build test -- --test-filter "name" ``` - Graphics/runtime verification is separate: ```bash - nix develop --command zig build test-integration -Dskip-present=true - nix develop --command zig build test-robustness - nix develop --command zig build phase5-gate - nix develop --command zig build phase5-visual-gate + devenv shell zig build test-integration -Dskip-present=true + devenv shell zig build test-robustness + devenv shell zig build phase5-gate + devenv shell zig build phase5-visual-gate ``` - `-Dskip-present=true` only suppresses presentation; SDL/Vulkan initialization still needs a display/compositor and driver. Use the repo skills `headless-crash-test`, `headless-screenshot`, `headless-benchmark`, or `headless-graphics-verification`, and always bound game/graphics commands with a timeout. - For deterministic startup checks, combine `-Dskip-present`, `-Dauto-world=`, and `-Dstartup-diagnostic-seconds=N`. `-Dchunk-debug-mode` disables LOD, water, caves, and decorations; selectively restore `lod,water,watergen,waterrender,caves,decorations` with `-Dchunk-debug-enable=`. @@ -35,12 +35,12 @@ - The benchmark harness is a separate build step; do not pass benchmark presets to ordinary `run` and assume benchmarking is active: ```bash - nix develop --command zig build benchmark -Doptimize=ReleaseFast \ + devenv shell zig build benchmark -Doptimize=ReleaseFast \ -Dbenchmark-preset=low -Dbenchmark-scenario=traversal \ -Dbenchmark-duration=60 -Dbenchmark-output=zig-out/benchmark-low.json ``` Scenarios are `stationary`, `traversal`, `rapid-turn`, and `teleport-eviction`. Prefer the `headless-benchmark` skill for bounded runs. -- Focused CPU-only tools: `nix develop --command zig build worldgen-report` and `nix develop --command zig build lod-bench`. Pass climate snapshot arguments after `--`, e.g. `nix develop --command zig build worldgen-climate-snapshot -- --seed 42 ...`. +- Focused CPU-only tools: `devenv shell zig build worldgen-report` and `devenv shell zig build lod-bench`. Pass climate snapshot arguments after `--`, e.g. `devenv shell zig build worldgen-climate-snapshot -- --seed 42 ...`. - Building/tests compile GLSL and write tracked `*.spv` files beside sources in `assets/shaders/vulkan/`. After intentional shader-size changes, run `./scripts/update_spirv_baseline.sh`; `docs/shaders/spirv-sizes.json` and shadow runtime SPIR-V parity are test-enforced. - New/changed textures go through `./scripts/process_textures.sh 512`; preserve licensing/attribution for placeholder assets. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aee2ef76..f4f3641e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,9 @@ Thank you for your interest in contributing to ZigCraft! This is primarily a sol ## Quick Start ### Prerequisites -- Nix package manager (installed via [NixOS](https://nixos.org/) or [Determinate Nix Installer](https://github.com/DeterminateSystems/nix-installer)) +- Nix package manager (installed via [NixOS](https://nixos.org/) or [Determinate Nix Installer](https://github.com/DeterminateSystems/nix-installer)) โ€” required by devenv +- [devenv](https://devenv.sh/getting-started/) (`nix profile add nixpkgs#devenv`) +- [direnv](https://direnv.net/) (optional; auto-activates the shell on `cd`) - Git ### First-Time Setup @@ -29,7 +31,7 @@ git clone https://github.com/OpenStaticFish/ZigCraft.git cd ZigCraft # Enter dev environment -nix develop +devenv shell # Build and run tests zig build test @@ -39,18 +41,18 @@ zig build test ## Development Environment -The project uses Nix for reproducible builds. All commands must be run with `nix develop --command`. +The project uses devenv (Nix-based) for reproducible builds. All commands must be run with `devenv shell`. ### Build & Run ```bash # Build -nix develop --command zig build +devenv shell zig build # Run -nix develop --command zig build run +devenv shell zig build run # Release build (optimized) -nix develop --command zig build -Doptimize=ReleaseFast +devenv shell zig build -Doptimize=ReleaseFast # Clean build artifacts rm -rf zig-out/ .zig-cache/ @@ -59,22 +61,22 @@ rm -rf zig-out/ .zig-cache/ ### Testing ```bash # Run all unit tests (also validates Vulkan shaders) -nix develop --command zig build test +devenv shell zig build test # Run a specific test -nix develop --command zig build test -- --test-filter "Vec3 addition" +devenv shell zig build test -- --test-filter "Vec3 addition" # Integration test (window init smoke test) -nix develop --command zig build test-integration +devenv shell zig build test-integration ``` ### Linting & Formatting ```bash # Format code -nix develop --command zig fmt src/ +devenv shell zig fmt src/ # Fast type-check (no full compilation) -nix develop --command zig build check +devenv shell zig build check ``` ### Asset Processing @@ -142,10 +144,10 @@ Follow the coding conventions in [Code Style](#code-style) below. The [AGENTS.md ```bash # Format your code before committing -nix develop --command zig fmt src/ +devenv shell zig fmt src/ # Run tests -nix develop --command zig build test +devenv shell zig build test ``` ### 3. Commit Changes @@ -266,10 +268,10 @@ For full coding guidelines, see [AGENTS.md](AGENTS.md) (internal AI agent refere ### Before Committing ```bash # Format code -nix develop --command zig fmt src/ +devenv shell zig fmt src/ # Run all tests -nix develop --command zig build test +devenv shell zig build test ``` ### Test Coverage diff --git a/README.md b/README.md index fb24937e..58fd188c 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Optimized for high chunk render distances with greedy meshing, job-based multith ## ๐Ÿ—๏ธ Build & Run -This project uses **Nix** for a reproducible development environment. +This project uses **devenv** (Nix-based) for a reproducible development environment. ### ๐Ÿ› ๏ธ Development Setup @@ -98,23 +98,23 @@ This configures a pre-push hook that runs: To bypass in emergencies: `git push --no-verify` ### ๐ŸŽฎ Running the Game -- **Run**: `nix develop --command zig build run` -- **Release build**: `nix develop --command zig build run -Doptimize=ReleaseFast` +- **Run**: `devenv shell zig build run` +- **Release build**: `devenv shell zig build run -Doptimize=ReleaseFast` ### Debug Build Flags -- **Smoke test**: `nix develop --command zig build run -Dsmoke-test` -- **Headless / no present**: `nix develop --command zig build run -Dskip-present` -- **Headless benchmark**: `nix develop --command zig build benchmark -Dbenchmark-preset=low -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-low.json` -- **Auto-open a world**: `nix develop --command zig build run -Dauto-world=normal` -- **Open on monitor**: `nix develop --command zig build run -Dmonitor-index=1` -- **Open on Hyprland monitor**: `nix develop --command zig build run -Dmonitor-name=DP-2` -- **Force XWayland monitor placement**: `nix develop --command zig build run -Dmonitor-index=1 -Dwindow-video-driver=x11` -- **Background window launch**: `nix develop --command zig build run -Dmonitor-name=DP-2 -Dwindow-video-driver=x11 -Dwindow-no-focus` -- **Startup diagnostic**: `nix develop --command zig build run -Dauto-world=normal -Dstartup-diagnostic-seconds=5 -Dskip-present` -- **Worldgen climate snapshot JSON**: `nix develop --command zig build worldgen-climate-snapshot -- --seed 42 --origin-x -256 --origin-z -256 --width 128 --depth 128 --step 4 --output zig-out/climate-42.json` -- **Worldgen climate heatmap**: `nix develop --command zig build worldgen-climate-snapshot -- --format ppm --field temperature --output zig-out/temperature-42.ppm` -- **Chunk-only debug mode**: `nix develop --command zig build run -Dchunk-debug-mode -Dauto-world=normal` +- **Smoke test**: `devenv shell zig build run -Dsmoke-test` +- **Headless / no present**: `devenv shell zig build run -Dskip-present` +- **Headless benchmark**: `devenv shell zig build benchmark -Dbenchmark-preset=low -Dbenchmark-duration=60 -Dbenchmark-output=benchmark-low.json` +- **Auto-open a world**: `devenv shell zig build run -Dauto-world=normal` +- **Open on monitor**: `devenv shell zig build run -Dmonitor-index=1` +- **Open on Hyprland monitor**: `devenv shell zig build run -Dmonitor-name=DP-2` +- **Force XWayland monitor placement**: `devenv shell zig build run -Dmonitor-index=1 -Dwindow-video-driver=x11` +- **Background window launch**: `devenv shell zig build run -Dmonitor-name=DP-2 -Dwindow-video-driver=x11 -Dwindow-no-focus` +- **Startup diagnostic**: `devenv shell zig build run -Dauto-world=normal -Dstartup-diagnostic-seconds=5 -Dskip-present` +- **Worldgen climate snapshot JSON**: `devenv shell zig build worldgen-climate-snapshot -- --seed 42 --origin-x -256 --origin-z -256 --width 128 --depth 128 --step 4 --output zig-out/climate-42.json` +- **Worldgen climate heatmap**: `devenv shell zig build worldgen-climate-snapshot -- --format ppm --field temperature --output zig-out/temperature-42.ppm` +- **Chunk-only debug mode**: `devenv shell zig build run -Dchunk-debug-mode -Dauto-world=normal` - **Shadow/cave lighting capture**: `./scripts/capture_shadow_test.sh screenshots/shadow-test.png` `-Dchunk-debug-mode` strips the overworld down to basic chunks for isolation work: @@ -135,21 +135,21 @@ Examples: ```bash # LOD only -nix develop --command zig build run -Dchunk-debug-mode -Dchunk-debug-enable=lod -Dauto-world=normal +devenv shell zig build run -Dchunk-debug-mode -Dchunk-debug-enable=lod -Dauto-world=normal # LOD plus cave generation -nix develop --command zig build run -Dchunk-debug-mode -Dchunk-debug-enable=lod,caves -Dauto-world=normal +devenv shell zig build run -Dchunk-debug-mode -Dchunk-debug-enable=lod,caves -Dauto-world=normal # Headless startup comparison after 5 seconds -nix develop --command zig build run -Dchunk-debug-mode -Dchunk-debug-enable=lod,water,caves -Dauto-world=normal -Dstartup-diagnostic-seconds=5 -Dskip-present +devenv shell zig build run -Dchunk-debug-mode -Dchunk-debug-enable=lod,water,caves -Dauto-world=normal -Dstartup-diagnostic-seconds=5 -Dskip-present ``` The shadow/cave lighting capture launches a deterministic low-block test scene, applies a small shadow-focused graphics preset, waits 5 seconds after the target is ready, captures a PNG, and exits. It defaults to a `dug-cave` variant that matches a player-dug dirt/grass cave mouth. Use `ZIGCRAFT_SHADOW_TEST_VARIANT=bend ./scripts/capture_shadow_test.sh screenshots/shadow-bend.png` to check the older bend/deep-black regression. Override the wait with `ZIGCRAFT_SCREENSHOT_DELAY_SECONDS=8 ./scripts/capture_shadow_test.sh screenshots/shadow-test.png`. Screenshot paths are restricted to image extensions from `image/png`, `image/jpeg`, `image/gif`, and `image/webp`; the built-in encoder currently writes PNG. ### ๐Ÿงช Running Tests -- **All Tests**: `nix develop --command zig build test` -- **Single Test**: `nix develop --command zig build test -- --test-filter "Test Name"` -- **Single Test Alternative**: `nix develop --command zig build test -Dtest-filter="Test Name"` +- **All Tests**: `devenv shell zig build test` +- **Single Test**: `devenv shell zig build test -- --test-filter "Test Name"` +- **Single Test Alternative**: `devenv shell zig build test -Dtest-filter="Test Name"` ## ๐Ÿ“‚ Project Structure @@ -196,7 +196,7 @@ cd ZigCraft ./scripts/setup-hooks.sh # Enter dev environment and run tests -nix develop --command zig build test +devenv shell zig build test ``` ### Branch Workflow @@ -214,13 +214,13 @@ All PRs target the `dev` branch. Use our PR templates (`feature.md`, `bug.md`, ` ## ๐Ÿ”ง Troubleshooting -### Nix Build Failures +### devenv Build Failures ```bash # Clean build artifacts rm -rf zig-out/ .zig-cache/ -# Update Nix channels (if using older Nix) -nix-channel --update +# Refresh devenv inputs (updates the pinned nixpkgs) +devenv update ``` ### Vulkan Driver Issues @@ -231,8 +231,8 @@ nix-channel --update ### Shader Validation Errors Shaders are validated during `zig build test`. If glslang fails: ```bash -# Install glslang via Nix -nix develop # glslang is included in the dev shell +# Install glslang via devenv +devenv shell # glslang is included in the dev shell ``` ### Performance Issues diff --git a/docs/benchmarks/README.md b/docs/benchmarks/README.md index eed98a3a..af506a25 100644 --- a/docs/benchmarks/README.md +++ b/docs/benchmarks/README.md @@ -69,7 +69,7 @@ The checked canary and acceptance baselines were captured on: - Runner label: `local NixOS x86_64` - GPU: `AMD Radeon RX 5700 XT` - Graphics driver: Mesa RADV 25.2.6 -- Zig version: `0.16.0`, provided by the Nix flake +- Zig version: `0.16.0`, provided by the devenv profile - Build mode: `ReleaseFast` - Presets: `low`, `medium`, `high` - `baseline.json`: 5 sampled seconds per row after readiness @@ -284,7 +284,7 @@ present in the artifact rather than being hidden. Run the lightweight policy gate with: ```bash -nix develop --command zig build phase5-gate +devenv shell zig build phase5-gate ``` It verifies that the build accepts exactly the four scenarios above (and rejects @@ -310,7 +310,7 @@ override its broad health thresholds only for diagnosed platform differences wit Run only this slower graphics check with: ```bash -nix develop --command zig build phase5-visual-gate +devenv shell zig build phase5-visual-gate ``` ## Automated motion captures diff --git a/docs/ci-test-guardrails.md b/docs/ci-test-guardrails.md index 2d89e085..7a0da933 100644 --- a/docs/ci-test-guardrails.md +++ b/docs/ci-test-guardrails.md @@ -7,7 +7,7 @@ Pull requests run `zig build test` in both `Debug` and `ReleaseSafe` through the Run locally: ```bash -nix develop --command zig build -Doptimize=ReleaseSafe test +devenv shell zig build -Doptimize=ReleaseSafe test ``` ## Coverage @@ -17,7 +17,7 @@ The `Coverage` workflow runs kcov against the unit suite, uploads the generated Run locally: ```bash -nix develop .#ci-unit --command kcov \ +devenv shell --profile unit -- kcov \ --include-path=src,modules,libs \ --exclude-path=.zig-cache,zig-cache,assets,docs \ coverage/kcov \ @@ -31,7 +31,7 @@ kcov reports line coverage only; branch coverage is not available from this setu The `Sanitize` workflow runs nightly and on `workflow_dispatch` with: ```bash -nix develop --command zig build -Dsanitize=address test +devenv shell zig build -Dsanitize=address test ``` The project is pinned to Zig 0.16.0. That compiler exposes `-fsanitize-c` and `-fsanitize-thread`, but not an LLVM AddressSanitizer build flag through `std.Build`. The repository keeps `-Dsanitize=address` as the CI entrypoint requested by the audit, and currently maps it to Zig's full C undefined-behavior sanitizer support. Failures fail the scheduled workflow check and should be triaged from the uploaded log artifact. diff --git a/docs/lighting-phase0-baselines.md b/docs/lighting-phase0-baselines.md index c3e90821..926a8458 100644 --- a/docs/lighting-phase0-baselines.md +++ b/docs/lighting-phase0-baselines.md @@ -34,7 +34,7 @@ captures outside either bound fail parity review. Record the pre-rewrite high-preset benchmark with: ```bash -nix develop --command zig build benchmark -Doptimize=ReleaseFast \ +devenv shell zig build benchmark -Doptimize=ReleaseFast \ -Dbenchmark-preset=high -Dbenchmark-duration=60 \ -Dbenchmark-output=lighting-phase0-high.json ``` diff --git a/docs/lod-water-and-latency-steering-752.md b/docs/lod-water-and-latency-steering-752.md index 72236165..4f3652fa 100644 --- a/docs/lod-water-and-latency-steering-752.md +++ b/docs/lod-water-and-latency-steering-752.md @@ -108,7 +108,7 @@ timed out in the local environment before useful LOD diagnostics were emitted. ## Verification -- `nix develop --command zig build test` after every change (add the W2 +- `devenv shell zig build test` after every change (add the W2 regression test). - `headless-screenshot` (`-Dskip-present -Dauto-world=normal`): open-ocean view, coastline view, and a shot taken ~3 seconds after load to prove the diff --git a/docs/platform-ci.md b/docs/platform-ci.md index 9367351f..f6bea4de 100644 --- a/docs/platform-ci.md +++ b/docs/platform-ci.md @@ -8,5 +8,5 @@ Known limitations: - Windows is manual build-only until SDL/Vulkan library discovery and a stable headless Vulkan smoke path are available on GitHub-hosted Windows runners. - macOS uses MoltenVK plus the Vulkan loader and is manual build-only until a repeatable headless smoke test is defined for GitHub-hosted macOS runners. -- Optional ImGui linkage remains covered by Linux/Nix CI; non-Linux build-only legs disable it until cimgui package availability is standardized there. +- Optional ImGui linkage remains covered by Linux CI; non-Linux build-only legs disable it until cimgui package availability is standardized there. - Linux/Lavapipe remains the required correctness signal for tests and validation logs. diff --git a/docs/profiling.md b/docs/profiling.md index 6bde5722..b6581a4d 100644 --- a/docs/profiling.md +++ b/docs/profiling.md @@ -5,7 +5,7 @@ The current capture command is: ```bash -nix develop .#ci-graphics --command zig build benchmark -Doptimize=ReleaseFast -Dbenchmark-preset=medium -Dbenchmark-duration=10 -Dbenchmark-output=profiling-artifacts/fixed-world-profile.json +devenv shell --profile graphics -- zig build benchmark -Doptimize=ReleaseFast -Dbenchmark-preset=medium -Dbenchmark-duration=10 -Dbenchmark-output=profiling-artifacts/fixed-world-profile.json ``` Artifacts are uploaded as `profiling-artifacts` and linked from the run summary: diff --git a/docs/ui-architecture.md b/docs/ui-architecture.md index b510c2f5..3e1a5355 100644 --- a/docs/ui-architecture.md +++ b/docs/ui-architecture.md @@ -11,7 +11,7 @@ ZigCraft uses three deliberately separate UI layers: ## Dependency boundary -RmlUi 6.2 is pinned in `flake.nix`. `libs/rmlui_bridge` contains the only C++ +RmlUi 6.2 is pinned in `devenv.nix`. `libs/rmlui_bridge` contains the only C++ integration code and exposes a narrow C ABI to Zig. Feature-off builds do not link the bridge or allocate the retained-geometry Vulkan buffers and pipelines. @@ -62,4 +62,4 @@ HiDPI, clean document teardown, and visual regression captures at 1280x720, The tracked menu golden is invalid because it is black. The comparison script now rejects black inputs. A new golden must not be promoted until the headless capture visibly contains the final player UI and is deterministic under the -`ci-graphics` Nix shell. +`graphics` devenv profile. diff --git a/docs/visual-test/README.md b/docs/visual-test/README.md index 5afcf0a6..918bb66d 100644 --- a/docs/visual-test/README.md +++ b/docs/visual-test/README.md @@ -11,7 +11,7 @@ The tracked `golden/menu.png` is known to be black and is therefore intentionall Capture a candidate through the same path used by CI. Inspect it visually and confirm it is non-black before promoting it: ```bash -nix develop .#ci-graphics --command zig build run -Dskip-present=true -Dscreenshot-path=screenshots/menu-candidate.png +devenv shell --profile graphics -- zig build run -Dskip-present=true -Dscreenshot-path=screenshots/menu-candidate.png magick screenshots/menu-candidate.png -colorspace RGB -format '%[fx:mean]\n' info: ``` diff --git a/docs/worldgen-biomes-and-terrain.md b/docs/worldgen-biomes-and-terrain.md index 59f7d4dd..ec6acd7a 100644 --- a/docs/worldgen-biomes-and-terrain.md +++ b/docs/worldgen-biomes-and-terrain.md @@ -118,15 +118,15 @@ Avoid broad range overlaps unless the priority behavior is intentional and cover For documentation-only changes, no Zig formatting is required. For code or data changes, run formatting on changed Zig files and at least the unit suite: ```bash -nix develop --command zig fmt -nix develop --command zig build test +devenv shell zig fmt +devenv shell zig build test ``` For biome or terrain distribution changes, also compare deterministic reports and snapshots: ```bash -nix develop --command zig build worldgen-report -nix develop --command zig build worldgen-climate-snapshot +devenv shell zig build worldgen-report +devenv shell zig build worldgen-climate-snapshot ``` Use the output from `terrain_report.zig` to inspect representative seed biome counts, height ranges, ocean/land ratio, mountain coverage, and role effect profiles. Use the climate snapshot when climate-space selection boundaries or biome scoring changed. Include intentional baseline changes in the PR description so reviewers know whether distribution movement is expected. From 926b680517885ab0d63bd48e4d7c93f872144023 Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 10:32:50 +0100 Subject: [PATCH 08/12] chore: remove nix flake and setup-nix action Phase 5 (final). Deletes flake.nix, flake.lock, and the now-orphaned .github/actions/setup-nix composite action. The devenv shell, the zigcraft:build task, and all CI workflows/scripts/docs now reference only devenv.nix/devenv.yaml/devenv.lock and the setup-devenv action. Verified post-removal: - 'devenv info' still evaluates and resolves ZIGCRAFT_DYNAMIC_LINKER. - actionlint full-repo scan reports no errors (no dangling setup-nix refs). - grep across all tracked .yml/.yaml/.sh/.md/.zig/.zon/.nix files finds zero residual 'nix develop'/'nix flake'/'nix-channel'/'setup-nix'/'flake-utils' references (CODEBASE_REPORT.md, which is gitignored/generated, excluded). The migration is functionally complete. Remaining 'Nix' mentions in docs are the accurate 'Nix-based'/'required by devenv' qualifiers, since devenv still runs on a Nix daemon. Signed-off-by: MichaelFisher1997 --- .github/actions/setup-nix/action.yml | 57 --- flake.lock | 61 ---- flake.nix | 506 --------------------------- 3 files changed, 624 deletions(-) delete mode 100644 .github/actions/setup-nix/action.yml delete mode 100644 flake.lock delete mode 100644 flake.nix diff --git a/.github/actions/setup-nix/action.yml b/.github/actions/setup-nix/action.yml deleted file mode 100644 index f1f9790f..00000000 --- a/.github/actions/setup-nix/action.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Setup Nix -description: Install Nix with primary/fallback strategy and restore cache - -inputs: - cache-key-prefix: - description: Prefix for the cache primary key - required: false - default: nix - cache-paths: - description: Paths to cache - required: false - default: ~/.cache/nix - -runs: - using: composite - steps: - - name: Mark Nix setup start - shell: bash - run: | - START=$(date +%s) - echo "SETUP_NIX_START=$START" >> "$GITHUB_ENV" - echo "Nix setup start: $(date -u +%Y-%m-%dT%H:%M:%SZ)" - - - name: Install Nix (primary) - id: nix_install_primary - continue-on-error: true - uses: DeterminateSystems/nix-installer-action@v16 - - - name: Install Nix (fallback) - if: steps.nix_install_primary.outcome == 'failure' - uses: cachix/install-nix-action@v31 - with: - extra_nix_config: | - experimental-features = nix-command flakes - - - name: Verify Nix installation - shell: bash - run: nix --version - - - name: Cache Nix Store - continue-on-error: true - uses: nix-community/cache-nix-action@v7 - with: - primary-key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('flake.nix', 'flake.lock') }} - restore-prefixes-first-match: ${{ inputs.cache-key-prefix }}-${{ runner.os }}- - paths: ${{ inputs.cache-paths }} - - - name: Mark Nix setup complete - shell: bash - run: | - END=$(date +%s) - START=${SETUP_NIX_START:-$END} - { - echo "### Nix Setup" - echo "- Duration: $((END - START))s" - echo "- Cache key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-${{ hashFiles('flake.nix', 'flake.lock') }}" - } >> "$GITHUB_STEP_SUMMARY" diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 5f609479..00000000 --- a/flake.lock +++ /dev/null @@ -1,61 +0,0 @@ -{ - "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1783522502, - "narHash": "sha256-iffAls3iaNTyJC2faYcUXSI+Gp02cDjYl+MygxKl2GI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "0bb7ec54c8483066ec9d7720e780a5caa71f8612", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index e8ab590c..00000000 --- a/flake.nix +++ /dev/null @@ -1,506 +0,0 @@ -{ - description = "Zig 0.16 SDL3 Vulkan Voxel Engine"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { - inherit system; - }; - - zig_version = "0.16.0"; - nix_dynamic_linker = if pkgs.stdenv.isLinux then pkgs.stdenv.cc.bintools.dynamicLinker else ""; - nix_runtime_library_path = if pkgs.stdenv.isLinux then pkgs.lib.makeLibraryPath [ - pkgs.glibc - pkgs.stdenv.cc.cc.lib - pkgs.sdl3 - pkgs.vulkan-loader - pkgs.mesa - cimgui - rmluiBridge - rmlui - pkgs.freetype - ] else ""; - zig_sources = { - x86_64-linux = { - url = "https://ziglang.org/download/${zig_version}/zig-x86_64-linux-${zig_version}.tar.xz"; - hash = "sha256-cOSWZKdDdLSLUebz/fv0N/Y5XUJQkFBYi9SavlK6PQA="; - }; - - aarch64-linux = { - url = "https://ziglang.org/download/${zig_version}/zig-aarch64-linux-${zig_version}.tar.xz"; - hash = "sha256-6ksJv7IuxvbGzqxXq2PvtrRuF6sI0h9p86SLOOFTTxc="; - }; - - x86_64-darwin = { - url = "https://ziglang.org/download/${zig_version}/zig-x86_64-macos-${zig_version}.tar.xz"; - hash = "sha256-A4dVftGHe8ai4YAsg5GVO63bp2CBh2MBxSL1KXe1K6c="; - }; - - aarch64-darwin = { - url = "https://ziglang.org/download/${zig_version}/zig-aarch64-macos-${zig_version}.tar.xz"; - hash = "sha256-sj1w3qqHm1wtSG7TMW9+qlPoSs9vycx0feFSRQ1AFIk="; - }; - }; - - zig_source = zig_sources.${system}; - zig_tarball = pkgs.fetchurl { - url = zig_source.url; - hash = zig_source.hash; - }; - - zig = pkgs.stdenvNoCC.mkDerivation { - pname = "zig"; - version = zig_version; - src = zig_tarball; - - dontUnpack = true; - dontConfigure = true; - dontBuild = true; - - installPhase = '' - mkdir -p $out - tar -xJf ${zig_tarball} -C $out --strip-components=1 - mkdir -p $out/bin - cp $out/zig $out/bin/zig - ''; - - meta = { - mainProgram = "zig"; - platforms = builtins.attrNames zig_sources; - }; - }; - - cimgui = pkgs.stdenv.mkDerivation rec { - pname = "cimgui"; - version = "1.92.7-docking"; - - src = pkgs.fetchFromGitHub { - owner = "cimgui"; - repo = "cimgui"; - rev = "d3f0c2f4a7d4d116ef908295b971a36bdfdafe27"; - hash = "sha256-CsnoCFSzAibhUz2ffbGQcxczzhpQKpz9WJoRYbNH+kc="; - fetchSubmodules = true; - }; - - nativeBuildInputs = [ pkgs.pkg-config ]; - buildInputs = [ pkgs.sdl3 pkgs.vulkan-headers ]; - - dontConfigure = true; - - cimguiBackendHeader = pkgs.writeText "cimgui_backend.h" '' - #pragma once - #include - #include - #include - - #ifdef __cplusplus - extern "C" { - #endif - - typedef struct ZigCraftImGuiVulkanInitInfo { - VkInstance instance; - VkPhysicalDevice physical_device; - VkDevice device; - VkQueue queue; - uint32_t queue_family; - VkDescriptorPool descriptor_pool; - VkRenderPass render_pass; - uint32_t min_image_count; - uint32_t image_count; - VkSampleCountFlagBits msaa_samples; - } ZigCraftImGuiVulkanInitInfo; - - bool ZigCraft_ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); - bool ZigCraft_ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); - void ZigCraft_ImGui_ImplSDL3_NewFrame(void); - void ZigCraft_ImGui_ImplSDL3_Shutdown(void); - - bool ZigCraft_ImGui_ImplVulkan_Init(const ZigCraftImGuiVulkanInitInfo* info); - void ZigCraft_ImGui_ImplVulkan_NewFrame(void); - void ZigCraft_ImGui_ImplVulkan_RenderDrawData(void* draw_data, VkCommandBuffer command_buffer); - void ZigCraft_ImGui_ImplVulkan_Shutdown(void); - - void ZigCraft_ImGui_CreateContext(void); - void ZigCraft_ImGui_DestroyContext(void); - void ZigCraft_ImGui_StyleColorsDark(void); - void ZigCraft_ImGui_NewFrame(void); - bool ZigCraft_ImGui_Begin(const char* name); - bool ZigCraft_ImGui_Checkbox(const char* label, bool* value); - void ZigCraft_ImGui_SameLine(void); - void ZigCraft_ImGui_TextUnformatted(const char* text); - void ZigCraft_ImGui_End(void); - void ZigCraft_ImGui_Render(void); - void* ZigCraft_ImGui_GetDrawData(void); - - #ifdef __cplusplus - } - #endif - ''; - - cimguiBackendSource = pkgs.writeText "cimgui_backend.cpp" '' - #include "cimgui_backend.h" - #include "imgui.h" - #include "backends/imgui_impl_sdl3.h" - #include "backends/imgui_impl_vulkan.h" - - bool ZigCraft_ImGui_ImplSDL3_InitForVulkan(SDL_Window* window) { - return ImGui_ImplSDL3_InitForVulkan(window); - } - - bool ZigCraft_ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { - return ImGui_ImplSDL3_ProcessEvent(event); - } - - void ZigCraft_ImGui_ImplSDL3_NewFrame(void) { - ImGui_ImplSDL3_NewFrame(); - } - - void ZigCraft_ImGui_ImplSDL3_Shutdown(void) { - ImGui_ImplSDL3_Shutdown(); - } - - bool ZigCraft_ImGui_ImplVulkan_Init(const ZigCraftImGuiVulkanInitInfo* info) { - ImGui_ImplVulkan_InitInfo init_info = {}; - init_info.Instance = info->instance; - init_info.PhysicalDevice = info->physical_device; - init_info.Device = info->device; - init_info.QueueFamily = info->queue_family; - init_info.Queue = info->queue; - init_info.DescriptorPool = info->descriptor_pool; - init_info.PipelineInfoMain.RenderPass = info->render_pass; - init_info.MinImageCount = info->min_image_count; - init_info.ImageCount = info->image_count; - init_info.PipelineInfoMain.MSAASamples = info->msaa_samples; - return ImGui_ImplVulkan_Init(&init_info); - } - - void ZigCraft_ImGui_ImplVulkan_NewFrame(void) { - ImGui_ImplVulkan_NewFrame(); - } - - void ZigCraft_ImGui_ImplVulkan_RenderDrawData(void* draw_data, VkCommandBuffer command_buffer) { - ImGui_ImplVulkan_RenderDrawData(static_cast(draw_data), command_buffer); - } - - void ZigCraft_ImGui_ImplVulkan_Shutdown(void) { - ImGui_ImplVulkan_Shutdown(); - } - - void ZigCraft_ImGui_CreateContext(void) { - ImGui::CreateContext(); - } - - void ZigCraft_ImGui_DestroyContext(void) { - ImGui::DestroyContext(); - } - - void ZigCraft_ImGui_StyleColorsDark(void) { - ImGui::StyleColorsDark(); - } - - void ZigCraft_ImGui_NewFrame(void) { - ImGui::NewFrame(); - } - - bool ZigCraft_ImGui_Begin(const char* name) { - return ImGui::Begin(name); - } - - bool ZigCraft_ImGui_Checkbox(const char* label, bool* value) { - return ImGui::Checkbox(label, value); - } - - void ZigCraft_ImGui_SameLine(void) { - ImGui::SameLine(); - } - - void ZigCraft_ImGui_TextUnformatted(const char* text) { - ImGui::TextUnformatted(text); - } - - void ZigCraft_ImGui_End(void) { - ImGui::End(); - } - - void ZigCraft_ImGui_Render(void) { - ImGui::Render(); - } - - void* ZigCraft_ImGui_GetDrawData(void) { - return ImGui::GetDrawData(); - } - ''; - - cimguiCompatSource = pkgs.writeText "cimgui_compat.c" '' - #include - #include - - extern int __isoc99_vsscanf(const char* str, const char* format, va_list args); - - int __isoc23_sscanf(const char* str, const char* format, ...) { - va_list args; - va_start(args, format); - int result = __isoc99_vsscanf(str, format, args); - va_end(args); - return result; - } - ''; - - buildPhase = '' - runHook preBuild - cxxflags="-std=c++17 -O2 -fPIC -I. -Iimgui -Iimgui/backends $(pkg-config --cflags sdl3) -I${pkgs.vulkan-headers}/include" - $CXX $cxxflags -c cimgui.cpp -o cimgui.o - $CXX $cxxflags -c imgui/imgui.cpp -o imgui.o - $CXX $cxxflags -c imgui/imgui_draw.cpp -o imgui_draw.o - $CXX $cxxflags -c imgui/imgui_demo.cpp -o imgui_demo.o - $CXX $cxxflags -c imgui/imgui_tables.cpp -o imgui_tables.o - $CXX $cxxflags -c imgui/imgui_widgets.cpp -o imgui_widgets.o - $CXX $cxxflags -c imgui/backends/imgui_impl_sdl3.cpp -o imgui_impl_sdl3.o - $CXX $cxxflags -c imgui/backends/imgui_impl_vulkan.cpp -o imgui_impl_vulkan.o - cp ${cimguiBackendHeader} cimgui_backend.h - $CXX $cxxflags -I. -c ${cimguiBackendSource} -o cimgui_backend.o - $CC -O2 -fPIC -c ${cimguiCompatSource} -o cimgui_compat.o - ar rcs libcimgui.a cimgui.o imgui.o imgui_draw.o imgui_demo.o imgui_tables.o imgui_widgets.o imgui_impl_sdl3.o imgui_impl_vulkan.o cimgui_backend.o cimgui_compat.o - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - mkdir -p $out/lib/pkgconfig $out/include/cimgui $out/include/cimgui/imgui - cp cimgui.h cimconfig.h $out/include/cimgui/ - cp imgui/imgui.h imgui/imconfig.h imgui/imgui_internal.h $out/include/cimgui/imgui/ - cp imgui/imstb_rectpack.h imgui/imstb_textedit.h imgui/imstb_truetype.h $out/include/cimgui/imgui/ - cp ${cimguiBackendHeader} $out/include/cimgui/cimgui_backend.h - cp imgui/backends/imgui_impl_sdl3.h imgui/backends/imgui_impl_vulkan.h $out/include/cimgui/imgui/ - cp libcimgui.a $out/lib/libcimgui.a - cat > $out/lib/pkgconfig/cimgui.pc < $out/lib/pkgconfig/zigcraft-rmlui-bridge.pc < Date: Sat, 25 Jul 2026 10:50:54 +0100 Subject: [PATCH 09/12] fix(ci): make patchelf best-effort in zigcraft:build task The build job failed in CI: patchelf --add-rpath hit a rewriteSectionsExecutable assertion ('startAddr % getPageSize() == startOffset % getPageSize()') on the PIE binary zig emits by default. The former flake packages.default avoided this via hardeningDisable=["all"] (which disables PIE); devenv builds zig's default PIE layout, which patchelf cannot always rewrite. The zig build itself succeeded (53s) -- only the post-build rpath bake failed. Since the uploaded artifact is for inspection rather than external execution and the binary runs inside 'devenv shell' via ZIGCRAFT_DYNAMIC_LINKER/ZIGCRAFT_RUNTIME_LIBRARY_PATH regardless, the rpath bake is now best-effort: on patchelf failure it warns and leaves the binary as-is instead of failing the task. Signed-off-by: MichaelFisher1997 --- devenv.nix | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/devenv.nix b/devenv.nix index b585a87a..f3b9d857 100644 --- a/devenv.nix +++ b/devenv.nix @@ -414,7 +414,18 @@ in set -euo pipefail out="''${1:-$PWD/dist}" zig build -Doptimize=Debug -Dtarget=x86_64-linux-gnu --prefix "$out" - patchelf --add-rpath ${artifact_runtime_rpath} "$out/bin/zigcraft" + # patchelf bakes the nixpkgs runtime rpath so the binary runs outside a + # devenv shell. Best-effort: zig emits PIE binaries whose program headers + # patchelf occasionally cannot rewrite (assertion in + # rewriteSectionsExecutable). The uploaded artifact is for inspection + # rather than external execution, so a failed rpath bake must not fail the + # build -- the binary still runs inside 'devenv shell' via + # ZIGCRAFT_DYNAMIC_LINKER / ZIGCRAFT_RUNTIME_LIBRARY_PATH. + if patchelf --add-rpath ${artifact_runtime_rpath} "$out/bin/zigcraft" 2>/dev/null; then + echo "Baked runtime rpath into $out/bin/zigcraft" + else + echo "patchelf could not rewrite the PIE binary; rpath left unset (binary still runs inside 'devenv shell')" + fi echo "Built zigcraft -> $out/bin/zigcraft" ''; From e2cb133c69ef4f1a1acb0600bb4f0b19b47824f3 Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 11:18:08 +0100 Subject: [PATCH 10/12] fix(ci): pin devenv nixpkgs to the former flake revision The integration test failed with 86 Vulkan validation errors (viewport width/height 0, render-pass srcAccessMask mismatches). Root cause: devenv.lock had floated to a newer nixos-unstable (e2587ca, 2026-07-23) than the former flake.lock (0bb7ec5, 2026-07-08), pulling in SDL3 3.4.12 and a newer vulkan-loader that surface these errors under Lavapipe. dev's integration test passes with the older pin (SDL3 3.4.10). Pin devenv's nixpkgs input to 0bb7ec54c8483066ec9d7720e780a5caa71f8612 (the exact rev the former flake.lock used) so the migration changes only the shell tooling, not dependency versions. Verified: devenv info resolves with sdl3-3.4.10 and mesa-26.1.4, matching the pre-migration flake. Bumping this pin (and reconciling any newly-reported validation errors) is deferred to a separate PR. Signed-off-by: MichaelFisher1997 --- devenv.lock | 6 +++--- devenv.yaml | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/devenv.lock b/devenv.lock index 3205ac3b..dfeaa443 100644 --- a/devenv.lock +++ b/devenv.lock @@ -53,16 +53,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1784796856, + "lastModified": 1783522502, "owner": "NixOS", "repo": "nixpkgs", - "rev": "e2587caef70cea85dd97d7daab492899902dbf5d", + "rev": "0bb7ec54c8483066ec9d7720e780a5caa71f8612", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-unstable", "repo": "nixpkgs", + "rev": "0bb7ec54c8483066ec9d7720e780a5caa71f8612", "type": "github" } }, diff --git a/devenv.yaml b/devenv.yaml index c6d28940..b9c87f52 100644 --- a/devenv.yaml +++ b/devenv.yaml @@ -1,3 +1,9 @@ inputs: nixpkgs: - url: github:NixOS/nixpkgs/nixos-unstable + # Pinned to the same nixos-unstable revision the former flake.lock used, so + # the flake -> devenv migration changes only the shell tooling, not the + # dependency versions. A newer nixpkgs surfaced 86 Vulkan validation-layer + # errors (viewport 0x0, render-pass srcAccessMask mismatches) in the + # integration test that the pinned layers do not flag. Bump this pin (and + # reconcile any newly-reported validation errors) in a separate PR. + url: github:NixOS/nixpkgs/0bb7ec54c8483066ec9d7720e780a5caa71f8612 From bde5bcf704233242d033cbe35f14259924cfa8ef Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 12:04:26 +0100 Subject: [PATCH 11/12] fix(ci): pin Lavapipe and validation layers to devenv.lock rev The nixpkgs pin in devenv.yaml did not flow into setup-lavapipe, which resolved mesa.drivers and vulkan-validation-layers via the bare 'nixpkgs#' shorthand (the floating flake registry). The validation layers therefore drifted forward 17 days independently of the project pin and surfaced 86 latent Vulkan errors (viewport 0x0, render-pass srcAccessMask mismatches), failing integration-test; the same drift inflated validation overhead enough to breach the LOD GPU budget in benchmark. setup-lavapipe now reads the nixpkgs rev from devenv.lock (.nodes.nixpkgs.locked.rev) and resolves both packages from github:NixOS/nixpkgs/, so the validation layers match the rest of the environment. Single source of truth: bumping devenv.yaml/lock updates the Lavapipe layers automatically. Also addresses two review findings: - patchelf best-effort rpath bake now captures stderr to a temp file and prints it on failure instead of redirecting to /dev/null, so future patchelf regressions are diagnosable. - The zigcraft build artifact no longer double-lists the binary: upload path narrows from dist/ to dist/zigcraft-linux (the prepared copy). Signed-off-by: MichaelFisher1997 --- .github/actions/setup-lavapipe/action.yml | 12 ++++++++++-- .github/workflows/build.yml | 2 +- devenv.nix | 7 +++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/actions/setup-lavapipe/action.yml b/.github/actions/setup-lavapipe/action.yml index 250ed880..2cc83aa5 100644 --- a/.github/actions/setup-lavapipe/action.yml +++ b/.github/actions/setup-lavapipe/action.yml @@ -8,8 +8,16 @@ runs: shell: bash run: | set -euo pipefail - LVP_PATH=$(nix build --no-link --print-out-paths nixpkgs#mesa.drivers)/share/vulkan/icd.d/lvp_icd.x86_64.json - LAYER_PATH=$(nix build --no-link --print-out-paths nixpkgs#vulkan-validation-layers)/share/vulkan/explicit_layer.d + # Pin Lavapipe (mesa.drivers) and the Khronos validation layers to the + # same nixpkgs revision devenv.lock pins. The bare 'nixpkgs#' shorthand + # resolves to the floating flake registry and lets the validation + # layers drift independently of the project pin, which surfaced latent + # Vulkan errors (viewport 0x0, render-pass srcAccessMask mismatches) + # that broke the integration-test gate. Read the rev from devenv.lock + # so there is a single source of truth. + nixpkgs_rev=$(jq -r '.nodes.nixpkgs.locked.rev' devenv.lock) + LVP_PATH=$(nix build --no-link --print-out-paths "github:NixOS/nixpkgs/${nixpkgs_rev}#mesa.drivers")/share/vulkan/icd.d/lvp_icd.x86_64.json + LAYER_PATH=$(nix build --no-link --print-out-paths "github:NixOS/nixpkgs/${nixpkgs_rev}#vulkan-validation-layers")/share/vulkan/explicit_layer.d { echo "VK_ICD_FILENAMES=$LVP_PATH" echo "VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c9097faa..23f96ce8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -157,7 +157,7 @@ jobs: uses: actions/upload-artifact@v7 with: name: zigcraft - path: dist/ + path: dist/zigcraft-linux retention-days: 7 unit-test-matrix: diff --git a/devenv.nix b/devenv.nix index f3b9d857..edcb48d5 100644 --- a/devenv.nix +++ b/devenv.nix @@ -421,11 +421,14 @@ in # rather than external execution, so a failed rpath bake must not fail the # build -- the binary still runs inside 'devenv shell' via # ZIGCRAFT_DYNAMIC_LINKER / ZIGCRAFT_RUNTIME_LIBRARY_PATH. - if patchelf --add-rpath ${artifact_runtime_rpath} "$out/bin/zigcraft" 2>/dev/null; then + patchelf_log="$(mktemp)" + if patchelf --add-rpath ${artifact_runtime_rpath} "$out/bin/zigcraft" 2>"$patchelf_log"; then echo "Baked runtime rpath into $out/bin/zigcraft" else - echo "patchelf could not rewrite the PIE binary; rpath left unset (binary still runs inside 'devenv shell')" + echo "patchelf could not bake rpath (binary still runs inside 'devenv shell' via the loader env vars):" + cat "$patchelf_log" fi + rm -f "$patchelf_log" echo "Built zigcraft -> $out/bin/zigcraft" ''; From f7f888893a6a49fbb32b58e302619dda14e9616f Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 Date: Sat, 25 Jul 2026 12:20:18 +0100 Subject: [PATCH 12/12] fix(ci): revert setup-lavapipe to floating nixpkgs (matches dev) The previous attempt to pin Lavapipe/validation layers to devenv.lock's rev (0bb7ec5, nixos-unstable) forced a from-source build of vulkan-validation-layers that failed: that rev does not keep the package in the binary cache, and the sandbox build aborts with 'FileNotFoundError: git'. Re-checking the root cause: the validation-layer VERSION is identical across the pinned and floating nixpkgs (1.4.350.0 at the failing run), so layer drift was not the differentiator. dev's green integration-test (2026-07-08) used floating nixpkgs# layers + an sdl3-3.4.10 binary. My first red run used the same floating layers but an sdl3-3.4.12 binary (devenv.lock had floated forward). The SDL3 bump (3.4.10 -> 3.4.12) is what surfaced the 86 validation errors (0x0 viewport under headless weston), and the devenv nixpkgs pin already restores sdl3-3.4.10. So setup-lavapipe is restored to the floating nixpkgs# form dev has always used, which substitutes from the well-populated nixpkgs-unstable cache. The devenv nixpkgs pin (sdl3-3.4.10) is the actual correctness fix. Signed-off-by: MichaelFisher1997 --- .github/actions/setup-lavapipe/action.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/actions/setup-lavapipe/action.yml b/.github/actions/setup-lavapipe/action.yml index 2cc83aa5..cece0b0a 100644 --- a/.github/actions/setup-lavapipe/action.yml +++ b/.github/actions/setup-lavapipe/action.yml @@ -8,16 +8,16 @@ runs: shell: bash run: | set -euo pipefail - # Pin Lavapipe (mesa.drivers) and the Khronos validation layers to the - # same nixpkgs revision devenv.lock pins. The bare 'nixpkgs#' shorthand - # resolves to the floating flake registry and lets the validation - # layers drift independently of the project pin, which surfaced latent - # Vulkan errors (viewport 0x0, render-pass srcAccessMask mismatches) - # that broke the integration-test gate. Read the rev from devenv.lock - # so there is a single source of truth. - nixpkgs_rev=$(jq -r '.nodes.nixpkgs.locked.rev' devenv.lock) - LVP_PATH=$(nix build --no-link --print-out-paths "github:NixOS/nixpkgs/${nixpkgs_rev}#mesa.drivers")/share/vulkan/icd.d/lvp_icd.x86_64.json - LAYER_PATH=$(nix build --no-link --print-out-paths "github:NixOS/nixpkgs/${nixpkgs_rev}#vulkan-validation-layers")/share/vulkan/explicit_layer.d + # Lavapipe ICD and the Khronos validation layers are resolved from the + # floating nixpkgs-unstable flake registry, matching how dev's CI has + # always resolved them. They are NOT pinned to devenv.lock's nixpkgs: + # the pinned (nixos-unstable) rev does not keep vulkan-validation-layers + # in the binary cache, so pinning forces a from-source build that fails + # (missing git in the sandbox). The integration-test correctness signal + # is governed by the binary's SDL3/vulkan-loader versions, which the + # devenv nixpkgs pin already locks to the pre-migration versions. + LVP_PATH=$(nix build --no-link --print-out-paths nixpkgs#mesa.drivers)/share/vulkan/icd.d/lvp_icd.x86_64.json + LAYER_PATH=$(nix build --no-link --print-out-paths nixpkgs#vulkan-validation-layers)/share/vulkan/explicit_layer.d { echo "VK_ICD_FILENAMES=$LVP_PATH" echo "VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation"