Files
claude-plugin/plugins/guards/hooks/hooks.json
T
mroberts d3258b224a Route isolated checkouts to jj workspaces
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).
2026-07-28 13:07:00 -05:00

40 lines
1.1 KiB
JSON

{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/bash-guard.mjs\"",
"timeout": 600,
"statusMessage": "Checking jj/attribution policy; gating push on build + tests..."
}
]
},
{
"matcher": "EnterWorktree|ExitWorktree",
"hooks": [
{
"type": "command",
"command": "echo 'BLOCKED: git worktrees are not used here — this repo is managed with jj (CLAUDE.md: version control is jj only). Use a jj workspace instead: jj workspace add ../<name> Remove it with: jj workspace forget <name> then delete the directory.' >&2; exit 2",
"timeout": 5
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "/home/mroberts/.local/bin/shush --changes-only --hook-output",
"timeout": 5
}
]
}
]
}
}