[BUG] Bash(ls:*) allow rule still prompts for ls commands in settings.local.json

Status Open
Maintainer reply None cached
Activity 12 comments · opened Mar 12, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

I have Bash(ls:*) in my project's .claude/settings.local.json allow list, but Claude Code still prompts me to approve ls commands. I'm also in "Edit Automatically" permission mode, which I initially expected would help, but I understand that mode only affects file edits, not Bash commands.

What Should Happen?

The Bash(ls:*) allow rule should match any command starting with ls and auto-approve it without prompting.

Error Messages/Logs

Steps to Reproduce

Add "Bash(ls:*)" to .claude/settings.local.json → permissions.allow
Start a conversation where Claude runs a command like:

ls -la /c/Users/jonat/Documents\ \(Local\)/pinman/pinman2/envdata/source_fixtures/richtree/
Claude Code prompts for approval instead of auto-approving

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

v2.1.71

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

VS Code integrated terminal

Additional Information

Looking at the docs, it appears the tool: syntax (with colon) may be deprecated in favor of tool (with space), e.g. Bash(ls *). However:

It's unclear whether the colon syntax still works at all or silently fails
There's no migration warning or documentation calling out the deprecation clearly
If the colon syntax is broken, many users with older configs will hit this silently
Additionally, the path in my command contains escaped parentheses (\(, \)) and escaped spaces — special characters in command arguments may also be interfering with the prefix matcher.

Environment:

Platform: Windows 11 (Git Bash)
Claude Code: latest (as of 2026-03-12)
My full allow list for reference:

"Bash(ls:*)",
"Bash(cat:*)",
"Bash(find:*)",
"Bash(grep:*)"
Suggestion:

If :* is deprecated, emit a warning or auto-migrate to the space syntax
Document the exact matching semantics for Bash allow rules more prominently
Clarify that "Edit Automatically" mode does not affect Bash command approval (this is a common point of confusion)

View original on GitHub ↗

12 Comments

github-actions[bot] · 5 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/29529
  2. https://github.com/anthropics/claude-code/issues/30071
  3. https://github.com/anthropics/claude-code/issues/30113

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

jake-albert · 5 months ago

Facing similar here for Next.js projects, closed my own issue https://github.com/anthropics/claude-code/issues/33827 so this can get consolidated.

dwightware4 · 5 months ago

Same issue. It's a real pain, and it's not just ls but basically all Bash commands from what I can tell. grep, tail, etc. None of my allow configuration seems to be respected anymore.

rdavidson-nf · 5 months ago

Experiencing on MacOS Tahoe 26.3.1 with Claude Code 2.1.75.

Almost positive it's when a bash command has unescaped () characters in it's arguments.

Quick script to reproduce with ls:

#!/bin/bash

# Setup
echo "Setting up two directories, one with parentheses and one without..."
mkdir claude-permissions-test
mkdir "claude-permissions-test/1-path-with-(parens)"
touch "claude-permissions-test/1-path-with-(parens)/sample.txt"
mkdir claude-permissions-test/2-path-without-parens

echo ""
echo "Directories created in ./claude-permissions-test/:"
ls -l claude-permissions-test

# Run both in parallel, capture output
echo ""
echo "Running two inline Claude prompts in parallel to ls each subdir..."
cd claude-permissions-test
claude -p "Run \`ls '1-path-with-(parens)'\`" --allowedTools "Bash(ls *)" --output-format text > parens-result.txt 2>&1 &
claude -p "Run \`ls '2-path-without-parens'\`" --allowedTools "Bash(ls *)" --output-format text > no-parens-result.txt 2>&1 &
wait

# Result
echo ""
echo "Path with parens result:"
cat parens-result.txt

echo ""
echo "Path without parens result:"
cat no-parens-result.txt

Result:

Setting up two directories, one with parentheses and one without...

Directories created in ./claude-permissions-test/:
total 16
drwxr-xr-x@ 3 rdavidson  staff   96 Mar 16 10:37 1-path-with-(parens)
drwxr-xr-x@ 2 rdavidson  staff   64 Mar 16 10:37 2-path-without-parens
-rw-r--r--@ 1 rdavidson  staff   48 Mar 16 10:37 no-parens-result.txt
-rw-r--r--@ 1 rdavidson  staff  135 Mar 16 10:37 parens-result.txt

Running two inline Claude prompts in parallel to ls each subdir...

Path with parens result:
The command requires approval. Please approve the `ls '1-path-with-(parens)'` command to proceed.

Path without parens result:
The directory `2-path-without-parens` exists but is empty.
karlkeefer · 5 months ago

Same issue here for a next.js project with (route-groups) in file paths 👍

sapient-christopher · 5 months ago

Same issue here. My project lives on a Google Drive path with spaces, and I have "Bash" (bare, matches all) in allow with specific patterns like "Bash(git push *)" in both ask and denyneither takes precedence over the broad "Bash" allow.

Tested on macOS Tahoe, Claude Code in VS Code, Opus model:

  • "Bash" in allow + "Bash(git push *)" in ask → push runs without prompting
  • "Bash" in allow + "Bash(git push *)" in deny → push still runs without prompting
  • "Bash(git diff *)" in allow (no bare "Bash") → git diff --stat HEAD~1 still prompts

So the pattern matching is broken in both directions: specific rules can't override a broad allow, and specific allow rules don't match multi-arg commands.

sapient-christopher · 5 months ago

Update/workaround: We worked around this by removing bare "Bash" from allow entirely and using a PreToolUse hook for granular bash command permissions. The hook inspects the command string and returns allow, ask, or deny dynamically.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/bash-permissions.sh"
          }
        ]
      }
    ]
  }
}

The hook script splits compound commands (&&, ;, |), checks each subcommand against allow/ask/deny patterns using grep -qE with [[:space:]] (not \s — macOS grep -E doesn't support it), and returns the appropriate permissionDecision. This gives full control that the permissions system currently can't provide.

Note: if your project path contains spaces (e.g. Google Drive), $CLAUDE_PROJECT_DIR in the hook command path won't work — use a quoted absolute path instead.

nikicat · 5 months ago

@sapient-christopher good job! Could you provide your bash-permissions.sh script?

sapient-christopher · 5 months ago

@nikicat see attached.
bash-permissions.sh

nikicat · 5 months ago

@sapient-christopher thanks!

yurukusa · 5 months ago

/tmp/gh-comment-body.txt

segiddins · 5 months ago

Worth pointing out that this still happens _even when the parens are in a single-quoted string_