Skip to content

Releases

v0.5.1

Choose a tag to compare

@dooly6276 dooly6276 released this 14 Nov 08:00

Fixed

  • basics rm-root blocks cmd /c "rmdir /s /q \"D:\path\"" run from PowerShell or cmd. Neither cmd.exe nor PowerShell treats \" as an escaped quote, so rd gets a path that starts at \, the root of the current drive; the same line from Antigravity wiped drive D (a r/google_antigravity report). rd /s and del /s targets that start with \" (or with \D: once PowerShell has ended its string at \") are blocked, and so is del /s of \. The message suggests Remove-Item -LiteralPath '<path>' -Recurse or cmd /c rmdir /s /q "<path>" without backslash-escaped quotes. From bash (Git Bash) the escapes are removed before cmd reads the line, so cmd //c "rmdir /s /q \"D:\work\out\"" gets the whole path and passes; a single quoted cmd /c argument from bash or PowerShell is now read as that shell's value, so such a path is checked like any other rd /s target.

0.5.0: xargs-split and link-following deletes, home app data, PowerShell $home, Pi and four more agents

Choose a tag to compare

@dooly6276 dooly6276 released this 14 Nov 06:54

0.5.0 adds guards for four more ways agents deleted real data this autumn, closes the holes a reviewer found in 0.4.0's root check, and adds Pi, Qwen Code, Kimi Code, Grok Build and Antigravity.

