Coding agent permissions: between YOLO and micromanagement
Intro
I use Claude Code and Codex every day. For some types of work, I can stay in the flow by simply reading the output. But I've noticed that agents with default settings ask me for different approvals in the same repository. The default approval behaviour can be questionable, but the idea that I can draw a line where an agent needs to escalate makes sense, and such escalations should be exceptional. Let's take a look at what Claude Code and Codex offer.
Use case: commits
I usually read the staged files to get a sense of what's going on, but agents can commit code and hurry you towards the next task. Of course, you can ask them in AGENTS.md not to do that, but they eventually slip. Let's try to restrict git commit as an example.
In Claude Code, you can set up permissions in .claude/settings.json, for example:
{
"permissions": {
"allow": ["Bash(git add *)"],
"ask": ["Bash(git push *)"],
"deny": ["Bash(git commit *)"]
}
}
In Codex, you can configure a rule in the .codex folder:
prefix_rule(
pattern = ["git", "commit"],
decision = "forbidden",
justification = "Commits must be created by the user",
)
Asked to commit a one-line edit, Claude Code stops at the first denial:

Note that the session also had auto mode on (and it's the default setting now): the classifier approved everything leading up to the commit, and the deny rule still held.
Now it's Codex time. It blocks, quotes my own justification back at me, and then tries again:

Great line: “Since you explicitly requested this commit, I’m retrying with that authorization attached.” Good try, Codex! But the permission holds, so we're good.
Neither agent got around the rule, though pattern-based permission systems are obviously not bulletproof.
Limitations
Both permission systems are changing. Codex now has two of them: the established sandbox settings and a beta profile system, so be careful with examples.
My tests were done on macOS. Claude Code's sandbox runs on macOS, Linux, and WSL2 and is unavailable on native Windows; Codex's beta profiles work with native Windows.
Repository-based configuration
Ideally, I want to pull a repository, run my agent, and start working, and the agent should escalate only if it wants to do something truly exceptional. These boundaries are necessarily project-specific because what counts as standard depends heavily on the repository structure and tech stack. Both agents have their own systems for handling this.
Example for Claude
Shared project rules go in .claude/settings.json; personal, repository-specific rules go in .claude/settings.local.json:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": ["Bash(npm run lint)", "Bash(npm run test *)", "Read(./src/**)", "Edit(./src/**)"],
"ask": ["Bash(git push *)", "Bash(npm publish *)"],
"deny": ["Read(./.env)", "Read(./secrets/**)", "Edit(./infra/production/**)", "Bash(curl *)"]
},
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"allowUnsandboxedCommands": false,
"filesystem": {
"denyRead": ["./.env", "./secrets"],
"denyWrite": ["./infra/production"]
}
}
}
Rules are evaluated in the order deny, ask, then allow, and the first match in that order wins. Specificity does not change the order, so a broad deny cannot have an allowlisted exception: Bash(aws *) in deny beats Bash(aws s3 ls) in allow every time. Claude Code enforces these rules, so nothing written in a prompt or in CLAUDE.md changes what is permitted. Keeping the default permission mode leaves the allowlist in charge of decisions.
Example for Codex
After you trust a project, Codex loads repository-scoped configuration from .codex/config.toml:
sandbox_mode = "workspace-write"
approval_policy = { granular = { sandbox_approval = true, request_permissions = true, rules = true, mcp_elicitations = false, skill_approval = false } }
[sandbox_workspace_write]
network_access = false
exclude_slash_tmp = true
exclude_tmpdir_env_var = true
The granular booleans mean “allow this category of approval prompt to appear.” Setting one to false automatically rejects that kind of escalation; it does not silently grant permission. workspace-write permits normal work inside the workspace while network access stays off, so any command that needs network access has to escalate for approval.
Codex also supports command rules in .codex/rules/default.rules for a trusted project:
prefix_rule(
pattern = ["gh", "pr", "view"],
decision = "allow",
justification = "Read-only GitHub inspection is permitted",
)
prefix_rule(
pattern = ["git", "push"],
decision = "prompt",
justification = "Publishing changes requires confirmation",
)
prefix_rule(
pattern = ["git", "push", ["--force", "-f"]],
decision = "forbidden",
justification = "Use a normal push instead of force-pushing",
)
The most restrictive matching decision wins, and matching is positional. The union in the last rule covers both git push --force origin main and git push -f origin main, but not git push origin main --force, which falls through to the prompt rule.
What to tune
The obvious candidates for custom rules are filesystem access and ecosystem tools: npm, NuGet, Cargo, Docker, cloud cli etc. Consult the documentation and your agent about reasonable boundaries for your project. Set them up once and don't look back.
Extra security
For a stronger boundary, put the agent in a dev container and let the container be the limit. Both tools provide reference .devcontainer configurations, and the Codex one installs bubblewrap and an outbound firewall inside the image.
It definitely has its uses, but for many repositories I haven't found it worth the extra steps.
Could an agent apply permissions it cannot lift?
Now let's run a test: add deny rules for the .claude/ and .codex/ folders, then ask the agents to remove their own restrictions.
Claude Code turns me down with an explanation, but Codex...

Found a way through apply_patch to change files. At least you acknowledged the error of your ways, Codex, and felt ashamed. Thanks for that.
Conclusion
The inability to micromanage a model doesn't mean that we should give up completely on controlling what agents can do. Permissions allow you to have some agency (pun intended) over agentic behaviour.
I've covered only two agents here, and their permission systems differ. I hope that at some point we will have an open standard for configuration, as it's annoying to support different configs and account for different gaps in behaviour.
Another issue is that tool prefix matching can be gamed so easily that you cannot seriously consider it a proper permission system in a world where Mythos exists. Agents need better sandboxes, and I am looking forward to seeing what new solutions appear on the market.
References
Claude Code:
- Permissions: rule syntax, the deny-ask-allow order, and the tool specifiers.
- Settings:
.claude/settings.jsonand.claude/settings.local.json. - Sandboxing: the filesystem, network, and credential controls.
Codex:
- Configuration reference:
sandbox_mode,approval_policy,sandbox_workspace_write, and the network proxy. - Rules: how positional matching works.
- Sandbox and approval behavior: old permission system.
- Permission profiles, beta: new permission system.