# WinImageKit (CLI prototype) WinImageKit is the "Pro" tier deployment recipe runner in the same product line as the sibling tool DeployForge. Where DeployForge runs a manifest's steps as a simple sequential list -- step 1, then step 2, then step 3, stopping the whole run on the first failure -- WinImageKit reads a dependency graph: each step declares, by name, which other steps it depends on (depends_on). WinImageKit validates that graph (rejecting any step that references a dependency name which doesn't exist, and detecting dependency cycles before running anything, naming the exact cycle found), computes a topological execution order so that every step's dependencies have already succeeded before it runs, and then executes idempotent check/install pairs (the same check-then-install shell-command mechanic DeployForge uses) in that order. The real differentiator is failure handling: in WinImageKit, a failed step blocks only its own transitive dependents -- unrelated branches of the graph keep running and can still complete successfully, instead of DeployForge's global fail-fast that stops the entire run on any single failure. This matters for real deployment recipes with genuine interdependencies, e.g. "install runtime" must happen before "install app", and "create data dir" must happen before "seed data", while an unrelated "configure logging" branch shouldn't be held hostage by a failure somewhere else in the graph. This prototype covers graph-ordered orchestration of shell-command steps only. The full WinImageKit concept -- building custom Windows images, unattended (answer-file driven) setup, bootable USB creation, EFI/bootloader repair, and offline driver injection into a WIM/VHD -- needs privileged, Windows-only imaging and deployment APIs (DISM, WinPE, diskpart, bcdboot, etc.) that a stdlib-only, cross-platform CLI prototype cannot exercise. Those pieces are on the roadmap; see ../plan.md for the full product plan. ## Build from source Requires Go 1.24+, no external dependencies (stdlib only). go build -o winimagekit . Cross-compile for other platforms, e.g.: GOOS=windows GOARCH=amd64 go build -o winimagekit.exe . GOOS=darwin GOARCH=amd64 go build -o winimagekit-darwin-amd64 . GOOS=darwin GOARCH=arm64 go build -o winimagekit-darwin-arm64 . GOOS=linux GOARCH=amd64 go build -o winimagekit-linux-amd64 . ## Usage winimagekit apply [--dry-run] [--log run.log] winimagekit validate winimagekit -h | --help | help ### apply 1. Parses the manifest and builds a dependency graph from each step's depends_on list. Validates it: - every name listed in depends_on must exist as a real step in the manifest, or the run is refused with the specific step/reference named; - the graph must contain no cycles -- if one exists, the run is refused and the exact cycle is printed, e.g. "dependency cycle detected: X -> Z -> Y -> X". If either check fails, NOTHING is executed and the process exits non-zero. 2. If the graph is valid, computes a topological execution order (any order where every step appears after all of its dependencies is acceptable -- WinImageKit does not promise one single canonical order, only a correct one) and prints it. 3. Executes steps in that order. For each step: - run its check command; if it exits 0, report SKIP (already satisfied) and move on; - otherwise, without --dry-run, run its install command and report INSTALLED or FAILED. Partial-failure policy (the key difference from DeployForge's global fail-fast): if a step FAILED (or was itself BLOCKED), every step that directly or transitively depends on it is marked BLOCKED and never attempted. Steps in unrelated branches of the graph -- anything that does not depend on the failed step, even indirectly -- are still attempted normally. The process exits non-zero if anything FAILED or was BLOCKED. With --dry-run: every step whose check fails is reported as WOULD INSTALL (check failed), in dependency order, without actually running any install command and without applying the blocking policy above (nothing is really failing in a dry run, so nothing needs to be blocked). 4. --log : appends one JSON object per line to for every step outcome, in the same spirit as DeployForge's log: {"name":"...","verdict":"...","timestamp":"...","dry_run":true|false} verdict is one of SKIP, INSTALLED, FAILED, BLOCKED, or WOULD_INSTALL. ### validate Runs just the graph validation from step 1 above (parses the manifest, checks that every depends_on reference resolves to a real step, checks for cycles) without executing any check or install command. Prints OK and the computed execution order if the graph is valid, or the specific problem(s) found (bad references and/or the exact cycle) and exits non-zero otherwise. ### Manifest format { "name": "example-image-recipe", "steps": [ { "name": "base-dir", "check": "test -d /tmp/wik-demo/base", "install": "mkdir -p /tmp/wik-demo/base", "depends_on": [] }, { "name": "config-file","check": "test -f /tmp/wik-demo/base/config.txt", "install": "sh -c \"echo cfg > /tmp/wik-demo/base/config.txt\"", "depends_on": ["base-dir"] }, { "name": "data-dir", "check": "test -d /tmp/wik-demo/base/data", "install": "mkdir -p /tmp/wik-demo/base/data", "depends_on": ["base-dir"] }, { "name": "seed-data", "check": "test -f /tmp/wik-demo/base/data/seed.txt", "install": "sh -c \"echo seed > /tmp/wik-demo/base/data/seed.txt\"", "depends_on": ["data-dir", "config-file"] } ] } Each step's check and install commands are run via "sh -c " on Linux/macOS and "cmd /C " on Windows (runtime.GOOS-selected, same as DeployForge). ## Prebuilt binaries See ../downloads/ for prebuilt binaries (Windows/macOS/Linux) and CHECKSUMS.txt for their SHA-256 hashes. Unsigned indie builds -- Windows SmartScreen and macOS Gatekeeper will warn on first run, expected until a code-signing certificate is in place.