d3258b224ac942ad94e267e7492abc1207c99b68
bash-guard mapped 20 mutating git verbs to their jj equivalents but not `worktree`, so `git worktree add` passed the hook untouched. Claude Code's built-in EnterWorktree/ExitWorktree tools were a second hole: they create a git worktree directly, never going through Bash, so the guard never saw them. A git worktree in a jj repo is not a jj workspace. jj does not manage it, it never appears in `jj workspace list`, and none of jj's workspace bookkeeping applies to it -- the isolated checkout ends up outside the VCS that owns the repo. Add the `worktree` entry to the git->jj map and a PreToolUse matcher on EnterWorktree|ExitWorktree that exits 2 with the jj workspace commands on stderr. The tool matcher replaces a `permissions.deny` entry in user settings.json: it travels with the plugin and names the replacement command instead of failing silently. Read-only `git worktree list` is blocked along with the rest of the verb. It cannot see jj workspaces, so its empty output reads as "no isolated checkouts exist" when several do -- worse than a denial. Verified by running the guard against `git worktree add ../feature` over socket stdin and confirming both the denial and that the reason names `jj workspace add`. The new checks fail against the 1.1.1 map. Tests: 12 passing (bash-guard).
mroberts — Claude Code plugin marketplace
Personal marketplace hosting multiple Claude Code plugins.
Install
claude plugin marketplace add ssh://[email protected]/mroberts/claude-plugin.git
claude plugin install guards@mroberts
Layout
.claude-plugin/marketplace.json # index — every plugin must be listed here
plugins/
guards/
.claude-plugin/plugin.json
hooks/hooks.json
hooks/bash-guard.mjs
Adding a plugin
mkdir -p plugins/<name>/.claude-plugin- Write
plugins/<name>/.claude-plugin/plugin.jsonwithname,version,description. - Add components:
hooks/hooks.json,commands/,agents/,skills/as needed. - Append an entry to
plugins[]in.claude-plugin/marketplace.json:
{ "name": "<name>", "source": "./plugins/<name>", "description": "...", "category": "productivity" }
A plugin absent from plugins[] is not installable, regardless of its directory.
- Push, then
claude plugin marketplace update mroberts.
Plugins
| Plugin | Purpose |
|---|---|
guards |
Enforces the hard constraints in ~/.claude/CLAUDE.md — jj-only VCS, no Claude attribution, build+test gate before push/tag, secret scrubbing on writes. |
Note on guards
hooks/bash-guard.mjs is referenced via ${CLAUDE_PLUGIN_ROOT} and travels with the
plugin. shush is referenced by absolute path (/home/mroberts/.local/bin/shush)
because it is a separately installed binary, not a repo file — that path is
machine-specific and will need changing on another host.
Languages
Python
91.6%
JavaScript
5.6%
Shell
2.8%