Whilst experimenting with something else, I discovered that "zargs -P" would often abandon its backgrounded jobs when receiving terminal-driven signals. This led me down several rat-holes trying to figure out what was going on. In fact I'm still not sure what all the reasons were or how many of them were related to "setopt nomonitor" (which is removed in the attached patch). I discovered for example that even when INT and QUIT were explicitly trapped, a shell function passed as the command for zargs to run would execute with those signals either reset to their defaults or simply ignored, and I haven't been able to work out the circumstances when each of those cases occurs. E.g., with f() { sleep $1; print $1 } zargs -n 1 -P 3 -- 2 3 4 5 6 -- f Interrupting zargs with ^C would leave all the background "f" running, waiting for "sleep". On the other hand, with zargs -n 1 -P 3 -- 2 3 4 5 6 -- /bin/sleep the ^C terminated the sleeps as expected but attempting to stop zargs with ^Z would cause zargs to return, leaving orphan stopped sleep processes behind. That part was due to "nomonitor". Here then is a patch which: -- as discussed in the "Removing subshell from zargs" thread, removes the preliminary "wait" for all the process -- as noted above, removes "nomonitor" (because it was only needed for that "wait") -- explicitly adds traps to exit for tty-generated signals plus TERM, except that it ... -- captures the global signal trap context and restores it in the background jobs -- wraps the whole thing in an "always" block to clean up local helper functions -- updates the comments to note another buglet and drop support for zsh 4.x. As further speculated in the other thread, this doesn't yet remove the subshell around the whole mess. I'd love to hear explanations of why the signal handling behaves as it does. Every time I thought I had the logic mapped onto subshell entry conditions or whatever, it'd behave a different way the next time I tried, until I ended up with the rather brute-force approach in the patch.