Summary
OpenCode Desktop stages a full copy of the CLI binary into cli/<version>/ on every CLI version change, but the existing stage-cleanup code never runs in packaged builds because it is gated behind a development-only flag. Each build is roughly 175 MB, so disk usage grows without bound (1.4 GB after 10 days and 8 releases in my case).
Environment
- opencode version: 2.0.24 (desktop,
latest channel)
- OS: macOS 27.0.1 (Darwin 27.0.0, arm64)
- Terminal: N/A (Desktop app)
- Shell: /bin/zsh
- Install/channel: Desktop app, channel
latest (app-update.yml, provider generic)
- Active plugins: none configured (MCP servers only)
Reproduction
- Install OpenCode Desktop and keep it updated across several releases (I accumulated 8 CLI builds between 2026-09-27 and 2026-10-06).
- Inspect
~/Library/Application Support/ai.opencode.desktop/cli/ (macOS; %APPDATA%/ai.opencode.desktop/cli on Windows, ~/.config/... on Linux).
- Observe one directory per CLI version, each ~171 to 180 MB, none removed.
Expected Behavior
Stale CLI builds should be pruned on startup, keeping disk use bounded to a few hundred MB instead of growing with every release.
Actual Behavior
Every version is retained forever.
180M 2.0.6 2026-09-27
171M 2.0.18 2026-09-27
171M 2.0.19 2026-09-29
172M 2.0.20 2026-09-30
172M 2.0.21 2026-10-01
172M 2.0.22 2026-10-02
171M 2.0.23 2026-10-05
176M 2.0.24 2026-10-06 <- only this one is in use
1.4G total
Additional Context
A cleanup function already exists. cleanStages in packages/desktop/src/main/service/desktop-cli.ts removes every sibling directory under the staged CLI root while keeping the current one. It is correct and the shipped 2.0.24 bundle contains it.
The problem is the only call site, in packages/desktop/src/main/service/background-service.ts:
const isolated = !app.isPackaged && process.env.OPENCODE_DESKTOP_ISOLATED_SERVER === "1"
...
if (mode === "initial" && isolated && cli.binary) yield* cleanStages(cli.binary).pipe(Effect.orDie)
isolated is !app.isPackaged && ..., so it is false in every packaged build and cleanStages never runs for released apps.
Staging, by contrast, does run in production. resolveBundledCli in the same file calls installCli(bundled, version) whenever app.isPackaged || isolated, which is always true for a released app.
So the net behavior is: production stages a new build on every version change and never prunes.
Suggested fix: invoke cleanStages under the same condition that triggers staging, app.isPackaged || isolated, so packaged builds prune on startup. This is a one line change in background-service.ts and would also self-heal existing installs on the next launch.
Related but distinct: #24255 (prunes Bun's install cache at ~/.bun/install/cache/, a different path), #29037 (cache management UI, closed as not planned), #37495 (SQLite WAL growth).
Workaround for affected users: delete all but the newest directory under cli/.
Summary
OpenCode Desktop stages a full copy of the CLI binary into
cli/<version>/on every CLI version change, but the existing stage-cleanup code never runs in packaged builds because it is gated behind a development-only flag. Each build is roughly 175 MB, so disk usage grows without bound (1.4 GB after 10 days and 8 releases in my case).Environment
latestchannel)latest(app-update.yml, providergeneric)Reproduction
~/Library/Application Support/ai.opencode.desktop/cli/(macOS;%APPDATA%/ai.opencode.desktop/clion Windows,~/.config/...on Linux).Expected Behavior
Stale CLI builds should be pruned on startup, keeping disk use bounded to a few hundred MB instead of growing with every release.
Actual Behavior
Every version is retained forever.
Additional Context
A cleanup function already exists.
cleanStagesinpackages/desktop/src/main/service/desktop-cli.tsremoves every sibling directory under the staged CLI root while keeping the current one. It is correct and the shipped 2.0.24 bundle contains it.The problem is the only call site, in
packages/desktop/src/main/service/background-service.ts:isolatedis!app.isPackaged && ..., so it is false in every packaged build andcleanStagesnever runs for released apps.Staging, by contrast, does run in production.
resolveBundledCliin the same file callsinstallCli(bundled, version)wheneverapp.isPackaged || isolated, which is always true for a released app.So the net behavior is: production stages a new build on every version change and never prunes.
Suggested fix: invoke
cleanStagesunder the same condition that triggers staging,app.isPackaged || isolated, so packaged builds prune on startup. This is a one line change inbackground-service.tsand would also self-heal existing installs on the next launch.Related but distinct: #24255 (prunes Bun's install cache at
~/.bun/install/cache/, a different path), #29037 (cache management UI, closed as not planned), #37495 (SQLite WAL growth).Workaround for affected users: delete all but the newest directory under
cli/.