Tasks is done I see the output file but model is waiting forever as background task is not ending by itself.
Fix this please.
Adding diagnostic evidence, since the original report was light on detail. I reproduced this and traced it to the OS level. The shell process has already exited — it is left as an unreaped zombie while the CLI continues to report it as running.
Environment
- Copilot CLI: 1.0.75 (no fix in 1.0.76–1.0.79-5 release notes)
- OS: RHEL 8 (Linux, x86_64)
- Node: v24.11.1
- Shell: bash, spawned by the CLI as
bash --norc --noprofile -c ...
Reproduction
Run any trivial command through the shell tool:
date +%s.%N; echo MARKER_START; ls -d ~/.copilot >/dev/null; echo MARKER_END; date +%s.%N
Output returns immediately and completely:
1786008693.683126807
MARKER_START
MARKER_END
1786008693.689291574
The timestamps show the command ran in 6 milliseconds. The tool then reports:
command ... is still running after 30 seconds
30+ seconds later, list_bash still shows:
shellId: 9, pid: 60889, mode: sync, status: running, elapsed: 152s, commands: 1, unread output: yes
Root cause: the process is a zombie
Inspecting the PIDs the CLI itself reported as running:
for p in 61902 60889 61404; do
if [ -d /proc/$p ]; then
echo "PID $p state=$(awk '{print $3}' /proc/$p/stat) cmd=$(tr '\0' ' ' </proc/$p/cmdline)"
fi
done
PID 61902 ALIVE state=Z cmd=
PID 60889 ALIVE state=Z cmd=
PID 61404 ALIVE state=Z cmd=
All three are in state Z (zombie) with an empty cmdline. The processes have terminated and their exit statuses are sitting in the process table waiting to be collected — the parent has not called waitpid(). Every command tested ends this way, so it is not command-specific.
Ruling out the obvious explanations
I tested the two usual causes of a "hanging" shell. Both are ruled out:
1. Not an orphaned child holding the stdout pipe. The child is fully dead (state Z), and explicitly closing both output streams changes nothing:
exec 3>&1; { date; echo REDIR_TEST; } >/tmp/rt.log 2>&1; exec 1>&- 2>&-; cat /tmp/rt.log >&3; exec 3>&-
→ output returns, session still reports running.
2. Not shell rc/profile config. The CLI spawns with --norc --noprofile, and ~/.bashrc / ~/.profile contain no background jobs. An explicit trailing exit 0 also does not help:
date +%s.%N; echo TEST_EXPLICIT_EXIT; exit 0
→ output returns, session still reports running.
Additionally, the CLI process holds both ends of its own pipes:
lr-x------ 10 -> pipe:[915443282] # read end
l-wx------ 11 -> pipe:[915443282] # write end (same inode)
With the write end held open by the reader itself, read() on that pipe can never see EOF regardless of what the child does.
Why this matters
Because no command-side change can fix it, this cannot be worked around by users:
- A
preToolUse hook that rewrites the command (setsid + wait + kill the process group) has no effect — there is no orphan to reap and the pipe is held by the parent.
- The only reliable mitigation is calling
stop_bash after every single command, which depends on the model remembering to do so on every turn. In practice it does not, so sessions accumulate phantom "running" shells.
The downstream effect is the behavior in the issue title: the model sees status: running, concludes work is still in progress, and either waits indefinitely or re-runs the command. Long-lived processes started in earlier sessions then survive indefinitely — I found a node server orphaned 56 days ago from a prior Copilot session still running on this host.
Expected behavior
The CLI should waitpid() the shell process once it exits and mark the session complete, rather than leaving it as a zombie reported as running. Output delivery already works correctly; only the completion/reaping step is broken.
Tasks is done I see the output file but model is waiting forever as background task is not ending by itself.
Fix this please.
Adding diagnostic evidence, since the original report was light on detail. I reproduced this and traced it to the OS level. The shell process has already exited — it is left as an unreaped zombie while the CLI continues to report it as running.
Environment
bash --norc --noprofile -c ...Reproduction
Run any trivial command through the shell tool:
Output returns immediately and completely:
The timestamps show the command ran in 6 milliseconds. The tool then reports:
30+ seconds later,
list_bashstill shows:Root cause: the process is a zombie
Inspecting the PIDs the CLI itself reported as
running:All three are in state
Z(zombie) with an emptycmdline. The processes have terminated and their exit statuses are sitting in the process table waiting to be collected — the parent has not calledwaitpid(). Every command tested ends this way, so it is not command-specific.Ruling out the obvious explanations
I tested the two usual causes of a "hanging" shell. Both are ruled out:
1. Not an orphaned child holding the stdout pipe. The child is fully dead (state
Z), and explicitly closing both output streams changes nothing:→ output returns, session still reports running.
2. Not shell rc/profile config. The CLI spawns with
--norc --noprofile, and~/.bashrc/~/.profilecontain no background jobs. An explicit trailingexit 0also does not help:→ output returns, session still reports running.
Additionally, the CLI process holds both ends of its own pipes:
With the write end held open by the reader itself,
read()on that pipe can never see EOF regardless of what the child does.Why this matters
Because no command-side change can fix it, this cannot be worked around by users:
preToolUsehook that rewrites the command (setsid+wait+ kill the process group) has no effect — there is no orphan to reap and the pipe is held by the parent.stop_bashafter every single command, which depends on the model remembering to do so on every turn. In practice it does not, so sessions accumulate phantom "running" shells.The downstream effect is the behavior in the issue title: the model sees
status: running, concludes work is still in progress, and either waits indefinitely or re-runs the command. Long-lived processes started in earlier sessions then survive indefinitely — I found anodeserver orphaned 56 days ago from a prior Copilot session still running on this host.Expected behavior
The CLI should
waitpid()the shell process once it exits and mark the session complete, rather than leaving it as a zombie reported asrunning. Output delivery already works correctly; only the completion/reaping step is broken.