From ad7b9a12cffebb6aa1c803b985c27cd9a55a1411 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Wed, 29 Jul 2026 15:20:38 +0100 Subject: [PATCH] chore(claude): remaining global settings deltas after #347 #347 landed the same hook merge this branch carried (compound-bash-allow.py, redirect-inline-eval.py, compound-bash.json, the README line, and the plain worktree-remove rule), and did the hook better: "}" handled explicitly ahead of _KW_BARE_RE with the reasoning about why "\b" cannot fire after a non-word character, _REDIR_TAIL_RE reused instead of a second near-identical regex, and the config lookup order documented in the docstring. Those are dropped here in favour of main. What is left is the part #347 did not cover: settings.template.json collapse the four "git rebase --abort/--continue/--quit/--skip" rules into "git rebase *"; add "git tag" reads, the "git -C" worktree-remove forms to match the plain one #347 added, and docs.rs, which pairs with the cargo block and rust-analyzer plugin the template already ships. bash-composition.md document the stdin-eval denial that redirect-inline-eval.py now enforces. The global CLAUDE.md predates that hook change and does not mention it, so the vendored rule otherwise ships a hook its own docs contradict. Skipped as personal: docs.polkadot.com, paritytech.github.io, effortLevel. Verified: deploy renders valid JSON with every new rule expanded and no leftover placeholders. Co-Authored-By: Claude Opus 5 (1M context) --- .../.claude/rules/bash-composition.md | 1 + .../cursor-workspace/.claude/settings.template.json | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/cursor-workspace/.claude/rules/bash-composition.md b/examples/cursor-workspace/.claude/rules/bash-composition.md index a0db6e98b..9a094b3dd 100644 --- a/examples/cursor-workspace/.claude/rules/bash-composition.md +++ b/examples/cursor-workspace/.claude/rules/bash-composition.md @@ -37,6 +37,7 @@ Unsure whether a command will trip? Write it to a file and dry-run the hook: `py **`cd` before `sbx`, never inside it.** The writable project root is resolved by running `git rev-parse --show-toplevel` in the OUTER shell, before the sandbox starts. So `cd && __WORKSPACE__/scripts/claude/bin/sbx ` gets a writable ``; `sbx bash -lc 'cd && '` gets a read-only one. This also fixes `npx` binary resolution, which depends on cwd. - **Inline eval** (`python3 -c`, `node -e`, `perl -e`, `ruby -e`, `php -r`, `bun -e`, `Rscript -e`, `deno eval`) — must be `sbx`-prefixed. A PreToolUse hook denies the bare form, so reach for `sbx` first. +- **An interpreter reading its program from stdin** is inline eval by another spelling, and is denied the same way: `python3 - <<'EOF'`, `python3 <<'EOF'`, `cat x.py | node`, `deno run -`. Heredocs are still fine as *data* (`git commit -F - <<'EOF'`) — it is the interpreter, not the heredoc, that triggers the deny. Prefix with `sbx`, or write the program to a file and run the file. - **`rm` / `mv` / `ln` / `dd` / `chmod` inside the project or `/tmp`** — prefix with `sbx` to auto-approve. Bare forms are the escape hatch for paths OUTSIDE the project, which the sandbox blocks; they prompt. - **Project-local tools** (`npx tsx`, `npx vitest`, and anything already in `node_modules/.bin`) — an `sbx` candidate, and the preferred way to run them: no allowlist rule needed. `npx` walks up the tree to find the binary, so a git worktree with no `node_modules` of its own still resolves from the parent repo. If the package is genuinely absent, `npx` falls through to the registry and dies with `EAI_AGAIN` — read that as "not installed locally", not as a sandbox fault. (`--no-install` and `--no` do NOT suppress the registry lookup on npm 9, and `--no` swallows a following `--version`.) To bypass `npx` entirely, call the binary by path: `node_modules/.bin/tsx`, or `../../node_modules/.bin/tsx` from a worktree. - **Not an `sbx` candidate** — anything needing network: `git fetch`/`push`, `gh`, dep installs, and `npx` that must *install* the package (not merely run an installed one). Also writes outside the project and `/tmp`. diff --git a/examples/cursor-workspace/.claude/settings.template.json b/examples/cursor-workspace/.claude/settings.template.json index 439286463..c4b4e43e8 100644 --- a/examples/cursor-workspace/.claude/settings.template.json +++ b/examples/cursor-workspace/.claude/settings.template.json @@ -65,10 +65,7 @@ "Bash(git describe *)", "Bash(git blame *)", "Bash(git reflog *)", - "Bash(git rebase --abort *)", - "Bash(git rebase --continue *)", - "Bash(git rebase --quit *)", - "Bash(git rebase --skip *)", + "Bash(git rebase *)", "Bash(git remote *)", "Bash(git reset HEAD *)", "Bash(git reset -q HEAD *)", @@ -82,6 +79,9 @@ "Bash(git status *)", "Bash(git submodule *)", "Bash(git symbolic-ref *)", + "Bash(git tag)", + "Bash(git tag --list *)", + "Bash(git tag -l *)", "Bash(git verify-commit *)", "Bash(git verify-tag *)", "Bash(git worktree add *)", @@ -130,6 +130,8 @@ "Bash(git -C /tmp/* rebase *)", "Bash(git -C * worktree remove /tmp/*)", "Bash(git -C * worktree remove --force /tmp/*)", + "Bash(git -C * worktree remove __HOME__/projects/*/.worktrees/*)", + "Bash(git -C * worktree remove --force __HOME__/projects/*/.worktrees/*)", "Bash(git push *)", "Bash(git pull *)", "Bash(npx gitnexus *)", @@ -156,6 +158,7 @@ "WebFetch(domain:github.com)", "WebFetch(domain:docs.claude.com)", "WebFetch(domain:docs.anthropic.com)", + "WebFetch(domain:docs.rs)", "WebSearch", "Write(__HOME__/projects/**)", "Write(/tmp/**)",