Claude Code permissions for a team: what to allow, what to ask
The first week a team shares a coding agent tends to go like this. One engineer has approved every prompt by hand, a hundred times a day, and is sick of it. Another has turned approvals off entirely. The third finds out about the difference when the agent force-pushes over a branch, or runs a migration against the wrong database because a .env file was sitting there.
Each setup made sense on one laptop. The trouble starts when the agent becomes a shared teammate and nobody has written down what it's allowed to do.
Below is the policy we'd write on day one, and how it maps to Claude Code's settings.
Three tiers: allow, ask, deny
Sort every action by two questions. Does it leave the machine? Can you undo it in a minute?
- Allow: stays on the machine and is easy to undo. The agent just does it.
- Ask: leaves the machine, or is hard to undo. The agent stops and a person says yes.
- Deny: the agent should never do it, even with a yes in the moment, because the blast radius is too big or the yes would be rushed.
The permission table
This is a starting point for a team of two to fifteen engineers. Move rows to fit your risk, and write down why.
| Action | Tier | Why |
|---|---|---|
| Read any file in the repo | Allow | The agent can't help without context |
Read .env, key files, credential folders |
Deny | Secrets end up in logs and prompts |
| Run tests, linters, type checks, the local build | Allow | Local, repeatable, no side effects |
| Edit files on a feature branch | Allow | Git is the undo button |
| Install or upgrade dependencies | Ask | Supply chain risk, and lockfile churn |
| Commit on a feature branch | Allow | Cheap to amend or drop |
| Push a feature branch, open a pull request | Allow | Review happens in the PR |
Push to main, force-push anything |
Deny | Goes through a PR, always |
| Merge a pull request | Ask | A human owns what ships |
| Deploy to production | Ask | Leaves the building |
| Run migrations or scripts against shared databases | Ask | Hard to undo |
| Delete files outside the repo, branches, cloud resources | Ask | Can't be undone |
| Send email, post in channels, comment on customer tickets | Ask | Someone reads it immediately |
| Spend money: paid APIs, cloud resources, purchases | Ask | Self-explanatory |
| Change CI, IAM, or the agent's own permissions | Deny | The agent shouldn't widen its own scope |
The two rows people argue about most are dependencies and merges. If your CI is strong and your PRs are small, letting the agent install packages from a lockfile-only command is reasonable. Merging is a judgment call about what ships, so we keep that with a person.
.env and credentials. Push to main or force-push. Change CI, IAM or its own permissions.Mapping it to Claude Code settings
Claude Code reads permission rules from settings files with allow, ask and deny lists. The two that matter for a team are the project file .claude/settings.json, which you check into the repo, and .claude/settings.local.json, which each person keeps to themselves and doesn't commit. Put the team policy in the shared file, so every engineer's agent starts from the same rules.
A minimal version of the table above:
{
"permissions": {
"allow": [
"Bash(npm run test:*)",
"Bash(npm run lint)",
"Bash(git status)",
"Bash(git diff:*)",
"Bash(git commit:*)",
"Edit"
],
"ask": [
"Bash(npm install:*)",
"Bash(gh pr merge:*)",
"Bash(git push:*)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(git push --force:*)",
"Bash(git push origin main)"
]
}
}
One difference from the table: the file puts every git push on ask. A command-prefix rule can't reliably tell a feature branch from main, so the agent asks before any push, and branch protection on main in GitHub enforces the deny row for real. Rule syntax and precedence change between versions, so check the current Claude Code docs before you copy this. Then ask the agent to read .env and confirm it refuses.
Two habits keep the file honest:
- Review it like code. Changes to
.claude/settings.jsongo through a PR, with a reason in the description. - Prefer narrow allows.
Bash(npm run test:*)is better thanBash(npm:*). Wide rules creep.
An example: a bug fix under this policy
This one is made up.
The ask in the team channel: "The signup button is hidden on mobile Safari. Fix it and open a PR."
What the agent did alone: read the signup component and the CSS, found a rule hiding the button below a certain width, changed it, ran the tests and the linter, committed on a branch called fix/signup-mobile, pushed the branch and opened a PR with a short description.
Where it stopped and asked: it wanted to upgrade a CSS library to the version that fixed a related bug. That's the dependency row, so it asked. The engineer said no: "Not in a bug fix. Open a separate ticket."
What the engineer changed: asked for a mobile-width screenshot, which the agent added to the PR.
What got approved: the merge, after review, then the deploy. Two yeses, both from a person. Everything else ran without a prompt.
How we do it at our company
Our engineer bot runs on its own cloud computer. That changes the deny column. The machine has only what we gave it: a git remote, logins for the apps we connected, and the files in its folder. It never sees anyone's laptop, and nothing on the internet can connect in. The rules in the agent's settings still matter, as a second line of defence. All five of our bots work to one rule: a bot can read, research, draft and build alone. Sending, posting, paying, deploying and deleting wait for a yes.
How to set it up in Caret
- Sign up at app.caretbot.com. Team starts with a 7-day trial.
- Create an engineer bot. Pick Claude Code or Codex and the model, running on your own Claude or ChatGPT plan.
- Write the permission table into its job in plain words, including the deny rows.
- Connect GitHub and give it one repo to start.
- Add it to the thread where bugs get reported. It's bridged to Slack both ways.
- Approve deploys and deletes from the approval card in the thread. An admin answers with one click, and the audit trail shows what the bot did before it asked.
Example asks:
- "fix the hidden signup button on mobile from the report above, open a PR with a screenshot"
- "review PR 73, run the tests and tell me what looks risky"
- "every day 09:00 check last night's jobs and tell me if anything failed"
fix the hidden signup button on mobile from the report above, open a PR with a screenshot
Fixed the CSS rule hiding the button below a certain width. Tests and linter pass. PR opened from fix/signup-mobile, mobile-width screenshot attached.
Reviewed and merged. Ship it.
Deploy to production
ApproveDenyApproved.
An example thread.
FAQ
How do I share Claude Code permissions with my team?
Put the rules in .claude/settings.json at the root of the repo and commit it. Everyone who runs Claude Code in that repo gets the same allow, ask and deny lists. Personal additions go in .claude/settings.local.json, which stays out of git.
Should a coding agent be allowed to push to main? No. Let it push feature branches and open pull requests, and keep merges and deploys on a human approval. A PR gives you a diff to review and an easy way to say no.
Is it safe to skip permission prompts in Claude Code? Only on a machine with nothing to lose: no secrets, no production access, a disposable checkout. On a laptop with your credentials on it, keep the prompts and write narrow allow rules for the commands you approve every day.
For the rest of an engineer's week with bots, see what Caret does for engineers. Put a bot on it: start your 7-day trial or download the Mac app.