v1.1.0 — Linux support
v1.1.0 — Linux support
First cross-platform release. Linux Claude Code users can now get the same subprocess hygiene story Windows users have had since v1.0.0, with a kernel-enforced strong path on modern systems and an honest fallback on older or container-only systems.
What's new
tools/linux/find-claude.sh— 9-probe ordered resolution mirroring the Windows version (PATH → npm prefix →/opt/homebrew→/usr/local→ nvm → fnm → asdf → volta → yarn global). Handles every supported Claude Code install path on Linux + macOS.tools/linux/claude-jobbed.sh— wrapper with two reaper paths picked at runtime:- STRONG:
systemd-run --user --scope(kernel ≥ 5.14, default on Ubuntu 22.04 / Fedora 36 / Debian 12 +). Closest POSIX equivalent of Win32JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. Survives SIGKILL of the wrapper itself via an out-of-process watchdog that triggerscgroup.killon every descendant. - FALLBACK:
setpgid+ bash trap onEXIT/INT/TERM/HUP. Works on no-systemd containers, WSL1, minimal Alpine. Honest caveat: does NOT survive SIGKILL of the wrapper (bash traps don't fire on-9).
- STRONG:
install.sh— top-level OS-detect router.--yes,--force,--uninstallflags. Idempotent shell-function injection in~/.bashrc/~/.zshrc/~/.config/fish/config.fish. Refuses to duplicate without--force.- bats test suite — 19 tests pinning runtime + behavior on
ubuntu-latest. Includes the load-bearingcgroup.killstrong-path test that SIGKILLs the wrapper and asserts the grandchild is reaped within 5s. - CI matrix —
.github/workflows/test.ymlnow runs PowerShell tests onwindows-latestand bats onubuntu-latest(withloginctl enable-lingersosystemctl --useris active for the cgroup test).
Guarantee matrix
| Platform | Strong path | SIGKILL-of-wrapper survival | Fallback |
|---|---|---|---|
| Windows 10+ | Win32 Job Object + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
✅ Kernel-enforced | n/a |
Linux ≥ 5.14 + systemd --user |
systemd-run --scope + cgroup.kill (watchdog-supervised) |
✅ Kernel-enforced via cgroup.kill | setpgid + trap |
| Linux < 5.14 / no systemd / WSL1 | n/a | ❌ (trap doesn't fire on SIGKILL) | setpgid + trap |
| macOS | n/a | ❌ (deferred to v1.2.0) | n/a |
Quick start
Linux
curl -fsSL https://raw.githubusercontent.com/ron2k1/claude-code-structured-concurrency/main/install.sh | bash -s -- --yesThen in a new shell:
claude --version # routes through claude-jobbed.sh transparentlyWindows
Unchanged — see v1.0.3 release notes.
Why the watchdog matters
systemd-run --user --scope is a CONTROLLER, not a parent. Per systemd.scope(5): "When the last process leaves the scope, systemd cleans the scope up." Scope lifetime tracks DESCENDANT lifetime, not controller lifetime. So a SIGKILL of the wrapper just kills systemd-run; the scope stays alive with claude + grandchildren intact. Bash traps don't fire on SIGKILL either, so we cannot tear the scope down from in-process.
The watchdog is a backgrounded subshell that polls our parent identity via stat -c %Y /proc/$$ (the procfs entry mtime equals process start time, which is robust to PID reuse). When it observes the parent vanish, it runs systemctl --user stop $unit, which triggers cgroup.kill on every descendant — delivering the SIGKILL-survival guarantee the README documents.
What's next
- v1.2.0: macOS support (setpgid + trap; honest documentation that Force-Quit case is not covered).
- v1.3.0+: Optional macOS Swift
kqueuehelper for Force-Quit coverage; Homebrew formula; apt PPA.
Stats
- 36 PowerShell tests + 19 bats tests pass on CI
- 3-9 ms reap latency (Windows orphan cleanup)
- ~5 s upper bound for cgroup.kill scope teardown after SIGKILL of wrapper