M4.6
Spill large artefacts
686 words · about 4 min
The concept
ConceptSpilling breaks the assumption that a tool result must travel through the context window. A result of 5MB does not become useful by being pruned to 5KB; it becomes useful by being stored, with a small reference left in the conversation that lets the model retrieve what it needs.
Spilling is different in kind from the other three rungs: it is preventive, not reactive. It happens at result-production time, before the content ever enters history. By the time you are measuring pressure, the spill opportunity is already gone.
The mechanism
MechanismThe seam is deliberately narrow. From docs/subsystems/spill.md:
SaveTextSpill { owner, source, suggestedName, content }
SpillRef { locator, bytes, retrievalHint }SpillLocator is a branded type — an opaque handle, not a path the model is invited to construct. The retrievalHint tells the model how to get the content back, which is what turns a reference into something actionable rather than a dead end.
Storage in the local backend is security-conscious in ways worth noting, because a spill path is a file the harness writes on behalf of model-influenced content. The root is created 0700; each session gets a subdirectory named by sha256(sessionId) rather than the id itself; files are written with open(path, 'wx', 0o600). The 'wx' flag fails if the path exists, so — as the doc says — "a planted symlink cannot redirect it". This is Module 5 material arriving early: a feature that writes files at content-derived paths is an attack surface.
The seam owns storage only. It explicitly does not own retention policy, tool-result replacement, or retrieval. That separation is what lets the policy live elsewhere and vary independently. packages/spill/spill-policy decides when to spill, gated on maxInlineBytes, and its exclusion list is instructive:
- Nested executions are skipped.
- Accepted value replacements are skipped.
readresults are skipped — spilling a file read would create aread → spill → read againloop.- Non-accept decisions are skipped.
- Only plain-text results are eligible.
That read exclusion is the kind of detail you only find by building the thing.
The notice left in the conversation is the whole user-facing contract:
(Omitted N bytes. Full formatted result stored at: <locator>.
Use read with offset/limit, or grep this path to search within it.)It states what was omitted, where it went, and — critically — how to get it back using tools the model already has. A handle with no retrieval instruction is a dead reference.
And the policy is best-effort: "A spill failure never turns a successful call into an isError." If the disk is full, the tool call still succeeded; you get a large result instead of a spilled one. Context management must never convert a working operation into a failed one.
Tradeoffs
Spilling adds a round trip. Content that would have been immediately available now requires a read or grep to retrieve, costing a step and latency. When the model needed the whole thing, you have made the interaction strictly worse. The maxInlineBytes threshold is a bet that results above a certain size are rarely needed in full, and like the compaction threshold it is a judgement, not a derived value — which is why omitting the key disables the policy entirely, so an operator unsure about the tradeoff can opt out.
Retention is the unsolved half. The seam owns no retention policy, which means spilled files accumulate on disk. Something must eventually clean them, and "something else's problem" is a real gap, honestly scoped rather than hidden.
How others differ
Claude Code writes large outputs to temporary files and references them by path — the same pattern with a less formal seam. The interesting alternative is spilling to a searchable store rather than a flat file, so the model can query rather than re-read. That is strictly more capable and drags in an indexing dependency and a whole retrieval-quality problem. dsh explicitly declines: "no retrieval/search API". Whether that is the right call depends on how often spilled content is needed again, and there is no published data on this.
Check yourself
2 questions on M4.6