Recovering Command Output After Agent Tools Truncate It
Our CLI keeps command output available after a tool truncates its response. Cross-shell lookup and remote build streams each needed separate fixes. Here is the capture and recovery contract we use.
A coding agent runs a command, gets a long response, and sees a truncation marker where the useful detail should be. Running the command again costs time. For a command that changes state, another execution can also repeat the change. We built a second path: keep the output from the first execution on disk and let the agent ask for the relevant part.
That sounds like ordinary logging. In practice, the recovery path has several contracts of its own: capture the bytes before presentation changes them, give the recording a reference that survives another shell, and preserve partial output when a remote operation ends early. We had to fix each of those separately.
Keep the original before shortening the response
An earlier output-filtering layer rewrote command text in place. Our replacement module documents examples where a single letter was masked and a command name was collapsed. The agent then reasoned from the rewritten text, with the original unavailable through that layer.
The replacement CLI tees non-interactive Git and Kubernetes command output into a session-scoped recording while forwarding it to the terminal. A recording has command metadata, the received stdout and stderr, and an exit footer. Presentation can then strip terminal escape sequences, collapse progress updates or summarize repeated lines while a separate read command retrieves the retained output.
The distinction matters when an agent needs a detail the summary author did not anticipate. A summary optimized for compiler errors can omit the source revision or a warning needed for the next diagnosis. Keeping the recording lets the agent change its question after the execution has finished.
Show the data
| Step | Time |
|---|---|
| Raw capture | 20 Aug, 01:19 UTC |
| Cross-shell lookup | 3 Oct, 18:24 UTC |
| Remote streams | 7 Oct, 05:43 UTC |
A reference has to survive the next shell
Our October investigation found 7 explicit missing-output errors in a bounded transcript inspection. All referred to recordings bucketed by the parent process. A controlled reproduction opened two separate shell parents: the first recorded a command successfully, and the second could not recover its printed reference.
The recording existed. The lookup had changed scope. With the parent process as the fallback session identity, two shell invocations could look in different directories for the same short sequence number.
The fix uses a stable harness or conversation identity when available, with an explicit output-session override taking precedence. Recorders also print a qualified reference containing the session and recording name. That reference can be read from a later shell even when the later shell has a different default session.
Short references still resolve only inside the current session. An ambiguous prefix returns an error. The resolver rejects path traversal and never chooses another session’s newest matching file. Those restrictions keep a convenient lookup from returning evidence for the wrong execution.
Remote commands need their own capture point
A later review found that remote Cargo execution never created a raw recording. Local child-process capture did not cover the builder’s response stream. An instruction to recover the full log was therefore insufficient for that path.
The remote runner now creates a recording and publishes its handle before source preparation and network waiting. Received builder chunks go into that recording before protocol parsing. Result-stream replays use the same recording, so the retained evidence follows the remote operation.
Terminal outcomes remain explicit. A completed build carries its exit code. Timeouts and transport failures do not acquire a successful exit footer, and an interrupted future can leave a partial file without a terminal footer. The partial output is useful evidence; its presence alone says nothing about completion.
Give the agent a small recovery interface
rac out list
rac out explain REFERENCE
rac out read REFERENCE --tail 80
rac out grep "error"The explanation command reports the command line and exit status, plus up to four distinct lines matching error-related terms. If those terms are absent, it uses a short tail. This is a heuristic view: the agent can follow the reference to inspect more context. Search is literal substring matching across the current session’s recordings.
During preparation of this post, we ran a read-only Git revision query and read its qualified recording from a second shell using the installed CLI. The original revision and the successful exit footer were recovered. That checks one current lookup path; it does not establish a fleet-wide recovery rate or exercise remote build interruption.
State the limits of the recording
- Cross-stream ordering is best effort. Stdout and stderr are drained separately, so the combined file can interleave them differently from the terminal.
- Interactive commands have metadata-only entries. Inherited terminal input and output preserve interactive behavior; the store does not capture their terminal transcript.
- Retention is bounded. The implementation caps a session at 256 MiB and removes old sessions using a 7-day age check during garbage collection. A reference can expire.
- Capture is best effort. Some asynchronous paths continue if the store is unavailable, and write failures can leave incomplete evidence. A printed handle should be checked before relying on its contents.
- Raw logs can contain sensitive output. The store creates owner-only session directories and log files. The explanation path applies secret screening; direct reads expose the retained text. Agents still need to avoid commands that print credentials.
Our design inference: giving the agent a recoverable reference makes a short tool response more useful because the next question can target the same execution. The evidence here supports the capture and lookup mechanisms and the specific fixes. We have no before-and-after measurement of task completion or token savings from them.