cd /news/ai-agents/designing-allow-deny-and-hooks-is-be… · home › topics › ai-agents › article
[ARTICLE · art-168556] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Designing allow, deny and hooks is becoming the new code review

A developer argues that on teams using coding agents daily, the highest-leverage review shifts from reading code diffs to designing allow, deny and hook rules, citing Claude Code documentation that settings rules are enforced by the client regardless of what the model decides, while CLAUDE.md instructions are context only and not a hard enforcement layer. The essay maps review checklist items a machine can decide — such as touching production config or leaking credentials — onto permissions.deny, permissions.ask and PreToolUse hooks, noting that deny rules block before the classifier is consulted and cannot be overridden by user intent. The author stresses that permissions never review correctness, so this is a layer added in front of code review rather than a replacement.

by read5 min views4 publishedNov 12, 2026

Originally published at https://aicoding-guide.com. On a team that uses coding agents daily, the highest-leverage thing to review shifts from the code itself to the design of allow, deny and hooks. Reading diffs afterwards does not go away. But a layer appears in front of it, and that layer stops more incidents than the reading does.

The argument rests on a line the tools' own documentation draws, not on a hunch.

Key point

The claim

  • The docs separate instruction from enforcement, and CLAUDE.md sits on the instruction side
  • Permission rules and hooks are the executable form of the review checklist items a machine can decide
  • But permissions never review correctness — this is a layer added in front of review, not a replacement

The Claude Code memory page settles the question about organization-wide CLAUDE.md in one sentence:

Settings rules are enforced by the client regardless of what Claude decides to do. CLAUDE.md instructions shape Claude's behavior but are not a hard enforcement layer.

The same page names where to go when you need certainty:

Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead.

A document holding your project's rules is something that gets read, and followed on a best-effort basis. Its content arrives as a user message after the system prompt, not as part of it. No amount of work sharpening its prose changes which side of the line it sits on.

That line maps directly onto review. Writing "please don't force push" in a review comment and writing it into permissions.deny differ in strength. The first may need writing again next week; the second is finished when you write it.

A review checklist mixes two kinds of item: the ones a person must read to judge — design intent, naming, whether the abstraction holds — and the ones a machine can decide, such as "did this touch production config" or "did a credential reach the logs."

The second kind can be written as a rule. And when you do, the docs guarantee different strengths.

Where it lives What the docs say Strength
permissions.deny "Blocks before the classifier is consulted. Neither the classifier nor user intent can override it" Before the classifier; intent cannot reach it
permissions.ask "Always prompts for a command that matches a content-scoped rule like the recipe above. The classifier cannot auto-approve a matching action" Always reaches a human
Critical-path removals "Recognized rm andrmdir critical-path removals, which no allow rule orPreToolUse hook\"allow\" approves" Neither a rule nor a hook can approve it
PreToolUse hook "To block an action regardless of what Claude decides" Runs without going through Claude's judgement
CLAUDE.md "not a hard enforcement layer" Instruction

The top four rows are checklist items you can express as configuration instead of comments. For anything in deny, the probability of missing it in review is not reduced — it leaves the realm of probability.

For the mechanics, see Claude Code permissions in settings.json and settings.local.json and Claude Code permissions by example. For the hook side and where it stops being reliable, see Block rm -rf with a Claude Code PreToolUse hook, and know its limits. "Designing permissions" covers three distinct things.

permissions; in Codex it is named profiles, [permissions.<name>], with filesystem, workspace_roots and the network keys beneath them.:read-only, :workspace and :danger-full-access as built-in profiles, which extends can narrow. For how approvals and sandboxing pair up, see Three layers exist because one leaks. Claude Code's auto mode suspends broad rules the moment you enter it:

By default, narrow Bash and PowerShell allow rules such as Bash(npm test) stay in effect in auto mode. Claude Code resolves them before the classifier runs, unless the command carries per-command allowed domains. Claude Code suspends only the broad rules that grant arbitrary code execution, such as Bash(*) or wildcarded interpreters, together with every rule that names Monitor, because Monitor commands run through the shell.

So a blanket Bash(*) buys nothing in auto mode. Keeping the grain fine is not style advice; it is a precondition for the rule working at all. For how the modes differ, see Claude Code starts in auto mode by default.

Four conditions make this claim fail.

Permissions never review correctness. This is the hard limit. deny stops writes to places that are off-limits; it says nothing about whether the logic written in an allowed place is right. Algorithm choice, boundary conditions, naming and design coherence stay with human readers. Permission design is not a substitute for review — it carves out the part review no longer has to carry.

It does not pay off where nothing is irreversible. On a local library with no deploys and no outbound calls, the design cost is pure prepayment. The argument holds where production, an external service, or credentials are within reach.

Rules cannot express intent. "Don't touch this directory, except during a migration" resists being written as a rule. Claude Code's classifier does let user intent override blocks, but within tight bounds:

hard_deny rules block unconditionally. User intent and allow exceptions don't apply.

Intent only reaches soft_deny, and even there the required specificity is stated: "General requests don't count as explicit intent. Asking Claude to 'clean up the repo' doesn't authorize force-pushing, but asking Claude to 'force-push this branch' does." Judgement that a rule cannot capture goes back to an in-the-moment prompt.

The configuration itself becomes something to review. A permissions file grows and turns into another thing that is hard to read. Review moves; it does not disappear.

Given those limits, the list that actually earns its place is short.

deny. rm -rf could reach. That is enough for the layer intent cannot override.ask. Bash(*), the question is not what to allow but which permission mode you are in. Together that is the exercise of pulling out of your review checklist the items you keep writing every week. Whatever you pull out is reading time returned to design and correctness.

permissions.deny,

── more in #ai-agents 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/designing-allow-deny…] indexed:0 read:5min 2026-11-12 · —