The Write-Side Context Tax: The Append That Secretly Reads the Whole File
"Append a line" sounds free — in most tooling it secretly reads and rewrites the whole file first. The read-side context tax has a write-side twin: read-modify-write in disguise.
"Append a line" sounds like the cheapest write there is. In most tooling it secretly reads and rewrites the entire file first — and nobody looks, because the word "append" tells you there's nothing to see. It's an old bug wearing a new coat: a read-modify-write hiding behind the friendliest name in I/O.
(Companion to The Context Tax. That one was about reads getting re-billed every turn. This is a single write that hides a whole read.)
The problem: an append that isn't one
Our orchestrator writes to state files constantly — a log row here, a status update there. The naive way to add one line is the way most code does it: read the whole file into memory, tack the line on the end, write the whole thing back. It works. It also means every one-line append pays to read the entire file it's appending to.
In our archive logs that was an observed ~60 KB read to add two short lines — call it ~200 bytes. (That ~60 KB is a real number from our own setup, not a controlled benchmark — take the shape, not the exact digits.) It had sat there unnoticed because "append" reads as free. The read-side tax from part one had a write-side twin the whole time.
This pattern has a name, and it predates agents by decades: read-modify-write. Databases hit it maintaining indexes, RAID controllers hit it updating parity, and now your agent hits it writing a log line. The lesson every time is the same — if you read the whole thing to change a small part of it, the read is the cost, not the change.
The fix: actually append
True append-mode I/O: open the file for append, write only the new bytes, never read-then-rewrite. If you need to confirm the write landed, seek to the tail and check there — don't re-read the file to verify it.
# The tax: every append re-reads and rewrites the whole file
with open(path) as f:
data = f.read()
with open(path, "w") as f:
f.write(data + line)
# The fix: append mode writes only the new bytes
with open(path, "a") as f:
f.write(line)
You don't need a dependency for this — append mode is stdlib in every language. And it's worth knowing the popular "safe file write" libraries won't save you here: they make whole-file replacement atomic by writing a full copy and renaming it, which for an append is read-modify-write — the very tax you're trying to dodge.
We shipped it as a small path-scoped helper the tooling now calls instead of hand-rolling file writes. The point of the helper isn't tidiness. It's that the cheap path becomes the only path — you can't accidentally take the expensive one, because the expensive one is no longer reachable from the code that writes logs.
The math is blunt: ~60 KB to add ~200 bytes is roughly a 300× overhead — and it grows with the file, so a bigger log means a bigger multiple. (Same observed number as before, not a benchmark.) Re-computed work, re-billed tokens, invisible until you measure it.
Two lessons that generalize
Audit the write path, not just the read path. Everyone optimizes what they load into context. Almost nobody notices a trivial "append" doing a full-file read underneath — the name promises it's nothing, so the profiler in your head skips it. Part one said pass conclusions, not payloads. Same instinct, other direction: watch what your writes secretly drag along with them.
The obvious retry is the bug. When a write's verify step fails, the reflex is "retry the write." For an append that's wrong: the first write may have already landed, so retrying writes the line twice. Append isn't idempotent. Retry the read-back, not the write — confirm what's actually on disk before you redo anything.
The takeaway
Cheap-sounding operations are where waste hides, precisely because their names tell you not to look. Append that only appends. Verify by seeking, not re-reading. And when a non-idempotent write looks like it failed, re-check before you redo it.
And it's worth remembering what those re-read bytes cost. In an agent, re-reading a file just to append to it isn't only slower — it's more tokens through the model, and tokens are GPU time: power drawn and water evaporated to cool the datacenter. Trim the bytes and the saving flows downstream — cheaper, faster, and quietly greener. The same move paying off three ways.
FAQ
Isn't "append" already efficient?
Usually not. The common pattern — read the file into memory, add the line, write it all back — reads the whole file just to add a line. True append-mode I/O (open in append, write only the new bytes) is the cheap path, and it's stdlib in every language.
Do "safe file write" libraries fix this?
No. They make whole-file replacement atomic by writing a full copy and renaming it — which for an append is exactly the read-modify-write you're trying to avoid.
A write's verify step failed — should I retry the write?
No. Append isn't idempotent: the first write may have already landed, so retrying can double the line. Re-read the tail to confirm what's actually on disk before you redo anything.