Long-running bash commands with large outputs cause truncation and agent retry loops #8049

Open
opened 2026-02-16 18:09:00 -05:00 by yindo · 2 comments
Owner

Originally created by @nabilfreeman on GitHub (Jan 30, 2026).

Originally assigned to: @thdxr on GitHub.

Description

Long-running bash commands with verbose output are being truncated and/or timed out, causing agents to re-attempt commands instead of polling the saved tool output. This creates serious idempotency issues in workflows where commands should run to completion.

Current behavior:

  1. Bash commands have a hardcoded 2-minute default timeout (src/tool/bash.ts:21)
  2. Output is truncated at 2,000 lines or 50KB (src/tool/truncation.ts:10-11)
  3. When output is truncated, full output is saved to ~/.opencode/data/tool-output/, but agents frequently re-run the command instead of reading the saved output
  4. Commands are killed after timeout, even if they would have completed successfully

The problem:

  • Commands that produce large build logs, test outputs, or verbose diagnostics get truncated
  • Agents see truncated output and often retry the command instead of using Read with offset/limit on the saved output file
  • This creates duplicate work, wasted API calls, and potential side effects from non-idempotent commands
  • For CI/CD workflows, this behavior is unacceptable - commands should never exit until a proper exit code is received

Current configuration options:

  • OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS - env var for timeout (exists)
  • No configuration for MAX_LINES or MAX_BYTES truncation limits (hardcoded)

Proposed solution:
Add opencode.json configuration for these limits:

{
  "experimental": {
    "bash": {
      "timeout_ms": 600000,      // 10 minutes
      "max_lines": 10000,        // or null to disable
      "max_bytes": 512000        // or null to disable
    }
  }
}

This would allow users to configure behavior appropriate for their workflows without needing environment variables.

Plugins

None

OpenCode version

Current (main branch)

Steps to reproduce

  1. Run a command that produces more than 2,000 lines of output (e.g., npm install with verbose logging, large test suite)
  2. Observe output is truncated with message about saved file
  3. Watch agent retry the command instead of reading the saved output
  4. For timeout: run any command that takes longer than 2 minutes

Screenshot and/or share link

No response

Operating System

macOS

Terminal

No response

Originally created by @nabilfreeman on GitHub (Jan 30, 2026). Originally assigned to: @thdxr on GitHub. ### Description Long-running bash commands with verbose output are being truncated and/or timed out, causing agents to re-attempt commands instead of polling the saved tool output. This creates serious idempotency issues in workflows where commands should run to completion. **Current behavior:** 1. Bash commands have a hardcoded 2-minute default timeout (`src/tool/bash.ts:21`) 2. Output is truncated at 2,000 lines or 50KB (`src/tool/truncation.ts:10-11`) 3. When output is truncated, full output is saved to `~/.opencode/data/tool-output/`, but agents frequently re-run the command instead of reading the saved output 4. Commands are killed after timeout, even if they would have completed successfully **The problem:** - Commands that produce large build logs, test outputs, or verbose diagnostics get truncated - Agents see truncated output and often retry the command instead of using `Read` with offset/limit on the saved output file - This creates duplicate work, wasted API calls, and potential side effects from non-idempotent commands - For CI/CD workflows, this behavior is unacceptable - commands should never exit until a proper exit code is received **Current configuration options:** - `OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS` - env var for timeout (exists) - No configuration for `MAX_LINES` or `MAX_BYTES` truncation limits (hardcoded) **Proposed solution:** Add `opencode.json` configuration for these limits: ```jsonc { "experimental": { "bash": { "timeout_ms": 600000, // 10 minutes "max_lines": 10000, // or null to disable "max_bytes": 512000 // or null to disable } } } ``` This would allow users to configure behavior appropriate for their workflows without needing environment variables. ### Plugins None ### OpenCode version Current (main branch) ### Steps to reproduce 1. Run a command that produces more than 2,000 lines of output (e.g., `npm install` with verbose logging, large test suite) 2. Observe output is truncated with message about saved file 3. Watch agent retry the command instead of reading the saved output 4. For timeout: run any command that takes longer than 2 minutes ### Screenshot and/or share link _No response_ ### Operating System macOS ### Terminal _No response_
yindo added the perf label 2026-02-16 18:09:00 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Jan 30, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #1721: bash tool often times out - Similar timeout issues with long-running commands
  • #4197: Set timeout for long running commands - Related feature request for configurable timeouts
  • #3950: [FEATURE]: Configurable command timeout in config.json - Similar proposal for timeout configuration in config file
  • #8633: feat: add 'never' option for mcp_timeout to disable timeout - Related approach to disabling timeouts
  • #8012: Function call auto-truncation - Related to output truncation issues
  • #7450: [FEATURE]: Truncate output of long scripts/diffs by default - Related to output truncation discussion
  • #10634: Compaction overflow check doesn't account for large tool outputs - Related to handling large outputs in context

Feel free to ignore if your specific case addresses concerns not covered by these issues.

