AI编码
dev.to ·
@AI Workspace Builder
面向团队的 Claude Code 权限配置:默认安全的共享 settings.json
文章介绍如何用提交到仓库的 .claude/settings.json 统一团队 Claude Code 权限,区分仓库共享、个人本地和全局三层配置文件,并给出 allow/ask/deny 示例:允许测试、lint、只读 git 等高频安全命令,push 等操作需人工确认,禁止读取 .env 和 secrets。文中强调 deny 规则优先于 ask 和 allow,且本地 allow 无法覆盖团队 deny,因此共享文件可作为安全基线。
AI推荐理由 这是一篇面向团队使用 Claude Code 的实操指南,具体介绍了 .claude/settings.json、settings.local.json 和 ~/.claude/settings.json 三层配置的分工,并给出 allow/ask/deny 的示例配置。文中还说明了 deny 优先于 ask、ask 优先于 allow 的匹配顺序,以及 deny 规则无法被本地 allow 规则覆盖这一关键机制,对团队安全落地有参考价值。局限在于内容属于经验性配置建议,没有官方文档引用或实测数据,且示例命令需按项目替换。
62
正文
When one developer uses Claude Code, permissions are a personal habit. They click "yes" on the commands they trust and "no" on the ones they don't, and over a few weeks their setup settles into something that works for them.
On a team, that habit doesn't scale. Every developer ends up with a different set of approvals, nobody knows what anyone else's agent is allowed to run, and the new hire clicks through prompts on day one without knowing which ones matter.
The fix is a shared permissions file, committed to the repository, that every developer's Claude Code session starts from.
The three files that matter
Claude Code reads settings from several places. For a team, three of them matter:
File
Who it applies to
Commit it?
.claude/settings.json
Everyone working in the repository
Yes
.claude/settings.local.json
One developer, in this repository
No
~/.claude/settings.json
One developer, in every project
Not in the repo
The shared file is where team rules go. The local file is for personal exceptions, so a developer who wants one extra command approved doesn't have to change the team file. When Claude Code creates the local file itself, it keeps it out of git; if someone creates it by hand, they need to add it to .gitignore.
Organizations that need rules nobody can override can also use managed settings, which sit above all three.
What goes in the shared file
A good starting point is short:
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)",
"Bash(git status)",
"Bash(git diff *)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
}
}
Enter fullscreen mode
Exit fullscreen mode
Replace the commands with your project's own. The pattern is what matters:
Allow the commands developers run dozens of times a day and that can't do damage: tests, lint, type checks, read-only git. Every prompt you remove here is a prompt nobody learns to click through without reading.
Ask for actions that are fine but deserve a human glance: pushing, publishing, running a migration locally.
Deny reads of secrets, and any command your team never wants an agent to run.
Lists from different files are combined, not replaced. A developer's personal allow rules add to the team's list; they don't remove the team's deny rules.
Rule order: deny wins
Claude Code checks deny rules first, then ask, then allow. The first match in that order decides, and a more specific rule doesn't change the order.
That means an allow rule can't carve an exception out of a deny rule. If the team file denies Bash(aws *), a developer adding Bash(aws s3 ls) to their local allow list still gets blocked. This is what makes the shared file safe to rely on: a team deny rule holds no matter what anyone adds locally.
Writing rules that match what you mean
A few details decide whether a rule does what you expect:
The * matches any text in its place. Bash(npm run test *) matches npm run test with any arguments.
The space before a trailing * matters. Bash(ls *) matches ls and ls -la but not lsof. Bash(ls*) matches lsof too.
Compound commands are split. An allow rule for Bash(npm run test *) does not approve npm run test && rm -rf build. Each part has to be allowed on its own, and a deny rule applies if any part matches it.
File rules use paths. Read(./.env) covers one file; Read(./secrets/**) covers everything under that folder.
Where permission rules stop
Permission rules shape what the agent does. They are not a security boundary on their own.
A Bash rule matches the command text the agent writes. The same program run a different way (through a variable, a script, or sh -c) may not match. The Claude Code documentation is direct about this: rules that try to restrict command arguments, such as limiting curl to one domain, are fragile.
For things that must never happen, add a second layer:
Sandboxing enforces filesystem and network limits that don't depend on how a command is written.
A PreToolUse hook runs your own check on every command before it executes, and can block it. Hooks live in the same shared settings file, so the whole team gets them.
Real access control still applies. If an agent should never touch production, the developer's machine shouldn't hold production credentials.
Rolling it out
Start with deny rules for secrets and allow rules for tests and lint. That alone removes most prompts and the riskiest reads.
Commit the file in a normal PR, so the team reviews it like code.
Ask developers to note any prompt they approve more than twice in a week. Those are candidates for the shared allow list.
Run /status in Claude Code to confirm the file loaded. It lists the settings sources in use.
Review changes to .claude/settings.json with the same care as changes to CI configuration. It decides what every developer's agent can do without asking.
Starting from the docs you already have
Permissions are one part of a team setup. The other part is the instructions: the commands, the conventions and the ownership rules your agent needs to follow. Most teams already have those written down in an onboarding guide or engineering handbook.
That is what we built AI Workspace Builder for. You upload the docs your team already has, and it generates the CLAUDE.md, a profile for each role, and an install script in 15 to 30 seconds, using your own Anthropic API key. There's one free trial workspace, no card required. If you'd rather start by hand, our free templates include a shared settings file.