Bash tool spawns a login shell whose state it then discards — ~830ms per call

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 23, 2026

The Bash tool appears to invoke commands through a login shell (bash -lc). On this machine that costs roughly 830ms on every single Bash call, and the state it pays for is discarded before the next one.

Measured on Windows 11, Intel Ultra 9 285K, each variant spawned individually, process time (not wall clock), median of repeated runs:

cat pyproject.toml              24.1ms    the work itself
bash -c 'cat pyproject.toml'    48.7ms    + a non-login shell
bash -lc 'cat pyproject.toml'  881.7ms    + sourcing the profile   (max observed 1674ms)

That is roughly 18x the work being wrapped, and it recurs per call.

What makes this look like waste rather than a cost worth paying: the Bash tool's own documented contract states both that the shell is initialized from the user's profile and that shell state does not persist between calls. Both are true simultaneously — the profile is sourced on every invocation and then thrown away. The things a login shell exists to establish (exported environment, PATH assembly, shell functions) are precisely what the contract says will not survive to the next call.

Supporting datapoint from a separate instrumented codebase: Bash and PowerShell tool calls accounted for 87.8% of total instrumented wall clock, against approximately 0% for the native file-read tool. On agent workloads this is where the time goes, not a rounding error.

The ask: is the login shell load-bearing for something not visible from outside? If it is not, using -c rather than -lc would return most of that ~830ms to every user on every platform. If it is, knowing what depends on it would help — the "state does not persist" contract makes the dependency hard to locate from the outside.

To reproduce: time bash -c against bash -lc for any trivial command on a machine with a non-trivial shell profile. The gap scales with whatever the profile does, which is why it may not show up on a clean test image.

View original on GitHub ↗