This machine was installed on 2026-04-25. That was 105 days ago. In that time it accumulated 1,598 packages taking up 23.29 GiB, and I had no idea what most of them were until I sat down and counted.
So I counted. Here's what a real Arch desktop looks like after three and a half months of unsupervised growth, and the commands I used to find out.
The top-line numbers
- 1,598 packages installed
- 240 of them explicitly requested by me
- 32 from outside the official repos (AUR and friends)
- 15 orphans — installed as dependencies, now depended on by nothing
- 23.29 GiB on disk
The gap between 1,598 and 240 is the interesting part. Roughly 85% of what's on this disk arrived as a dependency of something I asked for. That ratio is normal and healthy — it's what a package manager is for — but it means "what did I install" and "what is installed" are completely different questions, and only the first one is answerable from memory.
pacman -Qq | wc -l # everything
pacman -Qeq | wc -l # explicitly installed
pacman -Qmq | wc -l # foreign (AUR, local builds)
pacman -Qdtq | wc -l # orphansThe AI agents are eating the disk
This is the number that made me write the post.
Eighteen packages on this system are AI coding agents or AI-adjacent terminals. Together they take 3.81 GiB.
For scale, I added up 72 packages of GNOME — the shell, mutter, gdm, nautilus, gvfs, the whole core app set, orca, papers, loupe, all of it. That comes to 0.37 GiB.
Eighteen AI tools weigh ten times the entire desktop environment they run on.
The full list, because I think the list itself is the argument:
claude-code,claude-desktop-binopenai-codexgemini-cligithub-copilot-cliopencode,opencode-desktop-binantigravity,antigravity-cli,antigravity-idepi-coding-agent,pi-studio-bin,oh-my-pi-bindeepseek-reasonix-tui-bin,deepseek-reasonix-desktop-bincodewhale-binterax-ai-binzap-oss-bin
Ten different upstreams. Five of them ship both a terminal client and a desktop GUI as separate packages, so I'm carrying two copies of the same product five times over.
The size isn't because AI is inherently heavy. It's because almost every one of these ships its own runtime. antigravity-ide is 694 MiB. claude-desktop-bin is 538 MiB. github-copilot-cli — a *CLI* — is 373 MiB. Each one bundles a Chromium or a Node it didn't need to bundle, because shipping a tarball with everything inside is easier than depending on the distro's electron42, which is also installed at 329 MiB and which exactly one of my tools (paseo) actually reuses.
The distro solved this problem decades ago. The current generation of tooling has decided the solution isn't worth the packaging effort. On a 512 GiB SSD that's a rounding error, so nobody will fix it, and I can't really claim to be upset — I installed all eighteen.
Duplicate layers, counted honestly
Once you start counting one category you start counting all of them. Every line here is a real duplicate on this machine right now:
JavaScript package managers — 4: npm, pnpm, yarn, bun. Plus npm ls -g shows pnpm and yarn *also* installed globally through npm, so two of them exist twice through different paths.
JavaScript runtimes — 3: nodejs 26.7.0, bun 1.3.14, deno 2.9.5.
Terminal emulators — 5: ghostty, gnome-console, zt (a minimal one in Zig), zap-oss-bin and terax-ai-bin (both AI terminals). Only one can be the default.
Browsers — 4: firefox, librewolf-bin, google-chrome, epiphany.
Editors and IDEs — 8: nano, vim, neovim, emacs-wayland, gnome-text-editor, zed, visual-studio-code-bin, antigravity-ide.
Kernels — 3: linux 7.1.6, linux-lts 6.18.42, linux-zen 7.1.6, each with headers. This one is deliberate — LTS is the fallback that boots when a mainline update breaks something — and it's the only duplicate on this list I'd defend without hesitation.
Version managers — 3: mise, rustup, uv, each managing toolchains the others can also manage.
Fonts deserve their own line: 11 font packages, 1.25 GiB, more than three times the GNOME desktop. Almost all of it is CJK. That's not waste — a CJK face genuinely needs tens of thousands of glyphs, and I wrote a whole post about getting fontconfig to pick between them. But it does mean the two heaviest things on this laptop are Chinese typography and AI agents, which is a fair summary of what I do with it.
Chat clients: 5 packages, 1.77 GiB, and yes, they're all Electron too.
The commands worth keeping
The specific numbers above are mine and won't match yours. The commands will.
Everything by size, largest first. pacman -Qi reports sizes in mixed units, which breaks a naive sort, so normalise to KiB first:
LC_ALL=C pacman -Qi | awk '
/^Name/ { n = $3 }
/^Installed Size/ {
s = $4; u = $5
if (u == "MiB") s *= 1024
else if (u == "GiB") s *= 1024 * 1024
else if (u == "B") s /= 1024
printf "%10.0f KiB %s\n", s, n
}' | sort -rn | head -25The LC_ALL=C matters. Under a localised setup pacman -Qi prints translated field names and every /^Name/ match silently returns nothing — the script produces empty output and looks like a bug in your awk.
Total size of an arbitrary set of packages. Same normalisation, summed. This is how I got the AI-versus-GNOME comparison:
LC_ALL=C pacman -Qi $(pacman -Qq | grep -E '^gnome') 2>/dev/null | awk '
/^Installed Size/ {
s = $4; u = $5
if (u == "MiB") s *= 1024; else if (u == "GiB") s *= 1024 * 1024
t += s; c++
}
END { printf "%d pkgs, %.2f GiB\n", c, t / 1024 / 1024 }'What am I actually carrying from outside the repos?
pacman -QmThirty-two lines on this machine. This is the list that matters most, because these packages don't get the same eyes on them as the official repos, and a stale AUR package is how you end up running something the upstream abandoned a year ago.
What is this thing and why is it here?
LC_ALL=C pacman -Qi <pkg> | grep -E '^(Name|Description|URL|Required By)'
pactree -r <pkg> # who pulled it in, needs pacman-contribRequired By: None on an explicitly installed package means you asked for it and nothing else needs it — a candidate for removal that pacman -Qdt will never show you, because orphan detection only covers packages installed *as dependencies*.
When did this arrive?
grep -E ' installed ' /var/log/pacman.log | tail -40
head -1 /var/log/pacman.log # the moment the machine was bornThat last one is how I know this install is 105 days old. The first line of pacman.log is the bootstrap command from the installer, timestamped. It's the closest thing a Linux box has to a birth certificate.
Cleaning the obvious slack:
pacman -Qdtq | wc -l # count orphans first, always look before removing
sudo pacman -Rns $(pacman -Qdtq) # remove them and their now-unneeded deps
paccache -d # dry-run the package cache cleanup
sudo paccache -rk2 # keep the 2 most recent versions of eachpaccache is in pacman-contrib. On a system that's been through 105 days of rolling updates, the cache is usually the single largest easy win — larger than anything you'd feel bad about uninstalling.
What I actually took away from this
The dependency graph is not the problem. 1,358 packages I never asked for sounds alarming until you realise that's the package manager doing exactly its job, deduplicating shared libraries across 240 things I did ask for. GNOME being 0.37 GiB across 72 packages is that system working. The 3.81 GiB across 18 bundled AI tools is that system being bypassed.
Counting a category is more useful than counting packages. "1,598 packages" told me nothing. "18 AI agents at 3.81 GiB versus 72 GNOME packages at 0.37 GiB" told me something I'd act on. Sum by category, not by package, and pick categories that correspond to decisions you actually make.
The duplicates I can defend and the ones I can't are easy to tell apart, once written down. Three kernels: defensible, that's a recovery plan. Four JavaScript package managers: not defensible, that's just what happens when every project's README opens with a different install command. Writing the list is what makes the difference obvious — none of it was obvious while it was accumulating one paru -S at a time.
I haven't uninstalled anything yet. The audit was the point. But I now know that the next time this laptop runs out of disk, I know exactly which eighteen packages to look at first.




No comments yet