Skip to content

Bash auto-promotion can waste agent context and tokens on long validation commands #124

Closed

Description

@Zireael

Short description

Bash auto-promotion can waste agent context on long validation commands

What happened?

TL;DR

Bash commands are auto-promoted to background after 8 seconds. In some use cases that does not make the session more efficient.

Refer to attached agent example session, where I have a 10-15min build/validation script running in Docker.

example-coding-session.txt

In this case I want the AI to sit tight until it gets a list of failing tests to debug and fix them. Instead, the AI was mulling around doing random ceremony.

After promotion of the test/build script, the session accumulated roughly:

  • 16 additional tool calls
  • 17 assistant responses
  • 5 bash_status calls
  • about 120k transcript characters, roughly 30k tokens by a crude chars/4 estimate

The command then hit the hard 600-second timeout and returned partial results. The timeout caused the failure, but backgrounding made the session noisier and gave the agent many chances to burn context before the real result existed.

The core issue: backgrounding is useful for servers, watchers, and genuinely parallel work. It is not automatically useful for deterministic validation commands.

Concrete motivating case

My script runs a sequence of Docker-backed checks, including Cargo, Clippy, and TypeScript validation. Cargo compilation alone takes around 14 minutes in this environment, before the rest of the suite completes.

My AFT bash settings are:

"bash": {
  "rewrite": false,
  "compress": false,
  "background": false,
  "subagent_background": false,
  "long_running_reminder_enabled": false,
  "long_running_reminder_interval_ms": 600000,
  "foreground_wait_window_ms": 8000
}

Observed behavior:

  1. I don't want bash calls to be put in background.
  2. After 8 seconds, AFT auto-promoted it to a background task anyway.
  3. The agent then performed status checks, narration, recovery from status timeout, and manual reading of output files.
  4. The validation command eventually timed out at about 601 seconds with exit 124.

This made the user experience look like bash.background: false was ignored, even though technically only explicit backgrounding was disabled.

Problems

1. bash.background: false is ambiguous

A user reading this config reasonably expects:

Do not put bash commands in the background.

Current behavior appears to mean:

Do not allow explicit background starts, but still auto-promote long foreground commands after foreground_wait_window_ms.

That distinction may make sense internally, but the config name does not communicate it.

2. Auto-promotion is treated as generally helpful

For some commands, it is helpful:

  • dev servers
  • watchers
  • long-running indexers
  • benchmarks where the agent has useful parallel work

For deterministic validation commands, it can be harmful:

  • the useful result is the final exit code and final output
  • intermediate status checks usually do not help
  • each assistant/tool turn consumes context
  • agents tend to poll even when told not to
  • the command may still fail if the original timeout is too low

In this case, the efficient path was probably:

  1. run the validation command;
  2. wait with a long enough timeout;
  3. return the final result once.

Just let the bash script do it's thing. There isn't anything else more productive for AI to do in the mean time. And if there is, it should spawn a subagent to do the side thing.

3. The 8-second foreground window is too short for build/test workflows

Eight seconds is enough to identify an interactive command as “not immediately done,” but not enough to infer that backgrounding is useful.

For Rust, TypeScript, Docker, and monorepo validation scripts, 8 seconds may only cover startup overhead.

4. Timeout guidance is missing

The command timeout was 600 seconds. This Cargo compilation alone can take around 14 minutes in this environment.

AFT should help surface this mismatch. A build/test/check command with a 10-minute timeout may be doomed before it starts, especially in Docker or cold-cache conditions.

5. bash_status is too easy to misuse

The tool output says not to poll, but the session still produced repeated status checks.

For background validation tasks, AFT should bias agents toward a blocking wait-until-exit primitive, not repeated snapshots.

6. Runtime messages appear stale in places

Some background-disabled messages still refer to experimental.bash.background, while the current user-facing config uses top-level bash.background.

That makes an already confusing behavior look more broken.

Requested improvements

1. Split explicit backgrounding from auto-promotion

Add separate config semantics, for example:

"bash": {
  "explicit_background": false,
  "auto_promote_foreground": false,
  "subagent_background": false,
  "foreground_wait_window_ms": 8000
}

Alternative shape:

"bash": {
  "background": {
    "explicit": false,
    "auto_promote": false,
    "subagents": false
  }
}

Expected behavior:

  • explicit_background: false blocks bash({ background: true }).
  • auto_promote_foreground: false prevents foreground commands from being promoted to background.
  • subagent_background: false keeps current subagent safety behavior.

Backward compatibility option:

  • Treat existing bash.background: false as disabling both explicit backgrounding and auto-promotion.
  • Or keep the current behavior for one release, but emit a warning that bash.background only controls explicit backgrounding and that auto-promotion has a separate setting.

Preferred behavior: bash.background: false should disable all backgrounding because that matches normal user expectation.

