Three Ways to Hand 4,000 Lines of Logs to an Agent — Paste, .txt Attachment, or @ Reference
v2.3.0 added plain-text attachments, which means there are now three ways to hand a long log to an agent — and a new question about which one to pick. Here is how I trim, measure, and decide, with the scripts I actually run.
The overnight job was red by morning. As an indie developer shipping app updates on my own schedule, the failure notice usually reaches me within a few minutes of waking up.
The CI log ran to roughly 4,000 lines. With no idea where the failure started, I selected all of it and pasted it into the chat box. As the input field stretched down the screen, I already had the feeling that this was the wrong move.
What came back was not the obvious stack trace near the end of the log. It was a general observation about a warning line near the beginning. The agent had not been lazy. I handed over a 4,000-line block without telling it where the center of gravity was, and that was my design failure, not its reading failure.
v2.3.0 (2026-07-13) added attachment and in-conversation rendering for plain-text files. That brings the number of ways to hand long text to an agent up to three. More options also means more hesitation.
Below, I compare all three against the same log, and lay out how I decide between them — including the trimming and measuring scripts.
Three Handoff Paths, Each Breaking Somewhere Different
Here is the landscape as of today.
Method
What it actually is
Comfortable length
Where it breaks
Paste into chat
Becomes part of the conversation body
Up to ~120 lines
Long pastes crowd the conversation and degrade later turns
.txt attachment (v2.3.0+)
Travels as an attachment, rendered in the conversation
120 to a few thousand lines
You get a "read the whole thing" summary. It needs a stated focus
@ file reference
Points at a file inside the workspace
Effectively generous
Cannot point outside the workspace
The real difference is not the length ceiling. It is how each one fails.
Pasting contaminates the conversation itself. Those 4,000 lines stay in context for every turn that follows. That is the trap I walked into first.
An @ reference only reaches files inside the workspace. Anything under /var/log, or a log copied over from another machine, is out of reach.
So there are three options, but in any given moment only one or two actually qualify. Deciding that by feel every time was what produced my bad morning.
Trim First — Pulling a Window Out of 4,000 Lines
Before the three-way choice, there is something that has to happen first. Trim.
Of those 4,000 lines, the ones that explain the failure usually number around 100. The rest is progress output that looks identical to a healthy run, and handing it over does not help anyone reason.
Here is the extraction script I use. It finds the error lines and carves out the surrounding context.
#!/usr/bin/env bash# extract-log-window.sh — carve out just the region around an error# usage: ./extract-log-window.sh run.log 40 10 > slice.txtset -euo pipefailLOG="${1:?usage: extract-log-window.sh <logfile> [before] [after]}"BEFORE="${2:-40}"AFTER="${3:-10}"# Markers used for detection. Extend these per project.PATTERN='ERROR|FATAL|Traceback|Exception|panic:|✗|FAIL|exit code [1-9]'if ! grep -nEq "$PATTERN" "$LOG"; then echo "# No lines matched the pattern. Emitting the last ${AFTER} lines instead." >&2 tail -n "$AFTER" "$LOG" exit 0fiTOTAL=$(wc -l < "$LOG")echo "# source: $LOG (${TOTAL} lines)"echo "# window: -${BEFORE}/+${AFTER} around /${PATTERN}/"echo "# ---"# Overlapping windows get joined with --- separatorsgrep -nE -B "$BEFORE" -A "$AFTER" "$PATTERN" "$LOG"
4,127 lines became 143 — a 96.5% reduction. At 143 lines, paste and attachment are both viable again.
Why 40 before and only 10 after? The cause of an error is almost always written before the error line. What follows is cleanup and an exit code, which needs far fewer lines. That asymmetry is where I landed after a few rounds of tuning.
One caveat: if you are running shell scripts without set -euo pipefail, the real failure is the first error and everything after it is secondary damage. In that case, look only at the first match.
# Carve a window around the first error onlyFIRST=$(grep -nEm1 "$PATTERN" "$LOG" | cut -d: -f1)sed -n "$((FIRST > 40 ? FIRST - 40 : 1)),$((FIRST + 10))p" "$LOG"
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦A same-log, same-question comparison of paste vs. .txt attachment vs. @ reference, and the decision flow that came out of it
✦A complete extraction script (bash and Node) that pulls the relevant window out of a 4,000-line log
✦Measure before you hand off: line count, byte size, and token estimate, so the choice stops being a guess
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
143 lines, but over 4,500 estimated tokens. Your instinct about line count and the token reality diverge, because log lines are long. The threshold here checks both line count and tokens precisely because I have never had a day where I did not trip over that gap.
repeatRate exists to stop a specific accident: handing over a log that is mostly the same line repeated. Normalizing digits to # and measuring duplication, anything over half means trim again before handing off. Retry-loop logs get caught by this reliably.
Comparing All Three Against the Same Log
I handed the same 143-line slice.txt to all three paths with an identical question: "Name one direct cause of this failure and quote the line you based it on."
Dimension
Paste
.txt attachment
@ reference
Identified the direct cause
Yes
Yes
Yes
Quote accuracy
Whole line returned
Whole line returned
Sometimes with line numbers
Effect on later turns
Stays in the conversation
Body stays clean
Body stays clean
Revisiting it later
Scroll back through chat
Listed as an attachment
The file is the source of truth
Outside the workspace
Works
Works
Does not work
Once trimmed to 143 lines, all three got the answer right. The difference showed up afterward.
With a paste, asking a follow-up like "now propose a fix" means those 143 lines are still sitting there. By turn five or six, that weight starts to tell.
With an attachment, the conversation body holds only the question. When you want to go back to "that part of the log," the attachment list gets you there. The practical payoff of v2.3.0 rendering attachments inline is exactly this: you can return to it.
The @ reference fits a workflow where logs get written into the workspace anyway. My automated runs leave output under .logs/, so I can point straight at it. When the file updates, what the agent reads updates too — a property attachments do not have.
One more thing: this comparison is about the trimmed version. Run the same test on the raw 4,127 lines and every method degrades. Choosing a handoff method is not a substitute for trimming.
Redact Before You Hand Off
Logs contain things you did not intend to share.
CI logs often retain lines where environment variables were expanded, leaving API keys and tokens in plain view. Attachments are easier than pasting, which makes it easier to hand something over without ever looking at it. That convenience is the risk.
I fold a minimal redaction step into the extraction stage.
# Insert just before the output line in extract-log-window.shredact() { sed -E \ -e 's/(sk-[A-Za-z0-9_-]{8})[A-Za-z0-9_-]+/\1***REDACTED***/g' \ -e 's/(ghp_[A-Za-z0-9]{6})[A-Za-z0-9]+/\1***REDACTED***/g' \ -e 's/(AIza[A-Za-z0-9_-]{6})[A-Za-z0-9_-]+/\1***REDACTED***/g' \ -e 's/(Bearer )[A-Za-z0-9._-]+/\1***REDACTED***/g' \ -e 's/([A-Z_]*(TOKEN|SECRET|PASSWORD|API_KEY)[A-Z_]*=)[^[:space:]]+/\1***REDACTED***/g'}grep -nE -B "$BEFORE" -A "$AFTER" "$PATTERN" "$LOG" | redact
Keeping the first few characters is deliberate. It lets a human tell which key is being discussed later. Mask everything and you lose the ability to notice you are looking at the wrong credential.
This is not comprehensive. Project-specific secrets will not match these patterns. Stripping secrets from stored logs is a different layer with a different job, which I covered in removing secrets from stored agent logs. What happens here is the last net before handoff.
Where I Landed
I decide among the three in this order.
Trim first. Run extract-log-window.sh. Never skip this
Measure. Run measure-handoff.mjs and read recommend
If it says shrink-first, narrow the window or drop to first-match-only and try again
If it says paste (under 120 lines and 1,500 tokens), paste. Do not create a file for a one-round question
If it says attach: use @ reference when the log lives in the workspace, and a .txt attachment when it does not
When attaching or referencing, state the focus in the question. "Start from the stack trace at the end" changes the quality of the answer entirely
Step 6 is the one that slips. Picking a method feels like finishing the job, but every method still needs you to say where to start reading. Assuming the agent read all of it because you attached all of it was, in my case, wishful thinking.
Take your longest log and run extract-log-window.sh on it. Just watching the line count collapse tells you what you have been handing over all this time.
Mine went from 4,127 lines to 143. The other 3,984 never needed to travel.
Three options instead of one is an opportunity to rethink the handoff. Pick among them by feel and the only thing that grows is the hesitation. Make it measurable, and the extra options finally start paying for themselves.
If you measure just one log after reading this, it will have been worth writing. Thank you for reading to the end.
Share
Thank You for Reading
Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.