@github-actions[bot] commented on GitHub (Jan 30, 2026): This issue might be a duplicate of existing issues. Please check: - #1721: bash tool often times out - Similar timeout issues with long-running commands - #4197: Set timeout for long running commands - Related feature request for configurable timeouts - #3950: [FEATURE]: Configurable command timeout in config.json - Similar proposal for timeout configuration in config file - #8633: feat: add 'never' option for mcp_timeout to disable timeout - Related approach to disabling timeouts - #8012: Function call auto-truncation - Related to output truncation issues - #7450: [FEATURE]: Truncate output of long scripts/diffs by default - Related to output truncation discussion - #10634: Compaction overflow check doesn't account for large tool outputs - Related to handling large outputs in context Feel free to ignore if your specific case addresses concerns not covered by these issues.
Author
Owner

@nabilfreeman commented on GitHub (Jan 30, 2026):

Context from Related Issues

After reviewing the related issues, here's what I've gathered:

Timeout configuration - This has been addressed. OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS was added in December 2025 (#1721, #3950, #4197). The max timeout cap was removed, so agents can set arbitrarily long timeouts per-command. The env var sets the default.

Output truncation - This is the unaddressed gap. The hardcoded limits in truncation.ts (2000 lines, 50KB) have no configuration mechanism. Related issues:

  • #7450 discusses UI truncation for readability (different concern - that's about display, not agent context)
  • #10634 highlights that large tool outputs can cause context overflow and compaction issues

The maintainer perspective (from @rekram1-node in #3950):

"we will have something more appropriate in the config later, for now we will have: OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT (supported in next release also this is in milliseconds)"

This suggests the pattern for new settings: start with OPENCODE_EXPERIMENTAL_* env vars, then graduate to opencode.json config once the feature is stable.


Proposed First Phase (Safe, Low-Risk)

Following the established pattern, add two new env vars to flag.ts:

export const OPENCODE_EXPERIMENTAL_MAX_LINES = number("OPENCODE_EXPERIMENTAL_MAX_LINES")
export const OPENCODE_EXPERIMENTAL_MAX_BYTES = number("OPENCODE_EXPERIMENTAL_MAX_BYTES")

Then in truncation.ts:

export const MAX_LINES = Flag.OPENCODE_EXPERIMENTAL_MAX_LINES ?? 2000
export const MAX_BYTES = Flag.OPENCODE_EXPERIMENTAL_MAX_BYTES ?? (50 * 1024)

This is ~4 lines of code, follows the exact pattern used for OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS, and gives power users an escape hatch while the team decides on the proper config schema.


Why This Issue Should Be Primary

This issue consolidates the truncation + timeout + idempotency concerns that are scattered across multiple threads:

The unique contribution here is identifying the agent retry loop problem: when output is truncated, agents often re-run commands instead of reading the saved output file. This creates real workflow issues beyond just "I want more output" - it causes duplicate side effects and wasted compute.

Happy to submit a PR for the env var approach if maintainers confirm this is the right direction.

@nabilfreeman commented on GitHub (Jan 30, 2026): ## Context from Related Issues After reviewing the related issues, here's what I've gathered: **Timeout configuration** - This has been addressed. `OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS` was added in December 2025 (#1721, #3950, #4197). The max timeout cap was removed, so agents can set arbitrarily long timeouts per-command. The env var sets the default. **Output truncation** - This is the **unaddressed gap**. The hardcoded limits in `truncation.ts` (2000 lines, 50KB) have no configuration mechanism. Related issues: - #7450 discusses UI truncation for readability (different concern - that's about display, not agent context) - #10634 highlights that large tool outputs can cause context overflow and compaction issues **The maintainer perspective** (from @rekram1-node in #3950): > "we will have something more appropriate in the config later, for now we will have: OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT (supported in next release also this is in milliseconds)" This suggests the pattern for new settings: start with `OPENCODE_EXPERIMENTAL_*` env vars, then graduate to `opencode.json` config once the feature is stable. --- ## Proposed First Phase (Safe, Low-Risk) Following the established pattern, add two new env vars to `flag.ts`: ```typescript export const OPENCODE_EXPERIMENTAL_MAX_LINES = number("OPENCODE_EXPERIMENTAL_MAX_LINES") export const OPENCODE_EXPERIMENTAL_MAX_BYTES = number("OPENCODE_EXPERIMENTAL_MAX_BYTES") ``` Then in `truncation.ts`: ```typescript export const MAX_LINES = Flag.OPENCODE_EXPERIMENTAL_MAX_LINES ?? 2000 export const MAX_BYTES = Flag.OPENCODE_EXPERIMENTAL_MAX_BYTES ?? (50 * 1024) ``` This is ~4 lines of code, follows the exact pattern used for `OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS`, and gives power users an escape hatch while the team decides on the proper config schema. --- ## Why This Issue Should Be Primary This issue consolidates the **truncation + timeout + idempotency** concerns that are scattered across multiple threads: - #1721, #3950, #4197 focus only on timeout - #7450 focuses on UI display - #10634 focuses on compaction The unique contribution here is identifying the **agent retry loop problem**: when output is truncated, agents often re-run commands instead of reading the saved output file. This creates real workflow issues beyond just "I want more output" - it causes duplicate side effects and wasted compute. Happy to submit a PR for the env var approach if maintainers confirm this is the right direction.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8049