My AI agents were eating my SSD
My laptop's SSD is 78% worn out. Earlier this month I found out my AI coding agents were writing about half a terabyte to it every day, which left it roughly seven weeks to live. Here is what was writing, what I changed, why moving the agents off the laptop wasn't enough, and what I think everyone running agents locally will hit next.
How I found out
I was shopping for a cheap mini PC to run tests around the clock, so I checked the health of the drive I already had. The answer was worse than I expected.
I'm building Renor, a memory layer for coding agents. On a normal day I run about 10 agents on one laptop, and up to 22 at the peak. They write code, review each other's PRs and run the test suite before every merge.
The SSD is a 512 GB NVMe drive. Its own health report said:
| What the drive reports | Value |
|---|---|
| Wear ("Percentage Used") | 78% |
| Total written | 85.6 TB |
| Rated life, implied by those two | about 110 TB |
| Spare blocks left | 100% |
| Data-integrity errors, lifetime | 889,881 |
| Full self-test | passed |
Then I measured the write rate: about 500 GB a day. At that pace the remaining ~24 TB lasts about seven weeks.
Nothing had warned me. The drive doesn't complain, the operating system doesn't complain, and none of my agents knew the disk was finite. My first reaction was: why did nobody tell me?
Where the writes came from
It took a day of measuring, per process and per cgroup, to find the sources. None of them was a bug. Each one was a reasonable default that multiplies badly when ten agents do it at once.
| Source | What I measured |
|---|---|
| Full test runs | 72 full runs on one day (12.1 hours of testing). One run wrote 12.7 GB in 16 minutes. |
| Reruns and duplicates | 17 reruns caused by tests that flaked under load; 22 of 99 runs in three days repeated a run that already existed. |
| Test scratch on disk | One test file wrote 1,266 MB with its temporary files on the SSD, and 3.8 MB with them in RAM. |
| Copies of the repo | 106 working copies, one per agent task, each with about 850 MB of dependencies and nothing shared between them. |
| Agent history | One agent tool kept every session in a single 22.9 GB SQLite file, rewritten in small pieces all day. |
| The browser | Brave wrote about 29 GB a day while I was doing nothing. WhatsApp Web alone rewrites its 60 MB local database about every 10 minutes. |
Most of the testing ran on the laptop for two reasons: the merge gate runs locally, and my private-repo GitHub Actions minutes had run out for the month.
The last piece surprised me most. About half of all writes belonged to no process at all. That was the filesystem's own overhead, plus thousands of short-lived commands (git, node, shells) that agents start and finish faster than any monitor can count them.
Why agents make this worse
A human developer runs the test suite a few times a day. An agent fleet runs it every time any agent wants to merge, and nobody is watching the meter.
One square is one full test-suite run
The agent count was measured on one day; the human count is only for scale
Four things stood out.
- Most of the data is throwaway. Scratch files, temporary databases and dependency copies live for minutes and then get deleted. They never needed to touch the SSD.
- Nobody can see it. Linux counts writes per process, but not per agent or per task. It took my agents and me a full day to work out who was writing what.
- There is no budget. Nothing knew the drive had about 24 TB left, so nothing slowed down. To each agent, 72 full test runs in a day looked normal.
- The filesystem multiplies small writes. btrfs never overwrites data in place. Every small change inside a big file (a database, a browser profile, a log) also rewrites a piece of the filesystem's index. Agent tools are full of exactly those files.
What I changed
I didn't buy anything. Every fix was a setting, a rule for the agents, or moving work somewhere free.
Three of the fixes, before and after
Each row has its own scale
| Fix | Effect |
|---|---|
| Open-sourced the engine, so its tests run on GitHub's free runners for public repos | The biggest half of the suite left the laptop. An engine check on the laptop now writes almost nothing. |
| The laptop runs only the website half of the tests, one run at a time, with no full runs and no benchmarks | A website test run now writes about 0.4 GB. |
Test scratch goes to RAM (/dev/shm) | 1,266 MB down to 3.8 MB for the worst test file |
| One shared dependency cache, copied with btrfs reflinks | New working copies share their dependencies instead of rewriting 850 MB each |
| Old working copies and history deleted | 342 GB used down to 176 GB; the disk went from 74% to 38% full |
| Browser cache moved to RAM | Brave's idle writes went from about 29 GB a day to about 8 (heavy use can still reach about 29) |
Copy-on-write turned off for the agent-history folder (chattr +C) | That SQLite file no longer drags the filesystem's index along with every change |
btrfs saves every 2 minutes instead of every 30 seconds (commit=120) | Fewer, larger flushes. The cost is up to 2 minutes of lost changes after a crash. |
| A health check every 6 hours, plus an alert above 100 GB a day | The next time this happens, somebody gets told |
Results
Daily SSD writes fell from about 500 GB to 50–90 GB
GB per day, averaged over each measured interval; gaps were not measured
/sys/block/nvme0n1/stat), 14–16 Oct 2026.The first night after the fixes, the laptop wrote 61 GB a day. Over the next day, which included a launch, it averaged 90 GB, with a quiet-hours floor of 51 to 55 GB. Test runs are no longer the main writer. The browser, the agent tools and filesystem overhead are.
Time until the drive reaches its rated life
Remaining rated endurance divided by daily writes
- 500 GB a daybeforeabout 7 weeks
- 90 GB a daytodayabout 9 months
- 40 GB a daymy targetabout 1.6 years
Rated life is not a cliff, and many drives keep working well past 100%. The integrity-error count hasn't moved since I started watching. But a drive with that history can still fail without warning, so the real protection is a backup, not a number.
Part two: the agents left, the writes didn't
Moving most of the agents to a server cut the laptop's load from about 20 to about 2. Writes only fell from 100–140 GB a day to about 90. So the agents weren't the whole story.
The per-process counters I had been using (/proc/<pid>/io) were hiding most of it. They can't read processes owned by root, they miss commands that finish within a second, and they never see the filesystem's own writes. The kernel's per-cgroup counters (io.stat under /sys/fs/cgroup) see all three.
Most writes were the filesystem's own bookkeeping
Share of everything written to the SSD, from the kernel's per-cgroup counters
Three things turned up:
- The drive had never been trimmed. dm-crypt, the Linux disk encryption layer, drops TRIM requests unless you allow them, and the weekly trim timer was off. The SSD never learned which blocks were free, so it kept moving dead data around internally. One command fixed it (
cryptsetup --allow-discards --persistent refresh), and the firstfstrimfreed 274 GiB. TRIM doesn't lower the GB written; it lowers how much flash wear each GB costs. - A voice-typing app had left a recording running. It saved microphone audio as a new small file every 0.3 seconds. I suspect that pattern fed a lot of the filesystem's bookkeeping, but I haven't proven it.
- A broken service was crash-looping. It restarted every few seconds because a model file was missing, and its errors added about 6 GB a day to the system log. Stopping it took the log down to under 1 GB a day.
What the drive knew about its own free space
The 512 GB drive as 100 squares of about 5 GB each
The stuck recording, six seconds of it
I also switched the mounts from relatime to noatime, so reading a file no longer updates its access time on disk.
Where it stands: the last full day was 90 GB. That's still more than twice my 40 GB target, and leaves about 9 months of rated life at this pace. It's too early for TRIM to show in the wear percentage. Next I'll count which programs force the disk to sync (fsync) and move the worst ones to RAM.
If you run agents on your own machine
Most of this takes about ten minutes. Start with these five commands:
# wear and total written $ sudo smartctl -a /dev/nvme0 | grep -E 'Percentage Used|Data Units Written' # GB written since boot $ awk '{print $7*512/1e9, "GB"}' /sys/block/nvme0n1/stat # 0 means TRIM never reaches the encrypted drive $ cat /sys/block/dm-0/queue/discard_max_bytes $ systemctl is-enabled fstrim.timer # how much the system log holds $ journalctl --disk-usage
Then work down the list:
- Read your drive's health. "Percentage Used" and "Data Units Written" from
smartctl. Note them today and compare next week. - Measure a day of writes. The 7th field of
/sys/block/nvme0n1/statis sectors written. Read it twice, 24 hours apart, and multiply the difference by 512 bytes. - Count by cgroup, not by process.
io.statunder/sys/fs/cgroupincludes root processes, short-lived commands and the filesystem's own writes. Per-process counters miss all three. - Check that TRIM reaches the drive. On an encrypted disk,
discard_max_bytesmust not be 0, andfstrim.timershould be enabled. - Put scratch in RAM. Point
TMPDIRfor test runs at a tmpfs such as/dev/shm. - Share dependencies across worktrees. Use reflinks, hardlinks or a content-addressed store like pnpm's.
- Stop duplicate runs. If two agents want the same test run on the same commit, run it once and share the result.
- Use free CI for anything public. Public repos get GitHub-hosted runners at no cost.
- Look at your browser. A long-lived profile with web chat apps open can write tens of GB a day.
- Check your logs and background apps. A service stuck restarting, or an app recording in the background, can write gigabytes a day.
What's next: a write budget for agent fleets
Every fix above was manual. As agent fleets grow, I think this needs to be automatic, the way a cloud bill has a budget.
The tool I want to build next has three parts:
- A daily budget from the drive's real health. Remaining endurance divided by how long you want the drive to last. For my drive, about 24 TB over two years is roughly 33 GB a day.
- Writes counted per agent and per task. Each agent or test run gets its own cgroup, so the kernel's own counters say exactly who wrote what.
- Placement by how long data lives. Scratch that dies in minutes goes to RAM. Only data that has to survive goes to the SSD. When the day's budget runs low, heavy jobs wait or move to CI instead of grinding the disk.
How the write budget would work
Storage hardware already places data by expected lifetime internally. Doing it at the level of an agent fleet, with a budget tied to the drive's health, is the part I haven't seen yet. If you have, or if your agents have done this to your disk too, I'd like to hear about it.