Feature Request: Dynamic Sourcing of Allowed Bash Commands from Project Files

Resolved 💬 3 comments Opened Aug 1, 2025 by coygeek Closed Jan 4, 2026

Title: Feature Request: Dynamic Sourcing of Allowed Bash Commands from Project Files

Labels: feature-request, enhancement, permissions, security, automation

Is your feature request related to a problem? Please describe.

Currently, to grant Claude Code permission to use project-specific scripts (e.g., from package.json or a Makefile), developers must manually add each command to the permissions.allow array in .claude/settings.json.

For example, for a package.json with scripts like "lint", "test", and "build", the configuration would be:

{
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test)",
      "Bash(npm run build)"
    ]
  }
}

This manual process, as detailed in the IAM and Settings documentation, has several significant drawbacks:

  1. High Maintenance Overhead: It adds a tedious, manual step every time a project script is added, removed, or renamed.
  2. Configuration Drift: It is very easy for developers to forget to update settings.json, leading to a state where Claude's permissions are out of sync with the project's actual tooling. This causes valid commands to be unexpectedly denied.
  3. Onboarding Friction: New contributors must manually inspect the project's scripts and update settings to get Claude working effectively, which slows down adoption and creates a barrier to entry.

This forces a choice between overly permissive wildcards (e.g., Bash(npm run *)) and a brittle, error-prone manual process, ultimately limiting Claude's agentic capabilities within a project.

Describe the solution you'd like

I propose introducing a new syntax for the permissions.allow array that enables dynamic sourcing of commands directly from common project files. This would establish the project's task file (e.g., package.json, Makefile) as the single source of truth for its runnable commands.

A source: prefix within the Bash() tool specifier could be used to declare the file to parse. On startup or session initialization, Claude Code would read these rules, parse the specified files, and dynamically populate its internal allowlist of Bash commands.

