Agent Skills Framework Extension
Binary Distribution Patterns Skill
When to Use This Skill
Use this skill when implementing binary distribution patterns patterns in your codebase.
How to Use This Skill
- Review the patterns and examples below
- Apply the relevant patterns to your implementation
- Follow the best practices outlined in this skill
Cross-platform binary releases, artifact management, and distribution strategies.
Core Capabilities
- Cross-Platform Builds - Multi-OS, multi-arch compilation
- Release Automation - CI/CD release workflows
- Artifact Signing - Code signing and verification
- Distribution - CDN, package managers, direct download
- Installation - Shell scripts, package managers
Multi-Platform Build Matrix
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
env:
CARGO_TERM_COLOR: always
jobs:
build:
strategy:
matrix:
include:
# Linux
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact: myapp-linux-x64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
artifact: myapp-linux-arm64
cross: true
# macOS
- os: macos-latest
target: x86_64-apple-darwin
artifact: myapp-darwin-x64
- os: macos-latest
target: aarch64-apple-darwin
artifact: myapp-darwin-arm64
# Windows
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact: myapp-windows-x64.exe
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install cross-compilation tools
if: matrix.cross
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Package (Unix)
if: runner.os != 'Windows'
run: |
mkdir -p dist
cp target/${{ matrix.target }}/release/myapp dist/${{ matrix.artifact }}
cd dist
tar -czvf ${{ matrix.artifact }}.tar.gz ${{ matrix.artifact }}
sha256sum ${{ matrix.artifact }}.tar.gz > ${{ matrix.artifact }}.tar.gz.sha256
- name: Package (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist
Copy-Item target/${{ matrix.target }}/release/myapp.exe dist/${{ matrix.artifact }}
Compress-Archive -Path dist/${{ matrix.artifact }} -DestinationPath dist/${{ matrix.artifact }}.zip
Get-FileHash dist/${{ matrix.artifact }}.zip -Algorithm SHA256 |
ForEach-Object { $_.Hash.ToLower() + " " + (Split-Path $_.Path -Leaf) } |
Out-File -FilePath dist/${{ matrix.artifact }}.zip.sha256
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: dist/*
retention-days: 1
release:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release files
run: |
mkdir release
find artifacts -type f -name "*.tar.gz" -o -name "*.zip" -o -name "*.sha256" |
while read f; do cp "$f" release/; done
- name: Generate release notes
run: |
echo "## What's Changed" > RELEASE_NOTES.md
git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --pretty=format:"- %s" >> RELEASE_NOTES.md
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: release/*
body_path: RELEASE_NOTES.md
draft: false
prerelease: ${{ contains(github.ref, '-') }}
Release Manifest
// scripts/generate-manifest.ts
interface ReleaseAsset {
name: string;
os: 'linux' | 'darwin' | 'windows';
arch: 'x64' | 'arm64';
url: string;
sha256: string;
size: number;
}
interface ReleaseManifest {
version: string;
releaseDate: string;
assets: ReleaseAsset[];
changelog: string;
minVersion?: string;
}
async function generateManifest(version: string): Promise<ReleaseManifest> {
const assets: ReleaseAsset[] = [];
const baseUrl = `https://github.com/org/repo/releases/download/v${version}`;
const platforms = [
{ os: 'linux', arch: 'x64', ext: 'tar.gz' },
{ os: 'linux', arch: 'arm64', ext: 'tar.gz' },
{ os: 'darwin', arch: 'x64', ext: 'tar.gz' },
{ os: 'darwin', arch: 'arm64', ext: 'tar.gz' },
{ os: 'windows', arch: 'x64', ext: 'zip' },
];
for (const platform of platforms) {
const name = `myapp-${platform.os}-${platform.arch}.${platform.ext}`;
const sha256Path = `dist/${name}.sha256`;
if (existsSync(sha256Path)) {
const sha256 = readFileSync(sha256Path, 'utf-8').split(' ')[0].trim();
const size = statSync(`dist/${name}`).size;
assets.push({
name,
os: platform.os as ReleaseAsset['os'],
arch: platform.arch as ReleaseAsset['arch'],
url: `${baseUrl}/${name}`,
sha256,
size,
});
}
}
const changelog = execSync(`git log --pretty=format:"- %s" v${getPreviousVersion()}..HEAD`)
.toString()
.trim();
return {
version,
releaseDate: new Date().toISOString(),
assets,
changelog,
};
}
// Write manifest to file
const manifest = await generateManifest(process.env.VERSION!);
writeFileSync('dist/manifest.json', JSON.stringify(manifest, null, 2));
Install Script
#!/usr/bin/env bash
# install.sh - Universal installer for myapp
set -euo pipefail
# Configuration
REPO="org/myapp"
INSTALL_DIR="${MYAPP_INSTALL_DIR:-$HOME/.myapp/bin}"
VERSION="${MYAPP_VERSION:-latest}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
# Detect platform
detect_platform() {
local os arch
case "$(uname -s)" in
Linux*) os="linux" ;;
Darwin*) os="darwin" ;;
MINGW*|MSYS*|CYGWIN*) os="windows" ;;
*) log_error "Unsupported OS: $(uname -s)"; exit 1 ;;
esac
case "$(uname -m)" in
x86_64|amd64) arch="x64" ;;
arm64|aarch64) arch="arm64" ;;
*) log_error "Unsupported architecture: $(uname -m)"; exit 1 ;;
esac
echo "${os}-${arch}"
}
# Get latest version from GitHub API
get_latest_version() {
local url="https://api.github.com/repos/${REPO}/releases/latest"
curl -fsSL "$url" | grep '"tag_name"' | sed -E 's/.*"v([^"]+)".*/\1/'
}
# Download and verify
download_and_install() {
local platform="$1"
local version="$2"
local ext="tar.gz"
[[ "$platform" == windows-* ]] && ext="zip"
local filename="myapp-${platform}.${ext}"
local url="https://github.com/${REPO}/releases/download/v${version}/${filename}"
local sha_url="${url}.sha256"
log_info "Downloading myapp v${version} for ${platform}..."
local tmpdir
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
# Download binary and checksum
curl -fsSL -o "${tmpdir}/${filename}" "$url"
curl -fsSL -o "${tmpdir}/${filename}.sha256" "$sha_url"
# Verify checksum
log_info "Verifying checksum..."
cd "$tmpdir"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum -c "${filename}.sha256"
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 -c "${filename}.sha256"
else
log_warn "No SHA256 tool found, skipping verification"
fi
# Extract and install
log_info "Installing to ${INSTALL_DIR}..."
mkdir -p "$INSTALL_DIR"
if [[ "$ext" == "tar.gz" ]]; then
tar -xzf "$filename" -C "$INSTALL_DIR"
else
unzip -o "$filename" -d "$INSTALL_DIR"
fi
chmod +x "${INSTALL_DIR}/myapp"*
}
# Update shell profile
update_path() {
local shell_profile=""
case "$SHELL" in
*/bash) shell_profile="$HOME/.bashrc" ;;
*/zsh) shell_profile="$HOME/.zshrc" ;;
*/fish) shell_profile="$HOME/.config/fish/config.fish" ;;
esac
if [[ -n "$shell_profile" ]] && ! grep -q "$INSTALL_DIR" "$shell_profile" 2>/dev/null; then
log_info "Adding ${INSTALL_DIR} to PATH in ${shell_profile}"
if [[ "$SHELL" == */fish ]]; then
echo "set -gx PATH \$PATH $INSTALL_DIR" >> "$shell_profile"
else
echo "export PATH=\"\$PATH:$INSTALL_DIR\"" >> "$shell_profile"
fi
log_info "Please restart your shell or run: source $shell_profile"
fi
}
main() {
log_info "Installing myapp..."
local platform
platform=$(detect_platform)
log_info "Detected platform: ${platform}"
if [[ "$VERSION" == "latest" ]]; then
VERSION=$(get_latest_version)
fi
log_info "Version: ${VERSION}"
download_and_install "$platform" "$VERSION"
update_path
log_info "Installation complete!"
log_info "Run 'myapp --version' to verify"
}
main "$@"
npm Binary Package Pattern
// package.json (main package)
{
"name": "myapp",
"version": "1.0.0",
"description": "Cross-platform CLI tool",
"bin": {
"myapp": "bin/myapp"
},
"scripts": {
"postinstall": "node scripts/postinstall.js"
},
"optionalDependencies": {
"@myapp/darwin-x64": "1.0.0",
"@myapp/darwin-arm64": "1.0.0",
"@myapp/linux-x64": "1.0.0",
"@myapp/linux-arm64": "1.0.0",
"@myapp/win32-x64": "1.0.0"
}
}
// scripts/postinstall.js
const { existsSync, mkdirSync, copyFileSync, chmodSync } = require('fs');
const { join } = require('path');
const PLATFORM_PACKAGES = {
'darwin-x64': '@myapp/darwin-x64',
'darwin-arm64': '@myapp/darwin-arm64',
'linux-x64': '@myapp/linux-x64',
'linux-arm64': '@myapp/linux-arm64',
'win32-x64': '@myapp/win32-x64',
};
function getBinaryPath() {
const platformKey = `${process.platform}-${process.arch}`;
const packageName = PLATFORM_PACKAGES[platformKey];
if (!packageName) {
console.error(`Unsupported platform: ${platformKey}`);
process.exit(1);
}
try {
const packagePath = require.resolve(`${packageName}/package.json`);
const packageDir = join(packagePath, '..');
const binaryName = process.platform === 'win32' ? 'myapp.exe' : 'myapp';
return join(packageDir, binaryName);
} catch (e) {
console.error(`Platform package not installed: ${packageName}`);
console.error('Try running: npm install --ignore-scripts && npm run postinstall');
process.exit(1);
}
}
function install() {
const sourcePath = getBinaryPath();
const binDir = join(__dirname, '..', 'bin');
const targetPath = join(binDir, process.platform === 'win32' ? 'myapp.exe' : 'myapp');
if (!existsSync(binDir)) {
mkdirSync(binDir, { recursive: true });
}
copyFileSync(sourcePath, targetPath);
chmodSync(targetPath, 0o755);
console.log(`Installed myapp binary to ${targetPath}`);
}
install();
Usage Examples
Setup Cross-Platform Builds
Apply binary-distribution-patterns skill to configure GitHub Actions for multi-platform Rust binary releases
Create Install Script
Apply binary-distribution-patterns skill to create universal install script with checksum verification
npm Binary Package
Apply binary-distribution-patterns skill to structure npm package with platform-specific optionalDependencies
Integration Points
- cicd-pipeline-design - CI/CD workflows
- npm-packaging-patterns - npm distribution
- code-signing - Binary signing
Success Output
When successful, this skill MUST output:
✅ SKILL COMPLETE: binary-distribution-patterns
Completed:
- [x] Multi-platform build matrix configured (Linux/macOS/Windows)
- [x] Cross-compilation tools setup for ARM64 targets
- [x] SHA256 checksums generated for all artifacts
- [x] Release manifest created with download URLs
- [x] Universal install script tested on all platforms
- [x] GitHub Release created with all artifacts
- [x] npm binary package structure validated
Outputs:
- .github/workflows/release.yml (GitHub Actions workflow)
- dist/myapp-{platform}-{arch}.{tar.gz|zip} (binaries)
- dist/myapp-{platform}-{arch}.{tar.gz|zip}.sha256 (checksums)
- dist/manifest.json (release metadata)
- install.sh (universal installer)
- package.json (npm binary wrapper)
- scripts/postinstall.js (npm platform selection)
Completion Checklist
Before marking this skill as complete, verify:
- Build matrix produces binaries for all target platforms
- Cross-compilation succeeds without linker errors
- SHA256 checksums match actual binary hashes
- Release manifest includes all platform/arch combinations
- Install script detects platform correctly on Linux/macOS/Windows
- Install script verifies checksums before installation
- GitHub Release contains all artifacts with correct names
- npm package installs correct binary for host platform
- Installed binary executes successfully (--version works)
- All artifact sizes under expected limits (no debug symbols)
Failure Indicators
This skill has FAILED if:
- ❌ Build fails for any target platform
- ❌ Cross-compilation produces non-functional binaries
- ❌ SHA256 checksum verification fails
- ❌ Release manifest missing any platform
- ❌ Install script fails platform detection
- ❌ Install script installs wrong binary for platform
- ❌ GitHub Release upload incomplete or corrupted
- ❌ npm package installs but binary not executable
- ❌ Binary size exceeds 100MB (likely includes debug symbols)
- ❌ Windows binary not code-signed (triggers SmartScreen)
When NOT to Use
Do NOT use this skill when:
- Interpreted languages only - No binary compilation needed for Python/Node.js scripts
- Container-only distribution - Docker images sufficient, no standalone binaries
- Single-platform applications - If only targeting one OS, simpler build sufficient
- Library/SDK projects - Distribute source code, not binaries
- Internal tools only - GitHub releases overkill for team-only tools
- Frequent iterations - Binary distribution too heavy for rapid prototyping
- Web-only applications - No client-side installation required
Alternative approaches:
- Use Docker images for container-based distribution
- Use language package managers (pip, npm, cargo publish) for libraries
- Use internal artifact repositories (Artifactory, Nexus) for enterprise tools
Anti-Patterns (Avoid)
| Anti-Pattern | Problem | Solution |
|---|---|---|
| No checksum verification | Corrupted downloads undetected | Always generate and verify SHA256 |
| Debug symbols in release | 10x larger binaries | Strip symbols with --release flag |
| Missing platform detection | Wrong binary installed | Detect OS and arch in installer |
| Hardcoded download URLs | Breaks when URLs change | Use GitHub API for latest release |
| No version in filename | Can't tell versions apart | Include version in artifact name |
| Sequential builds | Slow release process | Use matrix strategy for parallel builds |
| Unsigned Windows binaries | SmartScreen warnings, low trust | Code sign with certificate |
| No ARM64 support | Excludes Apple Silicon, ARM servers | Include aarch64 targets |
| Manual release creation | Error-prone, slow | Fully automate with GitHub Actions |
| Missing install script | Users don't know how to install | Provide curl | sh one-liner |
Principles
This skill embodies these CODITECT principles:
- #3 Keep It Simple - Universal installer works across all platforms
- #6 Clear, Understandable, Explainable - Install manifest documents all artifacts
- #7 Error Handling Excellence - Checksum verification prevents corrupt installs
- #9 Observability First - Release manifest tracks all versions and platforms
- #10 Performance Matters - Matrix builds parallelize cross-platform compilation
- #11 Security by Design - SHA256 verification, code signing for Windows
- #13 Automate Repetitive Tasks - GitHub Actions eliminates manual releases
- #14 Cross-Platform by Default - Supports Linux/macOS/Windows from start
Full Principles: CODITECT-STANDARD-AUTOMATION.md