2. Add a validation/wait mode for long deterministic commands

AFT should support a mode optimized for build/test/check scripts:

"bash": {
  "validation_timeout_ms": 1800000,
  "validation_auto_promote": false
}

or at tool-call level:

{
  "command": "...",
  "mode": "wait",
  "timeout": 1800000
}

Behavior:

  • do not auto-promote;
  • wait for completion;
  • return final output once;
  • avoid extra assistant/tool turns;
  • preserve output truncation metadata and output file paths.

This is a better fit for Cargo, Clippy, TypeScript, Docker, and project check scripts.

3. Detect likely validation commands and warn about low timeout

If a command contains common validation patterns, AFT should warn when the timeout is likely too low.

Examples:

  • cargo check
  • cargo test
  • cargo clippy
  • npm test
  • pnpm test
  • bun test
  • tsc
  • vitest
  • docker build
  • project scripts named check, test, ci, validate

Example warning:

This looks like a build/test validation command. Timeout is 600s. Rust/Docker validation can exceed this, especially on cold caches. Consider 1800s or configure bash.validation_timeout_ms.

This should not block execution. It should make the failure mode obvious.

4. Prefer wait/watch over polling

When AFT does auto-promote a foreground command, the returned message should push the agent toward a blocking wait primitive.

Instead of primarily saying:

use bash_status(...) to inspect output

prefer:

Use bash_watch({ taskId, exit: true, timeoutMs: ... }) to wait for completion. Avoid polling with bash_status; it is snapshot-only.

Also consider:

  • warning after repeated bash_status calls on the same running task;
  • adding “recommended next action: bash_watch” to bash_status while the process is still running;
  • exposing a simple bash_wait tool if bash_watch is too general for agents.

5. Make reminder messaging match config

If long_running_reminder_enabled: false, auto-promotion should not tell the user that a completion reminder will be delivered.

The message should distinguish:

Completion reminder is enabled.

from:

No completion reminder is configured. Use bash_watch to wait for completion.

6. Update stale config references

Replace references to deprecated config keys such as:

experimental.bash.background

with the current top-level config shape.

Example:

background bash is disabled by bash.background: false

If separate explicit/auto-promote fields are introduced, the message should name the exact field that blocked or allowed the behavior.

7. Show resolved bash behavior in diagnostics

Add resolved bash behavior to aft doctor, aft configure, or equivalent diagnostics:

Bash:
  hoisted: true
  rewrite: false
  compress: false
  explicit_background: false
  auto_promote_foreground: true
  subagent_background: false
  foreground_wait_window_ms: 8000
  long_running_reminder_enabled: false

This would make the current behavior obvious before the user has to infer it from a live session.

Acceptance criteria

  • Users can configure AFT so bash commands are never backgrounded, including no foreground auto-promotion.

  • Explicit background execution and foreground auto-promotion are separately configurable.

  • Existing bash.background: false no longer creates the impression that the setting is ignored.

  • Long build/test/check commands can run as a single wait-until-exit operation with a realistic timeout.

  • AFT warns when likely validation commands have obviously low timeouts.

  • Auto-promoted tasks guide agents toward bash_watch or wait-until-exit behavior, not repeated bash_status polling.

  • Repeated polling is discouraged or warned about.

  • Runtime messages use current config names, not deprecated experimental.bash.* names.

  • Resolved bash behavior is visible in diagnostics.

  • Tests cover:

    • explicit background disabled;
    • foreground auto-promotion disabled;
    • bash.background: false behavior;
    • validation command timeout warning;
    • reminder disabled messaging;
    • stale experimental.bash.* message removal;
    • guidance toward wait/watch instead of repeated status polling.

To sum up

AFT’s background bash support is useful, but it should not be treated as a catch-all solution for long commands.

For validation commands, the most efficient agent behavior is often boring: run the command, wait long enough, return the final result once. In the observed session, auto-promotion did not save time. It mostly converted one long validation wait into many extra tool calls and assistant turns before the same timeout failure.

Diagnostics

Plugin version

v0.39.2

AFT binary version

v0.39.2

Platform

windows x64

Log output (optional)

Activity

  1. alfonso-aft commented on Jun 17, 2026

    @alfonso-aft
    Contributor

    Fixed in v0.39.3, in two parts:

    • bash.background: false now fully disables the background surface — the bash_status/bash_kill/bash_watch tools are no longer registered, the background/pty parameters are dropped from bash, and long commands run to completion in the foreground (bounded by timeout, default 30 min). Previously it only blocked explicit background: true while long commands still auto-promoted.
    • With background left on (the default), the waiting guidance was reworked: sync bash_watch is now interruptible (a message disengages the wait), so agents are steered to block on it when the result is the next thing they need, end the turn when there's parallel work, and not loop bash_status. The sync bash_watch cap was also raised from 5 to 30 minutes so it can wait out a real build.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions