- spill-policy reserves the spill notice's byte cost inside maxInlineBytes, so
the replacement (preview + notice) never exceeds the documented model-facing
cap. When the notice alone fills the budget the preview is empty; when even a
notice-only replacement is not smaller than the original, the inline result is
kept (spilling would only add bytes).
- retention TextRetainer trims an oversized single suffix chunk to the last
suffixCap bytes on push, so tail/headTail retention stays bounded by suffixCap
instead of retaining and re-copying the whole chunk in finish() — this is the
spill preview path, which pushes the whole result as one chunk.
Oversized plain-text tool results now spill to a session-scoped file and
return a bounded preview plus the spill path, so a verbose result stays
readable via `read` without consuming the next model request in full.
- dsh-spill: minimal SpillFiles seam (saveText → session-scoped SpillPath)
- dsh-spill-local: private 0700 session dirs, traversal-safe names, exclusive
owner-only writes
- dsh-spill-policy: tools/post-execute transformer; no-op unless maxInlineBytes
is set; skips read; best-effort on save failure (never turns a success into
an isError)
web_fetch is the showcase — no tool-specific spill code. The coding-agent
example loads the stack so its keyless Loader smoke guards the namespace-plugin
export shape. Snapshot gap for a transcript-visible web_fetch spill is recorded
in the RFC's Consequences (ACP replay is keyless and cannot hit the web).