All three input paths cap collection at 20,000 lines: wrapMaxLines (cmd/wrap.go:20), mcpMaxLines (internal/mcp/dispatch.go:16), and maxInputLines for stdin (cmd/io.go:26). When the cap is hit, the child is killed (internal/exec/stream.go:124-128) and the kill is mapped to success (stream.go:173-176), so the first 20k lines are compacted as if they were the whole input.
Two problems compound here:
1. The truncation is invisible. Neither the CLI summary line nor the MCP tool text mentions that input was cut. The user (or agent) sees a confident "N→M tok (X% reduction)" summary computed over the kept slice only. An agent debugging an incident has no signal that it analyzed a fraction of the logs.
2. The wrong fraction is kept. Because collection stops at the cap, codag keeps the oldest 20k lines and drops the newest. For the core use case — incident debugging — the recent lines are usually where the incident is. codag wrap -- cat /var/log/app.log on a large log file analyzes the oldest slice and can miss today's incident entirely, while reporting a clean compaction summary. Same applies to the MCP wrap/tail_* tools when an agent doesn't pre-bound the window.
Suggested fixes (independent):
- Minimal: when
hitLimit fires, append a marker to the compact output and stderr summary, e.g. [codag] input truncated at 20,000 lines (oldest kept) — bound the window with --since/--tail for full coverage. The MCP tools should include it in the returned text so agents can react.
- Better: ring-buffer the most recent
maxLines instead of killing at the cap (trade-off: the child then runs to completion or the 90s timeout, so latency changes; could apply keep-last only to file readers like cat/zcat where "newest = end of file" is unambiguous, or expose --keep first|last).
Happy to PR the minimal marker version if you're open to it.
All three input paths cap collection at 20,000 lines:
wrapMaxLines(cmd/wrap.go:20),mcpMaxLines(internal/mcp/dispatch.go:16), andmaxInputLinesfor stdin (cmd/io.go:26). When the cap is hit, the child is killed (internal/exec/stream.go:124-128) and the kill is mapped to success (stream.go:173-176), so the first 20k lines are compacted as if they were the whole input.Two problems compound here:
1. The truncation is invisible. Neither the CLI summary line nor the MCP tool text mentions that input was cut. The user (or agent) sees a confident "N→M tok (X% reduction)" summary computed over the kept slice only. An agent debugging an incident has no signal that it analyzed a fraction of the logs.
2. The wrong fraction is kept. Because collection stops at the cap, codag keeps the oldest 20k lines and drops the newest. For the core use case — incident debugging — the recent lines are usually where the incident is.
codag wrap -- cat /var/log/app.logon a large log file analyzes the oldest slice and can miss today's incident entirely, while reporting a clean compaction summary. Same applies to the MCPwrap/tail_*tools when an agent doesn't pre-bound the window.Suggested fixes (independent):
hitLimitfires, append a marker to the compact output and stderr summary, e.g.[codag] input truncated at 20,000 lines (oldest kept) — bound the window with --since/--tail for full coverage. The MCP tools should include it in the returned text so agents can react.maxLinesinstead of killing at the cap (trade-off: the child then runs to completion or the 90s timeout, so latency changes; could apply keep-last only to file readers like cat/zcat where "newest = end of file" is unambiguous, or expose--keep first|last).Happy to PR the minimal marker version if you're open to it.