Skip to content

v1.1.0 — Linux support

Choose a tag to compare

@ron2k1 ron2k1 released this 11 May 05:59
2b28322

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 Win32 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE. Survives SIGKILL of the wrapper itself via an out-of-process watchdog that triggers cgroup.kill on every descendant.
    • FALLBACK: setpgid + bash trap on EXIT/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).
  • install.sh — top-level OS-detect router. --yes, --force, --uninstall flags. 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-bearing cgroup.kill strong-path test that SIGKILLs the wrapper and asserts the grandchild is reaped within 5s.
  • CI matrix.github/workflows/test.yml now runs PowerShell tests on windows-latest and bats on ubuntu-latest (with loginctl enable-linger so systemctl --user is 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 -- --yes

Then in a new shell:

claude --version  # routes through claude-jobbed.sh transparently

Windows

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 kqueue helper 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