--- title: Build Notes type: concept updated: 2026-04-28 --- # Build Notes Practical gotchas around building `.skill` archives. ## Why `build.ps1` exists alongside `build.sh` The user is on Windows; the install target may be Linux/macOS. So archives must be portable. **Windows PowerShell 5.1's `Compress-Archive` (v1.0.1.0) writes ZIP entries with backslashes** (e.g. `caveman\SKILL.md`). Linux/macOS `unzip` then either fails or extracts the literal name as a single file. Verified: archives produced by `Compress-Archive` listed entries like `caveman\SKILL.md`. Workarounds considered: - Install `zip.exe` → adds a Windows dep we don't want. - PowerShell 7's `Compress-Archive` is fixed → can't assume PS7 is installed. - **Use .NET `System.IO.Compression.ZipArchive` directly** ← chosen. Walks files, adds entries with `path -replace '\\','/'`. Spec-compliant ZIPs everywhere. `build.ps1` does that. `build.sh` prefers `zip` (one-liner, fast on *nix), and on Windows-without-`zip` it falls back to invoking `build.ps1` via `powershell.exe`. ## ZIP layout the loader expects Looking at the canonical `~/.claude/skills//` layout, the `.skill` archive should contain a single top-level directory `/` with `SKILL.md` plus optional `assets/`, `references/`, etc. inside. `zip -qr dist/.skill ` (run from `skills/`) does this naturally. The .NET path adds an explicit `/` prefix to each entry. ## Extracting `.skill` files A `.skill` file is just a renamed `.zip`. To extract on Windows: ```powershell Copy-Item project-bootstrap.skill project-bootstrap.zip Expand-Archive -Path project-bootstrap.zip -DestinationPath ~/.claude/skills/ Remove-Item project-bootstrap.zip ``` On *nix: `unzip dist/project-bootstrap.skill -d ~/.claude/skills/`. (Our `install.sh` skips this entirely — it copies from `skills/` directly. Extraction-from-archive is only needed when you don't have the source tree, e.g. when sharing a single `.skill` file with someone else.)