Skip to content

🖥️ 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

PlatformDetect ComposerAuto-install ComposerAuto-install PHPSmart default strategy
🐧 LinuxPackage manager (apt/dnf/pacman) first, otherwise download phar
🍎 macOSbrew first, otherwise download phar
🪟 Windows⚠️ LimitedDownload 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 via os/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:

go
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 fallback

The detector package has per-platform file implementations:

  • pkg/detector/darwin.go — macOS-specific paths
  • pkg/detector/windows.go — Windows-specific paths
  • pkg/detector/unix.go — Generic Unix paths (shared by Linux)

Also supports COMPOSER environment variable for manual path specification:

go
// 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 IDPackage managerInstall command
ubuntu / debianaptapt-get install composer
fedora / rhel / centosdnf/yumdnf install composer
alpineapkapk add composer
archpacmanpacman -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

go
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 /:

go
import "path/filepath"
dir := filepath.Join("data", "sub") // On Windows, automatically becomes data\sub

Working 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

Released under the MIT License