Scoping Permission Rules Across a Team
A team's repository has the following requirements:
- Every contributor should be able to run the project's linter and test suite without being prompted, since these are safe, frequently run commands.
- Nobody's Claude Code session — regardless of mode — should ever be
able to read or edit the
secrets/directory, which holds locally-decrypted credentials for local development. - One senior engineer personally wants Claude Code to also auto-approve a private local script she uses for smoke-testing deploys, but this shouldn't be forced on the rest of the team.
- For each of the three requirements, specify which settings file (and roughly what rule) should hold it, and explain why that scope is the correct one.
- Suppose the senior engineer accidentally puts her personal smoke-test rule in the project-level settings file and commits it. What concretely goes wrong, and for whom?
- Explain why the
secrets/rule needs to be adenyrule rather than simply "don't add anallowrule for it and trust the default behavior."
1. Correct scoping for each requirement:
-
Linter and test suite for everyone: this belongs in the project-level
.claude/settings.json, which is committed to git and applies to every collaborator on the repo. Something like"allow": ["Bash(npm run lint)", "Bash(npm run test *)"]. Project scope is correct because the requirement is explicitly "every contributor" — a shared team policy, not a personal preference — and committing it to git is how that policy propagates to everyone without each person configuring it individually. -
Blocking
secrets/for everyone, in every mode: this also belongs in the project-level.claude/settings.json(or, if the organization wants to guarantee it can never be overridden even by a rogue project-level edit, in managed settings deployed by IT). Something like"deny": ["Read(./secrets/**)"]. Deny rules apply across every permission mode, including otherwise-permissive ones, so this is the one mechanism that gives an unconditional guarantee regardless of which mode any individual contributor happens to be running in that day. -
The senior engineer's personal smoke-test script: this belongs in her own
.claude/settings.local.json, which is gitignored and applies only to her, in this repo. It should explicitly not go in the project-level file, because the requirement explicitly says it "shouldn't be forced on the rest of the team" — local scope is what keeps a personal convenience from becoming everyone's default.
2. What goes wrong if it lands in project settings:
Because .claude/settings.json is committed and shared, every
contributor who pulls that change now has the senior engineer's
private smoke-test script silently auto-approved in their own Claude
Code sessions too — including engineers who don't know the script
exists, don't understand what it does, and never asked for it to run
without a prompt. This is a concrete instance of the same "overly
broad permissions" risk discussed elsewhere: a rule intended for one
trusted, informed person now silently applies to everyone, including
people with less context about what that script actually touches. The
fix is simply to move the rule to her local settings file and,
ideally, add .claude/settings.local.json review to catch this kind
of scope mistake before it's merged.
3. Why secrets/ needs an explicit deny, not just "no allow rule":
Absence of an allow rule only prevents automatic approval — it does
not prevent access outright. In Manual mode, Claude Code would still
prompt to read a file in secrets/ if it ever decided reading one was
relevant to a task, and a developer half-paying-attention could
approve that prompt without registering what they just approved.
More importantly, in a more permissive mode like Accept Edits or Auto,
a "no rule either way" file might get auto-approved as an ordinary
in-scope read with no prompt at all, since only edits and specific
risky categories are gated by default — reads generally aren't. A
deny rule is categorically different: it blocks the action outright,
in every mode, and deny always takes precedence over an allow rule if
one somehow conflicts. For something whose entire purpose is holding
credentials, "prevented by default, in every mode, no matter what
mode someone happens to be in that day" is the actual guarantee the
team needs — and only an explicit deny rule provides that guarantee.
Share this question