Set the macOS wallpaper on every Space across every display in one command.
On macOS, the public wallpaper APIs (NSWorkspace.setDesktopImageURL, Finder AppleScript, osascript "tell application \"System Events\"") are scoped to the currently-visible Space on each display. That's by design — it's the surface Apple exposes. If you want to change the wallpaper on every Mission Control Space at once, there isn't a public API for it.
wallall fills that specific gap by writing directly to WallpaperAgent's Index.plist under AllSpacesAndDisplays.Desktop and then restarting the agent. Every Space on every display picks up the new image at once, because they all fall through to the single global entry.
- macOS 14 Sonoma or newer (the WallpaperAgent-based wallpaper subsystem)
- Python 3 (bundled with Xcode Command Line Tools —
xcode-select --installif needed)
Pick any directory on your PATH. /opt/homebrew/bin on Apple Silicon, /usr/local/bin on Intel, or ~/.local/bin if you prefer per-user installs.
One-liner (adjust the target directory for your setup):
BIN=/opt/homebrew/bin # or /usr/local/bin, or ~/.local/bin
curl -fsSL https://raw.githubusercontent.com/treschar/wallall/main/wallall \
-o "$BIN/wallall" && chmod +x "$BIN/wallall"Or clone and symlink:
git clone https://github.com/treschar/wallall.git
cd wallall && ln -sf "$(pwd)/wallall" /opt/homebrew/bin/wallallwallall is a single-file Python script with no dependencies and no build step — you can also just drop it anywhere reachable from PATH.
wallall ~/Pictures/spacey.jpg # set on every Space + every display
wallall --status # print current wallpaper state
wallall --revert # restore the backup taken on first runOn the first run wallall copies Index.plist to Index.plist.wallall-backup so --revert is always available.
Starting in macOS 14, the wallpaper subsystem lives in a single binary plist:
~/Library/Application Support/com.apple.wallpaper/Store/Index.plist
Its top-level keys are:
AllSpacesAndDisplays— the global wallpaper entry (Desktop + Idle)Displays[<uuid>]— per-display overridesSpaces[<uuid>]— per-Mission-Control-Space overrides
When AllSpacesAndDisplays.Desktop is populated (and Type = "desktop"), WallpaperAgent uses it as the source of truth for every Space across every display — regardless of whatever entries exist in Spaces[]. The per-Space entries become dormant until AllSpacesAndDisplays is cleared.
The public macOS wallpaper APIs (NSWorkspace.setDesktopImageURL, Finder AppleScript, osascript) take the opposite path: they write to the currently-visible Space's own Desktop entry and leave AllSpacesAndDisplays alone. That's why changing wallpaper through the normal paths only affects the Space you're looking at — the global entry never gets touched.
wallall writes to AllSpacesAndDisplays.Desktop directly and then restarts WallpaperAgent. The single global write propagates to every Space on every display in one shot.
The Configuration field inside each Desktop entry is itself a nested binary plist encoding an NSURL-ish structure ({type: "imageFile", url: {relative: "file:///..."}}). Python's plistlib handles both layers natively, which is why wallall is a single-file script with zero dependencies.
- Just need to set the wallpaper on your current Space on one display? The built-in
osascript/NSWorkspacepath is simpler and doesn't touch the Index.plist. - Want a well-maintained CLI with multi-display support, colors, screensavers, etc.?
desktoppris a great option and covers most use cases. - Need every Mission Control Space to match, simultaneously, without clicking through them? That's what
wallallis for.
Built for a colorscheme manager that theme-swaps ghostty, tmux, sketchybar, starship, and the desktop wallpaper in one shot. Every tool in the pipeline could follow the colorscheme cleanly except the wallpaper, which would change on the current Space and then drift on all the others. After digging through the macOS 14+ wallpaper subsystem to understand why, this tool fell out.
- macOS 14+ only. Earlier versions used a completely different subsystem (
~/Library/Application Support/Dock/desktoppicture.db) that this tool doesn't touch. - Single static image only. No slideshow / shuffle / multi-image. (PRs welcome.)
- Not signed or notarized. Run it from source; it's a plain text script.
- Edits a file inside
~/Librarythat Apple considers private. The schema could change in any macOS point release. The--statuscommand prints the current state so you can diff across versions if something breaks.
MIT. See LICENSE.