stout
Article

Cask Support: Install GUI Apps on macOS and Linux with stout

stout cask installs macOS .app bundles, Linux AppImages, and Flatpaks — GUI applications with the same speed and reliability as CLI packages.

Neul Labs ·
#stout#cask#macos#linux#appimage#flatpak

Homebrew Cask extended the package manager beyond command-line tools to GUI applications — install Firefox, VS Code, or Slack with brew install --cask. But Cask support was always macOS-only, and the implementation inherits all of Homebrew’s performance overhead: Ruby startup, JSON API parsing, and sequential downloads. stout brings cask support to both macOS and Linux with the same speed improvements as its formula installations, plus native support for Linux application formats like AppImage and Flatpak.

Casks on macOS

On macOS, stout handles .app bundles, .pkg installers, and .dmg disk images — the same application formats that Homebrew Cask supports. The command syntax is intentionally familiar:

stout install --cask firefox
# Downloading Firefox-125.0.dmg (98 MB)... done
# Mounting disk image...
# Installing Firefox.app to /Applications...
# Installation complete: Firefox 125.0

stout’s cask installation is faster than Homebrew’s for the same reasons its formula installation is faster: native binary startup, parallel dependency resolution, and no Ruby overhead. But there are additional optimizations specific to cask handling.

DMG processing. When installing from a .dmg file, stout uses hdiutil to mount the image and copies the .app bundle directly, without spawning a separate Ruby process for each step. The mount-copy-unmount cycle is handled as a single async operation.

PKG installation. For .pkg installers, stout invokes the macOS installer command with the correct target volume and provides progress feedback. If the package requires elevated privileges, stout prompts for authentication once and caches the authorization for the duration of the install session.

stout install --cask docker
# Downloading Docker.dmg (620 MB)... done
# Requires administrator privileges to install.
# Password: ********
# Installing Docker.app to /Applications... done
# Installation complete: Docker 4.28.0

Quarantine handling. macOS applies quarantine attributes to downloaded applications, which triggers Gatekeeper verification on first launch. stout preserves this security behavior by default but provides an option to remove quarantine for trusted sources:

# Default: quarantine preserved (Gatekeeper will verify on first launch)
stout install --cask some-app

# For apps from your private index with Ed25519 verification
stout install --cask some-app --no-quarantine

Casks on Linux

Homebrew Cask has no Linux support at all. stout extends the cask concept to Linux by supporting AppImage and Flatpak formats natively.

AppImage support

AppImage bundles an application and all its dependencies into a single executable file. stout manages AppImage downloads, verification, and desktop integration:

stout install --cask neovide
# Downloading neovide-0.12.2-x86_64.AppImage (28 MB)... done
# Verifying SHA256... OK
# Installing to ~/.local/bin/neovide
# Creating desktop entry: ~/.local/share/applications/neovide.desktop
# Installation complete: neovide 0.12.2

stout places AppImages in ~/.local/bin (or a configurable location) and creates XDG desktop entries so the application appears in your desktop environment’s application launcher. The AppImage is made executable and optionally extracted for faster startup:

# Install and extract for faster cold start
stout install --cask neovide --extract
# Extracts the AppImage squashfs to avoid FUSE mount on each launch

Flatpak integration

For applications distributed as Flatpaks, stout delegates to the flatpak command while providing its own search, version tracking, and consistent interface:

stout install --cask slack
# Detected Flatpak available for slack
# Installing com.slack.Slack via Flatpak...
# Installation complete: Slack 4.38.125

stout tracks Flatpak installations in its local database so that stout list --cask shows a unified view of all GUI applications regardless of the underlying format:

stout list --cask
# NAME          VERSION     FORMAT      SOURCE
# firefox       125.0       .dmg/.app   public
# docker        4.28.0      .dmg/.app   public
# neovide       0.12.2      AppImage    public
# slack         4.38.125    Flatpak     public
# acme-dash     1.2.0       AppImage    acme-internal

Cross-platform cask definitions

stout’s cask definitions support platform-specific variants within a single entry. The SQLite index stores download URLs and installation methods for each platform:

-- Simplified cask schema
CREATE TABLE casks (
    id INTEGER PRIMARY KEY,
    token TEXT NOT NULL UNIQUE,
    name TEXT,
    description TEXT,
    version TEXT NOT NULL,
    -- Platform-specific fields stored as JSON
    artifacts TEXT  -- JSON object with per-platform instructions
);

