🖥️ Cross-platform support
Composer Skills works consistently across Windows, macOS, and Linux. This page shows the support matrix and explains how "smart defaults" choose the installation method per platform.
📊 Platform support matrix
| Platform | Detect Composer | Auto-install Composer | Auto-install PHP | Smart default strategy |
|---|---|---|---|---|
| 🐧 Linux | ✅ | ✅ | ✅ | Package manager (apt/dnf/pacman) first, otherwise download phar |
| 🍎 macOS | ✅ | ✅ | ✅ | brew first, otherwise download phar |
| 🪟 Windows | ✅ | ✅ | ⚠️ Limited | Download composer.phar + .cmd wrapper script |
Common capabilities (consistent across all platforms):
- 🌐 Packagist API (
pkg/client) — pure Go, platform-independent. - 🛠️ Composer CLI wrapper (
pkg/composer) — subprocess viaos/exec, consistent across platforms. - 🔧 Detector (
pkg/detector) — scans different paths per platform.
One codebase, three platforms
You don't need to write if runtime.GOOS == "windows" branches. The SDK internally compiles per-platform files (darwin.go/windows.go/unix.go) and exposes a unified API.
🔍 Platform detection
The detector scans different paths for different platforms:
d := detector.NewDetector()
path, err := d.Detect()
// Internally:
// Linux/macOS: Check PATH, /usr/local/bin, /usr/bin, ~/.composer/..., with which fallback
// Windows: Check PATH, C:\ProgramData\ComposerSetup\..., with where fallbackThe detector package has per-platform file implementations:
pkg/detector/darwin.go— macOS-specific pathspkg/detector/windows.go— Windows-specific pathspkg/detector/unix.go— Generic Unix paths (shared by Linux)
Also supports COMPOSER environment variable for manual path specification:
// User can set: COMPOSER=/opt/composer/composer.phar
// Detector will prioritize this environment variable📦 Smart defaults: per-platform install method
The installer's SmartConfig() picks the best strategy per platform:
🐧 Linux
DetectLinuxDistro() parses /etc/os-release (with fallback to lsb_release and known files) and selects the package manager:
| Distro ID | Package manager | Install command |
|---|---|---|
| ubuntu / debian | apt | apt-get install composer |
| fedora / rhel / centos | dnf/yum | dnf install composer |
| alpine | apk | apk add composer |
| arch | pacman | pacman -S composer |
If no package manager is available, fallback to downloading composer.phar and writing a wrapper script to /usr/local/bin/composer.
🍎 macOS
brew install composer first; if no brew, download the phar.
🪟 Windows
Download composer.phar to a fixed directory, then generate a .cmd wrapper script and add it to PATH.
🐧 Linux distro detection example
distro, err := installer.DetectLinuxDistro()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Distro: %s (ID=%s)\n", distro.Name, distro.ID)
fmt.Printf("Package manager: %s\n", distro.PackageManager)
// Can also check/install PHP along the way
if installer.HasPHP() {
ver, _ := installer.GetPHPVersion()
fmt.Printf("PHP installed: %s\n", ver)
} else {
_ = installer.InstallPHP(distro, false)
}⚙️ Notes on cross-platform coding
Path separators
The SDK internally uses filepath.Join for path separators. When passing paths, please also use filepath.Join instead of hardcoding /:
import "path/filepath"
dir := filepath.Join("data", "sub") // On Windows, automatically becomes data\subWorking directory permissions
On Windows, writing to protected directories like C:\Program Files requires administrator privileges. It's recommended to point WorkingDir to a user-writable directory.
CI containers
In GitHub Actions / GitLab CI Linux containers, you usually run as root, so the installer can install globally without sudo. On a local macOS dev machine, prefer brew to avoid manual sudo.
🧭 Next steps
- 📡 Detector docs — scan paths and priorities per platform.
- 📥 Installer docs — platform strategies, distro detection, PHP install.
- 🔧 Auto-install mechanism — full detect→install→verify flow.
- 🔄 CI/CD pipeline — usage on CI runners across three platforms.