New blocks

  • rm-xargs-split: xargs without -0/-d running rm -r, or xargs dirname/basename feeding an rm -r later in the pipeline. From a r/ClaudeCode report where xargs -n1 dirname split Application Support at the space, returned ~/Library, and rm -rf deleted it. Use find ... -print0 | xargs -0 rm -rf -- or find ... -delete.
  • rm-root now also covers whole app-data folders one level into home (~/Library/Application Support, ~/Library/Containers, ~/AppData/Roaming, ~/AppData/Local, ~/.local/share), another user's home, and C:\Users.
  • PowerShell: Remove-Item -Recurse (any spelling, with or without -Force) of $home, $env:USERPROFILE, (Split-Path $home) or a drive root, also inside powershell -Command and pwsh -c (anomalyco/opencode#62825, where $home is PowerShell's automatic variable for the user profile).
  • rm-through-link: git worktree remove --force on a folder holding a junction or symlink to an existing folder outside it, and on Windows a PowerShell Remove-Item -Recurse of such a folder. From a r/ClaudeAI report where removing two old worktrees on Windows deleted about 230 GB of models and a .venv they linked to. The message gives cmd /c rmdir "<link>" or unlink <link> to remove the link first.

Fixed

  • rm-root fills in variables set on the same line, so D=/; rm -rf "$D/" is blocked, and a variable set from cygpath, wslpath, realpath, readlink -f or dirname of a root counts as that root, so "${D:?}/" no longer passes for it. "${D:?}/sub" with a literal subfolder still passes. Reported by foma-agent in anthropics/claude-code#95426.
  • The rm-empty-var hint for rm -rf "$BUILD_DIR"/* kept the glob inside the quotes. It now says rm -rf "${BUILD_DIR:?}"/*.

More agents

  • Pi: pi install npm:claude-bulkhead (the npm package is now a Pi package), or bulkhead setup pi.
  • bulkhead setup qwen|kimi|grok|antigravity for Qwen Code, Kimi Code, Grok Build and Antigravity.

Check any command without installing: npx -y claude-bulkhead explain -- '<command>'. Upgrade in Claude Code with /plugin marketplace update bulkhead, or npm i -g claude-bulkhead@0.5.0. Full notes in CHANGELOG.md.

0.4.0: deletes through an empty variable, .git deletes, BSD pkill

Choose a tag to compare

@dooly6276 dooly6276 released this 14 Nov 00:51

Added

  • Bulkhead recognizes Aider CLI sessions in status and session ownership checks.
  • basics rm-empty-var: rm -rf $D/, rm -rf "$D"/*, rm -rf $(cygpath -u "$X")/ and rsync --delete src/ $D/ are blocked when the variable is not set to something non-empty earlier in the same shell, because an empty or unset variable (or a command that prints nothing) turns the path into / (anthropics/claude-code#109735). Deleting the whole output of a path command, such as rm -rf "$(cygpath -u 'C:\')", which prints /c/, is blocked too (anthropics/claude-code#95426 lost 600 GB). "${D:?}/", "$TMPDIR/foo" and D=$(mktemp -d) && rm -rf "$D"/ pass. Also Remove-Item -Recurse -Force $env:X\, rd /s /q %X%\, and the same commands inside bash -c and wsl -- bash -lc. With wsl -- bash -lc '...' an assignment inside the string does not count, because wsl hands the line to a Linux shell that expands the variable first. Applies with a single session. Turn it off with basics.rmEmptyVar.
  • basics rm-unquoted-var: rm -rf $D with D unquoted is blocked when the value, set earlier on the line or in the environment, has a space or a wildcard, since bash splits it into several paths and deletes each (anthropics/claude-code#107271). Turn it off with basics.rmUnquotedVar.
  • basics rm-git-dir: rm -rf .git, rm -rf path/.git and find . -name .git -exec rm -rf {} + are blocked when that .git is an existing folder, since the repository's history goes with it (anthropics/claude-code#107274). A .git the same line creates, such as after git clone, passes. Turn it off with basics.rmGitDir.
  • kill-guard bsd-pkill: on macOS and the BSDs, pkill with a long option (--signal, --full) or with more than one pattern is blocked, also with a single session. BSD pkill has no long options and reads everything after the first pattern as another pattern, so pkill -f "gcloud.py compute" -u me --signal 0, meant as an existence check, also matched 0 and sent SIGTERM to about 66 processes, every other Claude Code session among them (anthropics/claude-code#109627). The message suggests pgrep -f '<pattern>' for an existence check. Turn it off with killGuard.bsdPkill.

Changed

  • bulkhead scan --share lists what people fear first, in plain words: kills by name that would have hit other sessions' processes, recursive deletes, git add -A of another session's edits, branch switches in a shared tree, port clashes. The rest folds into one line and the foreground waits come last. No rule names appear in the share text any more (before, a rule without a description showed as basics self-allow).

Fixed

  • kill-guard reads pkill arguments the way the platform's pkill does. On Linux, options written after the pattern (pkill -f x --signal 0, pkill -f x -P $$) are options, as procps reads them, so a signal-0 check or a -P scope there passes. On macOS, every extra operand is a pattern, and each gets the same checks as the first.

0.3.7

Choose a tag to compare

@dooly6276 dooly6276 released this 12 Nov 10:28

Changed

  • The bulkhead skill now fits every agent that loads it, not only Claude Code. It says that orphan-reaper's cleanup at session end is Claude Code only and that in Copilot CLI and the other agents you stop your own servers before you finish, and it explains how to run bulkhead and bulkhead-slot with node from the plugin folder when a plugin-only install (Copilot CLI) does not put them on PATH.

Fixed

  • Codex and Copilot CLI sessions are found when CODEX_HOME or COPILOT_HOME moves their config folder. Before, a machine with only a moved folder skipped the process scan for that agent, so its servers and folders were not protected from other sessions.

0.3.6

Choose a tag to compare

@dooly6276 dooly6276 released this 12 Nov 08:07

Changed

  • Releases are published to npm by GitHub Actions with npm trusted publishing (.github/workflows/publish.yml), so each version on npm carries a provenance statement linking it to this repository and the commit it was built from. The same workflow attaches the Gemini CLI extension archive to the release. The guards are unchanged from 0.3.5.

0.3.5

Choose a tag to compare

@dooly6276 dooly6276 released this 12 Nov 07:29

Added

  • kill-guard broad-pattern: pkill -f <pattern> is blocked when the pattern matches a desktop app (a process inside an .app bundle) or 8 or more processes outside the session's own tree, also when only one session runs. pkill -f cat, meant for one stuck cat, matches every app under /Applications; on macOS, BSD pkill reads -n, -u and -P written after the pattern as more patterns, so they narrow nothing (anthropics/claude-code#100684, #107867). Processes the session started do not count. Turn it off with killGuard.broadPattern.

Fixed

  • The Gemini extension archive test no longer fails on Windows runners where the checkout and the temp folder are on different drives.

0.3.4: Gemini CLI extension and Codex plugin

Choose a tag to compare

@dooly6276 dooly6276 released this 12 Nov 05:59

Added

  • Gemini CLI extension: gemini extensions install https://github.com/dooly6276/claude-bulkhead installs the guards as an extension (gemini-extension.json, a BeforeTool hook on run_shell_command). The extension is the release asset bulkhead-gemini-extension.tar.gz, built by scripts/build-gemini-extension.js.
  • Codex plugin: codex plugin marketplace add dooly6276/claude-bulkhead, then codex plugin add bulkhead@bulkhead installs the guards as a Codex plugin (.codex-plugin/plugin.json, a PreToolUse hook on Bash). The marketplace entry installs the npm package, which now ships .codex-plugin/ and codex/.

Fixed

  • Windows: bulkhead worktree prune and list now match a session or the current folder to its worktree when one of the two paths uses an 8.3 short name (C:\Users\RUNNER~1\...) and git prints the long one. Before, prune could remove a worktree a live session was working in, or the one it was run from. The Windows CI jobs pass again: the other failures were tests that assumed /bin/sh, paths without a drive letter, or the Linux time limit for the 1 MB fuzz case.

v0.3.3: guard errors are logged, CI fuzz fix

Choose a tag to compare

@dooly6276 dooly6276 released this 11 Nov 22:58

Changed

  • A guard that throws is still skipped so the other guards run, but the error is now written to the event log with rule guard-error and to guards.log, so bulkhead log and bulkhead top show it instead of it looking like a clean pass.

Fixed

  • port-guard reads a very long pipeline (hundreds of thousands of segments) in a fraction of the time: dev-server detection looks a program up by name instead of testing every known tool against every segment. This also keeps the 1 MB fuzz case inside its time limit on slower CI runners.

v0.3.2: plugins for Copilot CLI, Cursor and opencode

Choose a tag to compare

@dooly6276 dooly6276 released this 11 Nov 21:56

New

  • Plugin bundles for Copilot CLI, Cursor and opencode. The repository is now also an Agent Plugins 1.0.0 plugin (plugin.json at the root, hooks in com.github.copilot/hooks/hooks.json) that Copilot CLI installs with copilot plugin marketplace add dooly6276/claude-bulkhead and copilot plugin install bulkhead@bulkhead; a Cursor plugin (.cursor-plugin/plugin.json with its own .cursor-plugin/hooks.json); and an opencode plugin from npm ("plugin": ["claude-bulkhead"], entry opencode/plugin.mjs). Each calls bulkhead hook --agent <name> from the plugin's own copy, so the guards are the same as with bulkhead setup <agent> and nothing is written to the agent's config. The Claude Code plugin and hooks/hooks.json are unchanged.

v0.3.1

Choose a tag to compare

@dooly6276 dooly6276 released this 11 Nov 20:58

Changed

  • A project file can only make bulkhead stricter. A repository's .claude/bulkhead.json comes with whatever you clone, so it can no longer take names off kill-guard's list, ignore ports, lengthen the wait limit, lower the RAM floor, turn a guard or rule off, turn on auto-queue or add programs for orphan-reaper to stop. Those settings are read from the global file only; in a project file they are ignored with a warning in bulkhead config, bulkhead doctor and the startup notice. A project can still add shared names, protected branches and secret patterns (added to the global lists, no longer replacing them), tighten limits and turn guards on. A project preset applies only where it is stricter. Block messages now point to the global file.
  • The skill no longer runs bulkhead remote run on its own. It shows the user the remote, the commit and every uncommitted change it would send, any --files it would add, and the command, and runs it only after the user says yes to that run, as /bulkhead:remote already did. memory-guard's block message says the same.

Fixed

  • bulkhead worktree prune counts a branch as merged when every commit on it was cherry-picked or rebased onto the base, not only when it was merged or squash-merged.