A cask like VS Code has different artifacts for each platform:

{
  "macos_arm64": {
    "url": "https://update.code.visualstudio.com/.../darwin-arm64/stable",
    "type": "dmg",
    "app": "Visual Studio Code.app"
  },
  "macos_intel": {
    "url": "https://update.code.visualstudio.com/.../darwin/stable",
    "type": "dmg",
    "app": "Visual Studio Code.app"
  },
  "linux_x86_64": {
    "url": "https://update.code.visualstudio.com/.../linux-x64/stable",
    "type": "appimage"
  }
}

When you run stout install --cask visual-studio-code, stout selects the correct artifact for your platform and uses the appropriate installation method automatically.

Upgrading casks

stout tracks installed cask versions and supports both individual and bulk upgrades:

# Check for outdated casks
stout outdated --cask
# firefox       125.0  → 126.0
# docker        4.28.0 → 4.29.0

# Upgrade a specific cask
stout upgrade --cask firefox
# Downloading Firefox-126.0.dmg...
# Removing Firefox 125.0...
# Installing Firefox 126.0 to /Applications...
# Upgrade complete

# Upgrade all casks
stout upgrade --cask
# Upgrading 2 casks...

On macOS, stout checks whether the application is currently running before upgrading. If it is, stout asks whether to proceed (which will quit the application) or skip it:

stout upgrade --cask docker
# Docker is currently running. Quit and upgrade? [y/N]

In non-interactive environments (CI, scripts), use --force to proceed automatically or --skip-running to skip applications that are in use.

Cask cleanup and disk management

GUI applications tend to be large. stout provides tools to manage disk usage:

# Show disk usage for installed casks
stout info --cask --sizes
# firefox           245 MB  (/Applications/Firefox.app)
# docker            2.1 GB  (/Applications/Docker.app)
# visual-studio-code 580 MB (/Applications/Visual Studio Code.app)
# Total: 2.9 GB

# Remove cached downloads
stout cleanup --cask
# Removing cached downloads...
# Freed 1.8 GB

Brewfile support for casks

Casks integrate with stout’s Brewfile/bundle management. Declare GUI applications alongside CLI packages:

# Brewfile
brew "git"
brew "jq"
brew "ripgrep"

cask "firefox"
cask "visual-studio-code"
cask "docker"
cask "slack"
stout bundle install --file Brewfile
# Installing 3 formulae and 4 casks...
# Formulae: git, jq, ripgrep (already installed)
# Casks: firefox (downloading...), visual-studio-code (downloading...),
#        docker (downloading...), slack (downloading...)
# All downloads parallel — total wall time: 12s

Cask downloads also benefit from stout’s parallel download infrastructure. Four large GUI application downloads happen concurrently, saturating your connection instead of serializing 3GB of downloads.

Uninstalling casks

Cask uninstallation removes the application and any associated files:

stout uninstall --cask firefox
# Removing Firefox.app from /Applications...
# Removing cached download...
# Uninstallation complete

On macOS, stout also removes associated files like preference plists and application support directories when they are defined in the cask metadata:

stout uninstall --cask docker --zap
# Removing Docker.app from /Applications...
# Removing ~/Library/Group Containers/group.com.docker/
# Removing ~/Library/Containers/com.docker.docker/
# Removing ~/.docker/
# Zap complete: all Docker files removed

The --zap flag performs a thorough removal, similar to Homebrew’s zap stanza, cleaning up all known associated files. Without --zap, only the application bundle itself is removed, leaving configuration files intact in case you reinstall later.

Security verification

Cask downloads are verified using SHA-256 checksums stored in the index, just like formula bottles. For casks from private indexes, Ed25519 signatures provide an additional layer of verification:

stout install --cask acme-dashboard
# Downloading acme-dashboard-1.2.0-x86_64.AppImage... done
# Verifying SHA256... OK
# Verifying Ed25519 signature... OK (signed by: acme-internal)
# Installing to ~/.local/bin/acme-dashboard

For macOS .dmg and .pkg files that are code-signed by the developer, stout verifies both the index checksum and the macOS code signature, providing defense in depth.

Need Rust performance engineering or AI agent expertise?

Neul Labs — the team behind stout — consults on Rust development, performance optimization, CLI tool design, and AI agent infrastructure. We build fast, reliable systems that ship.