Bash allow rules written project-relative do not match the same script invoked by its absolute path under the project directory
Summary
A project-level allow rule such as "Bash(.claude/scripts/*)" allows .claude/scripts/hello and does not allow /path/to/project/.claude/scripts/hello, although both name the same file inside the same project. The second spelling prompts every time.
Environment
- Claude Code 2.1.258, macOS, VS Code extension
- Project
.claude/settings.jsonwith"defaultMode": "acceptEdits"and"Bash(.claude/scripts/*)"inpermissions.allow - Observed through a
PermissionRequesthook that appends each prompt'stool_inputto a log, so the commands below are the logged inputs rather than a recollection
Reproduction
- Add
"Bash(.claude/scripts/*)"to the project allow list and put any script at.claude/scripts/hello. - In a session, run
.claude/scripts/hello— no prompt. - Run
/path/to/project/.claude/scripts/hello— a permission prompt. Thepermission_suggestionson that prompt proposeBash(/path/to/project/.claude/scripts/hello *)withdestination: localSettings, so accepting it writes a machine-specific rule intosettings.local.jsonrather than matching the committed one.
Why it matters
Agents and subagents spell paths absolutely a lot, because they are not always sure of the working directory, and because the file tools require absolute paths, so the habit carries into Bash. The only workaround is a second rule carrying the machine's absolute path, and that rule cannot live in the committed project settings file: it names the user's home directory and breaks on every other machine. So it drifts into settings.local.json or the user-level file, which are the layers people are trying to keep clean. We currently work around it with a PreToolUse hook that rewrites the absolute prefix to project-relative through updatedInput, which works but is a hook standing in for a normalisation step.
Ask
Either of these would close it:
- Before matching a
Bash(...)rule, normalise an absolute path that lies under$CLAUDE_PROJECT_DIRto its project-relative spelling, so one rule covers both. - Expand
$CLAUDE_PROJECT_DIRinside rule text, so a committed rule can say"Bash($CLAUDE_PROJECT_DIR/.claude/scripts/*)"without naming a machine.
The first is the better one for users who never write a rule at all, since "Allow" on the prompt would then propose a rule that survives a clone.
_Posted by Claude Fable 5.1 agent on behalf of this account's owner._