Releases: itchio/butler
v15.26.1
Version identity bug in v15.25.0 and v15.26.0
v15.25.0 and v15.26.0 were shipped with an incorrect version string: they identified themselves as head instead of their actual version. Butler uses its built-in version to determine which update channel to check: builds marked as head check the development channel, while stable builds check the stable channel. Because v15.25.0 and v15.26.0 incorrectly identified as head, running butler upgrade on either of these versions would switch you to the development line instead of staying on stable releases.
If you are currently on v15.25.0 or v15.26.0, we recommend re-downloading butler from https://broth.itch.zone/butler to ensure you are back on the stable update channel. You can verify your version with butler version, it should show v15.26.1 with a commit hash, not head.
Bug Fixes
- Fix version string in builds: CI builds were always reporting version as "head" regardless of the git tag. Build scripts now correctly use GitHub Actions native environment variables to inject version, commit hash, and build timestamp into the binary.
- Fix Wine launch failures: Fixed an issue where launching
.exefiles through Wine could fail when the{{EXT}}template action couldn't locate the executable path.
v15.26.0
This feature release primarily contains updates for butlerd, the part of butler that services the itchio app. CLI updates below.
butlerd (daemon)
New Features
- Stdio transport mode (
--transport stdio) — reads JSON-RPC from stdin, writes to stdout, logs to stderr. No authentication required (inherently secure via parent process pipe). Supports single connection only. Install.GetUploads— fast endpoint returning available uploads for a game (~100ms, no file I/O). Returns game object and filtered upload list.Install.PlanUpload— cancelable planning for a specific upload. Accepts optionalidparameter for cancellation viaInstall.Cancel. Performs network I/O and file inspection.Caves.GetSettings/Caves.SetSettings— per-cave configuration stored as JSON in the database. Settings include sandbox overrides (Sandbox,SandboxType,SandboxNoNetwork,SandboxAllowEnv) and extra launch arguments (ExtraArgs).SandboxOptionsin Launch — fine-grained sandbox configuration per launch:Type(auto/bubblewrap/firejail/flatpak/fuji),NoNetwork,AllowEnv.CaveSettings.ExtraArgs— per-cave extra command-line arguments appended after manifest args at launch.
Improvements
- Hard limits on lazy fetches to prevent excessive resource consumption: collection games capped at 2000 items, owned keys at 5000 items. Warns when limits are reached.
- Fix quadratic operation for collection and library sync, which could cause butlerd to lock up when synchronizing larger collections
- Structured logging (slog) for database queries, HTTP requests, and DB migrations. New
slogHandlerconverts slog records to comm's JSON message format. Enable HTTP debug logging withBUTLER_HTTP_DEBUG=1. - butlerd.json spec now includes result types, precise enum values (int, bool, string), and
@deprecatedtags on endpoints and types. - Thread-safe cancellation with new
MakeCancelablehelper onRequestContext. Mutex protection on cancel funcs map. - Prefer system-installed firejail over prereqs version when available.
Deprecations
Install.Plan— useInstall.GetUploads+Install.PlanUploadfor cancellation support.Install.Planstill works but internally delegates to the new endpoints.
Bug Fixes
- Fixed install plan not actually being cancelable (was using wrong context).
- Prevented non-JSON logging from being sent to stdout when in stdio mode (redirected to stderr).
butler CLI
Improvements
- Fixed context/goroutine leaks in
push,fetch,login,statuscommands (DefaultCtxnow returns a cancel func that must be called). - Pointer semantics for
CompressionSettingsindiffandsigncommands.
Bug Fixes
- Fixed variable shadowing bug in
pushfinalize that could report the wrong error.
Dependency Updates
smaug (sandboxing)
- New: Bubblewrap Linux sandbox backend with persistent per-game home directory (
{InstallFolder}/.itch/home), GPU/audio/display support, PID/UTS namespace isolation, and controller input device access. - New: Flatpak-spawn sandbox for running inside Flatpak containers. Auto-detected via
/.flatpak-info. Usesflatpak-spawn --sandboxwith optional network isolation. - New: Centralized
SandboxConfigstruct with type selector replacing scattered per-platform parameters. Auto-selection priority on Linux: Flatpak-spawn → Bubblewrap → Firejail. - New: macOS sandbox policy modes —
balanced(strict, default) restricts/devaccess;legacyallows broader compatibility for problematic games. - New: Rosetta 2 support — x86 games can now run sandboxed on Apple Silicon Macs.
- Improved: Cryptographically secure Windows sandbox account passwords using
crypto/rand. - Improved: Unified network control (
NoNetwork) across all sandbox backends (bubblewrap:--unshare-net, flatpak-spawn:--no-network, firejail:--net=none, macOS: conditional policy rules). - Improved: Centralized environment variable allowlists per platform prevent accidental info leaks.
- Fixed: Windows fuji sandbox "access denied" error on first launch — ACL permission propagation may not be immediate, so process start now retries on
ErrPermission(up to 7 attempts with 1s delay).
screw (file operations)
- Fixed: macOS memory leak in
TrueBaseName— C string fromGetCanonicalPathwas not being freed. - Improved: Rollback error handling now reports both the rollback error and original error together via
errors.Join.
wharf (patching)
- Updated: Regenerated protobuf definitions with modern protobuf toolchain.
hades (database ORM)
- Breaking: Query logging migrated from headway
Consumertoslog.Logger.Contextstruct now usesLogger *slog.Loggerinstead ofConsumer *state.Consumer. NewContextno longer requires aConsumerargument.
boar (archive extraction)
- Updated to libc7zip 1.9.0.
- Added Windows ARM64 (
windows-arm64) builds, removed 32-bit Linux (linux-386).
go-itchio (API client)
- Added
slog.Loggersupport for structured HTTP request logging, used by butler'sBUTLER_HTTP_DEBUGflag.
httpkit (HTTP file transport)
- Made debug logging more granular.
ox (Windows process launching)
- Fixed Windows game launching (fuji sandbox and simple runner) broken by Go 1.24
os.Processinternals change. Replaced unsafe reflection hack withos.FindProcess. - Fixed thread handle leak in process launching when
SysProcAttris nil.
lake (protocol buffers)
- Migrated from
github.com/golang/protobuftogoogle.golang.org/protobuf. Regenerated.pb.gofiles with modernprotoctoolchain. Replacedcopystructuredeep-clone withproto.Clone.
v15.25.0
New Builds
Linux ARM64 (aarch64)
Butler now builds natively for Linux ARM64, and those builds are published to broth.
macOS ARM64 (Apple Silicon) + Universal Binary
Butler now builds natively for macOS ARM64. A universal binary (x86_64 + arm64 via lipo) is also produced and code-signed. The ox dependency was updated to support ARM architecture detection.
Note: we may stop generated universal builds in the future, testing it out to see if it's useful to anyone
Breaking Changes
Linux minimum glibc raised from 2.28 to 2.31
Linux binaries are now built on Debian Bullseye, raising the minimum required glibc from 2.28 to 2.31. Users on older Linux distributions (e.g. Debian Buster) may need to upgrade.
Build & CI/CD
New GitHub Actions Build & Release Workflow
We have migrating building and releasing binaries of butler to GitHub actions. The new workflow includes all new job pipelines for signing and notarizing builds. Builds are published to broth directly from GitHub actions.
Windows executables are now signed with Azure Trusted Signing.
CI Modernization
- Go version: Upgraded from Go 1.14/1.23 to Go 1.24.0. All CI workflows now use
go-version-file: 'go.mod'instead of hardcoding versions.
Helper Makefile
New Makefile with build, install, test, and clean targets for local development convenience.
Dependency Updates
Major dependency upgrades across the board. Many itchio dependencies were bumped to modern Go with enhancements and cleanups.
| Dependency | Old | New | Highlights |
|---|---|---|---|
itchio/arkive |
2020 | 2026-01-29 | Proper error handling for password protected zips |
itchio/boar |
2024-12-12 | 2026-01-29 | Support for libc7zip arm on linux and macOS |
itchio/dash |
2020 | 2026-01-28 | |
itchio/go-itchio |
2020-08-26 | 2025-12-29 | Includes new OAuth login API methods |
itchio/headway |
2020 | 2025-12-29 | |
itchio/httpkit |
2020 | 2025-12-31 | |
itchio/hush |
2020 | 2026-01-23 | Updated extensions for naked apps |
itchio/ox |
2020 | 2026-02-04 | Ability to detect arm architecture from host machine |
itchio/savior |
2020 | 2026-01-28 | |
BurntSushi/toml |
0.3.1 | 1.6.0 | |
mitchellh/mapstructure |
1.3.2 | 1.5.0 | |
golang.org/x/crypto |
0.31.0 | 0.47.0 | |
golang.org/x/sync |
0.10.0 | 0.19.0 | |
golang.org/x/sys |
0.28.0 | 0.40.0 | |
golang.org/x/text |
0.21.0 | 0.33.0 | |
golang.org/x/time |
2020 | 0.14.0 | |
klauspost/compress |
1.10.9 | 1.18.3 | |
stretchr/testify |
1.6.1 | 1.11.1 |
Documentation
Migrated from gitbook to honkit for documentation building. Docs deployed from master into GitHub pages.
Expanded Installation Guide
The docs/installing.md was completely rewritten with:
- Platform-specific step-by-step installation instructions (Windows, Linux, macOS)
- Verification steps for each platform
- Clarified broth URLs as permanent (vs expiring itch.io download links)
- New appendix: "Using butler from the itch app" with paths for each platform and how to find the current version
New Troubleshooting Page
Added docs/troubleshooting.md covering common issues: PATH errors, incorrect directory paths, spaces in file paths, invalid target errors, authentication problems, project page requirements, and firewall/antivirus issues.
butlerd
OAuth Login with PKCE Support
New Profile.LoginWithOAuthCode butlerd endpoint that allows the itch.io desktop app to authenticate users via OAuth authorization code exchange with PKCE. This accepts an authorization code, PKCE code verifier, redirect URI, and client ID — and returns the user profile along with a website cookie. The OAuth client ID is no longer hardcoded; it is provided as a parameter by the caller.
Unlike the existing LoginWithPassword and LoginWithAPIKey endpoints, the OAuth result also returns a Cookie map, enabling the desktop app to synchronize website login state after authentication.
butlerd NPM Package Rename
The butlerd npm package has moved to https://www.npmjs.com/package/@itchio/butlerd
The generous support path changed from butlerd/lib/support to @itchio/butlerd/lib/support.
butlerd Spec Updates
- Added
Profile.LoginWithOAuthCoderequest tobutlerd.jsonspec - Added
metadatafield (type{ [key: string]: any }) toCandidatetype in spec
v15.24.0
- Fix bug where numbered releases didn't have the version number baked in the executable (only affected v15.23.0)
- Build across all platforms with most recent version of go (1.23.4)
- Update some go dependencies
- Fix outdated
.itch.ovhdomain in utility library (boar)
v15.23.0
v15.21.0
v1.0.1
Because of a flawed resume check, the unzip command in v1.0.0 skipped over the first file of the zip archive. v1.0.1 fixes this.
v1.0.0
v1.0.0 introduces many new concepts in butler, @elisee asked me what was new so, here it goes:
Manifests (intro)
One big feature is dividing containers in blocks. Up till then we had "archives" (containers compressed as a .zip file), "signatures" (MD5 hashes of <=16KB blocks), and "patches" (list of instructions).
This release introduces a new file format, "manifests", which contains SHAKE256 32-bit hashes of 4MB blocks. They're supported by the "ls" and "file" command, and most of the code writing or reading it is available in the blockpool package of wharf.
There are no new user-facing commands in butler allowing the creation of manifests, this will come in later releases, more details in the later sections.
Healing
Another big feature is healing: given a signature and a heal source, the verify command can now redownload parts of files that were corrupted. It'll also restore missing directories and missing/corrupted symlinks.
Note that when --heal is used, the exit code behavior of verify is modified: it'll now return 0 if it healed everything successfully, whereas without --heal it would've returned 1.
Plans: The apply command will also get a --heal parameter, so that if patch application fails for a reason or another, it'll be able to heal the result, instead of forcing the butler user to fall back to a full re-download.
itchfs
For healing to be interesting, the heal source must be remote — and yet verify's --heal parameter accepts a local path.
However, butler now accepts, for all path arguments, itchfs:///XXX urls. All valid URLs can be devised from the sources.go file of go-itchio.
Note that the API key is passed as a query parameter.
- Example URL:
itchfs:///upload/3/download?api_key=XXX
(Yes, that's three slashes - the third is the root, much like file:///etc/hosts)
This means, when an itchfs is passed to the --heal parameter of the verify command, butler will only download the parts of the remote .zip file it needs to heal the local container. Due to the structure of the .zip format, this is relatively efficient:
- First request establishes the size of the file
- Second request to seek to the end and read the Central directory
- Then, reading from any files is just an additional request. If files are read in-order, the same request is re-used throughout.
The itch.io-specific parts are in go-itchio, the io.ReaderAt interface for remote files can be found in httpkit.
Note that the remote server must support the Range HTTP header and respond with a 206 partial content, otherwise an error is thrown.
itchfs is implemented in a pluggable way, which means other vendors are welcome to come up with their own URL schemes and build a version of butler that supports them (for example, for building their own launcher/updater system).
Resumable unzip
The unzip command now accepts a --resume-file parameter. With itchfs URLs, it can be used to download and extract a file at the same time (and resume at the beginning of the last file it was working on, using the resume file's info).
BPS / ETA
All progress-emitting commands now output eta (estimated time remaining, in seconds) in json output mode. They also now emit progress (floating number between 0.0 and 1.0) in addition to percent (floating number between 0.0 and 100.0, kept for backwards compatibility for now).
A few commands (like unzip, cp) are also getting bps (bytes per second processed). This is useful to show download/processing speed graphs:
Manifests (plans)
The big idea for manifests is for them to be usable as a heal source for verify, apply, and as an argument to a new command unsplit. Since manifests are only a list of hashes, access control is left as an exercise to the user — for itch.io, it'll be implemented in the form of download sessions tied to a certain set of blocks, expiring, and started with a valid itch.io API key, which allows for monitoring of abuse and prevents Dropshipping blocks.
v0.1.4
Better release support on travis+S3
v0.1.3
Auto S3 deployment fiddling