Example settings.json Configuration:
{
  "permissions": {
    "allow": [
      // Statically defined rules would continue to work as they do today
      "Bash(git status)",
      "Read(docs/**)",

      // Dynamically sourced rules
      "Bash(source:package.json#scripts)",
      "Bash(source:Makefile)",
      "Bash(source:Justfile)"
    ],
    "deny": [
      "Bash(curl:*)",
      "WebFetch"
    ]
  }
}
How it would work:
  • Bash(source:package.json#scripts): Claude would parse package.json, find the scripts object, and automatically grant permission for npm run <script-name> (and equivalents like yarn or pnpm) for every script defined.
  • Bash(source:Makefile): Claude would parse the Makefile and grant permission for make <target> for every available target.
  • Bash(source:Justfile): Claude would parse the Justfile and grant permission for just <recipe> for every available recipe.
  • Extensibility: This could be extended to other common task runners or a generic JSON/YAML path for maximum flexibility (e.g., Bash(source:pyproject.toml#tool.poetry.scripts)).

Describe alternatives you've considered

  1. Manual Updates (Current Method): As described above, this is tedious, error-prone, and doesn't scale.
  2. Broad Wildcards: Using Bash(npm run *) is a possible workaround, but it is less secure as it doesn't distinguish between a safe lint script and a potentially destructive deploy script. It also fails to support non-prefixed commands from tools like make or just.
  3. Custom Pre-commit Hooks: A developer could write a script to generate settings.json from package.json and run it in a pre-commit hook. This is a fragile, complex workaround that adds unnecessary tooling instead of being a native, robust solution.

Describe the benefits

Implementing this feature would provide significant advantages:

  • Automation: Eliminates a tedious and error-prone manual task.
  • Single Source of Truth: Ensures the project's own command definitions are the canonical source for permissions, preventing configuration drift.
  • Reduced Friction: Developers can add or modify scripts and have Claude use them immediately without any extra configuration steps.
  • Improved Maintainability: Keeps Claude's capabilities perfectly aligned with the evolving project, making the tool more reliable.
  • Deeper Integration: Makes Claude Code feel more intelligently and seamlessly integrated into the development workflow.

Additional Context

This feature aligns perfectly with the goal of making Claude Code a seamless and powerful tool, as described in the Best Practices for Agentic Coding documentation. By reducing configuration boilerplate and automating permission discovery, it makes Claude more effective out-of-the-box.

Relevant Documentation:

Thank you for considering this feature. I believe it would be a powerful quality-of-life improvement for all developers using Claude Code.

Expanded Usage Cases and Scenarios

The utility of this feature extends across numerous common development patterns:

1. Modern Frontend Development (package.json)

  • Scenario: A developer is working on a Next.js/React project. The package.json contains dozens of scripts for development servers, building, type-checking, linting, formatting, multiple testing suites (unit, integration, e2e), and Storybook.
  • Without this feature: The developer must manually add and maintain Bash(npm run dev), Bash(npm run test:e2e), Bash(npm run storybook), etc. When a new script for test:visual is added, they must remember to update .claude/settings.json or Claude won't be able to run it.
  • With this feature: A single line, Bash(source:package.json#scripts), ensures Claude is always aware of the entire toolchain. The developer can simply ask, "Run the end-to-end tests for the checkout flow," and Claude can correctly execute npm run test:e2e -- --spec "tests/e2e/checkout.cy.ts".

2. Polyglot Backends & DevOps (Makefile, Justfile, Taskfile.yml)

  • Scenario: A backend team manages a Go service, a Python data pipeline, and Terraform infrastructure. They use a Makefile at the project root for common DevOps tasks like make build, make test, make run-local-db, make deploy-staging.
  • Without this feature: The only automated option is a broad Bash(make *) rule, which is a security concern as it would also permit a hypothetical make deploy-production or make NUKE-DATABASE target.
  • With this feature: Bash(source:Makefile) intelligently parses the available targets. The team can now safely ask Claude to perform setup or testing sequences like, "Get the local environment ready by running the database," and Claude can execute make run-local-db without needing blanket permissions.

3. The Python Ecosystem (pyproject.toml)

  • Scenario: A Python project uses Poetry or Hatch for dependency management and task running. Project-specific commands are defined under [tool.poetry.scripts] or [tool.hatch.scripts] in pyproject.toml.
  • Without this feature: This is another configuration file that must be manually synchronized with .claude/settings.json.
  • With this feature: The syntax could be extended to support this, like Bash(source:pyproject.toml#tool.poetry.scripts). Claude could then be instructed, "Run the data processing script," and it would correctly execute poetry run process-data as defined in the project configuration.

4. Complex Monorepo Environments

  • Scenario: A developer is working within a large monorepo. The root contains a Makefile for global orchestration (e.g., make bootstrap, make test-all). Their current working directory is packages/web-app, which has its own package.json with scripts like dev and build.
  • Without this feature: Managing permissions is a nightmare, requiring complex, directory-specific configurations.
  • With this feature: This becomes trivial. The root .claude/settings.json can contain Bash(source:Makefile). A nested .claude/settings.json inside packages/web-app could add Bash(source:package.json#scripts). Because Claude merges settings up the directory tree, it would seamlessly have permission to run both global make targets and local npm scripts, fully understanding the project's context.

5. CI/CD and Headless Automation

  • Scenario: A GitHub Actions workflow uses claude-code-action to automatically fix linting errors found in a pull request.
  • Without this feature: The CI workflow file must either hardcode the lint command or be granted overly broad permissions, making the pipeline configuration brittle.
  • With this feature: The CI job simply checks out the code and runs Claude. Claude reads the source: rule from the project's checked-in .claude/settings.json and knows it's allowed to run npm run lint:fix. The CI configuration becomes simpler, more secure, and independent of project-specific script names.

6. Seamless Team Collaboration and Onboarding

  • Scenario: A new developer joins a team, clones a repository, and wants to start using Claude Code immediately.
  • Without this feature: They face an immediate hurdle: Claude can't run any project tasks. They must pause, read through the package.json or Makefile, and manually configure their .claude/settings.json or .claude/settings.local.json.
  • With this feature: They clone the repo, run claude, and it just works. All the project's standard commands are immediately available because the permissions are co-located with the code and sourced dynamically. This drastically reduces onboarding friction and showcases Claude as a true, out-of-the-box team assistant.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