Feature Request: Dynamic Sourcing of Allowed Bash Commands from Project Files
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:
- High Maintenance Overhead: It adds a tedious, manual step every time a project script is added, removed, or renamed.
- 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. - 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 parsepackage.json, find thescriptsobject, and automatically grant permission fornpm run <script-name>(and equivalents likeyarnorpnpm) for every script defined.Bash(source:Makefile): Claude would parse theMakefileand grant permission formake <target>for every available target.Bash(source:Justfile): Claude would parse theJustfileand grant permission forjust <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
- Manual Updates (Current Method): As described above, this is tedious, error-prone, and doesn't scale.
- Broad Wildcards: Using
Bash(npm run *)is a possible workaround, but it is less secure as it doesn't distinguish between a safelintscript and a potentially destructivedeployscript. It also fails to support non-prefixed commands from tools likemakeorjust. - Custom Pre-commit Hooks: A developer could write a script to generate
settings.jsonfrompackage.jsonand 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.jsoncontains 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 fortest:visualis added, they must remember to update.claude/settings.jsonor 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 executenpm 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
Makefileat the project root for common DevOps tasks likemake 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 hypotheticalmake deploy-productionormake NUKE-DATABASEtarget. - 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 executemake run-local-dbwithout 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]inpyproject.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 executepoetry run process-dataas defined in the project configuration.
4. Complex Monorepo Environments
- Scenario: A developer is working within a large monorepo. The root contains a
Makefilefor global orchestration (e.g.,make bootstrap,make test-all). Their current working directory ispackages/web-app, which has its ownpackage.jsonwith scripts likedevandbuild. - Without this feature: Managing permissions is a nightmare, requiring complex, directory-specific configurations.
- With this feature: This becomes trivial. The root
.claude/settings.jsoncan containBash(source:Makefile). A nested.claude/settings.jsoninsidepackages/web-appcould addBash(source:package.json#scripts). Because Claude merges settings up the directory tree, it would seamlessly have permission to run both globalmaketargets and localnpmscripts, fully understanding the project's context.
5. CI/CD and Headless Automation
- Scenario: A GitHub Actions workflow uses
claude-code-actionto 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.jsonand knows it's allowed to runnpm 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.jsonorMakefile, and manually configure their.claude/settings.jsonor.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.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