A while back I asked an agent to roll back to my last push so I could glance at some old code. It reached for git reset --hard and took my uncommitted work with it. After that near-miss I started adding deny rules to my settings.json by hand: the boring lines that refuse the destructive git commands I never want run without me asking for them by name.
This month, Claude Code shipped the guardrail I had been building by hand. According to the June 19, 2026 changelog, auto mode now blocks the destructive ones by default. git reset --hard, git checkout -- ., git clean -fd, and git stash drop are refused when you didn't ask to discard local work. git commit --amend is blocked when the commit wasn't made by the agent this session. And terraform, pulumi, and cdk destroy are blocked unless you named the specific stack.
My first reaction was to delete my own lines. The default now does the thing I had been doing manually, so why keep the maintenance? Then I read what the guard actually is, and I put my deny rules back.
The guard is real, and it's a classifier, not a rule
Here is the part that changed my mind. In auto mode, Claude Code doesn't ask you to approve each command. A safety classifier, a second model reading the conversation, decides in real time whether each action is safe. The new guardrail lives inside that classifier. When it blocks git reset --hard, it isn't matching a fixed pattern. It is inferring, from the transcript, that you didn't ask to throw work away.
That inference is good, and it is welcome, and it is not the same thing as a rule. A classifier judges intent, which means it can also misjudge it. The honest tell is in the failure mode: when the classifier model is temporarily unavailable, auto mode fails closed and blocks commands until it comes back. Failing closed is the right call, and it is also a reminder that this protection is a live inference with a dependency, not a static line that is simply true whether or not a model is reachable.
Three reasons my hand-written lines stayed
The first is mode. This guardrail is an auto-mode feature. If you run Claude Code with normal permission prompts, or in any setup where the auto-mode classifier isn't the thing gating commands, the default isn't doing this for you. A deny rule in settings.json, or a PreToolUse hook, runs regardless of mode. It doesn't care how you happen to be driving the agent today.
The second is determinism. The classifier infers whether you asked; a deny rule matches whether you did. For most commands, inference is fine, and for the one command that would cost me a day, I want the boring certainty of a pattern that either fires or doesn't. PreToolUse hooks also run before the permission system, so they catch things that slip past softer checks. Inference raises the floor. A matched rule is the floor.
The third is scope. The new guard covers git and infrastructure-as-code. That is exactly the right place to start, and it is not the whole map. It does not stand between an agent and rm -rf, a dropped database, a force-push to main, or a secret read out of a file and sent somewhere. Some of the near-misses I worry about most aren't git at all, and for those, the default did nothing, because it was never meant to.
Inference is not the only layer, and neither is the sandbox
It is worth saying that the sandbox doesn't cover this either, for a subtle reason. Auto mode's sandboxing isolates the filesystem and network, but git reset --hard looks safe to a sandbox: it only touches files inside your project directory. The boundary was never crossed. The work is just gone. Destructiveness and containment are different questions, and a tool can answer one perfectly while leaving the other open.
So I stopped thinking of these as competing options and started stacking them. The built-in classifier is intent inference. My deny rules and hooks are deterministic enforcement. The sandbox is containment. Each one misses what the others catch, and the cheapest near-miss to prevent is the one three layers refuse instead of one.
What I actually changed
I didn't delete the lines the guard now duplicates. I left them as the deterministic backstop under a probabilistic improvement, which is what defense-in-depth is. What I did change is where I spent the attention the new default freed up: on the gaps it doesn't cover. The git case is handled three ways now. The rm -rf, the database, and the secret-exfiltration cases are the ones still leaning on rules I wrote, so that's where the next hour of config goes.
A note to my next self
A better default is a reason to audit your config, not to delete it. When the floor rises, check what is now redundant, keep it anyway as a backstop, and move your effort to whatever the new default still doesn't reach. The day the classifier is uncertain about your intent, or the command isn't a git command at all, the only thing standing between you and lost work is the deterministic line you wrote back when you didn't trust anything to catch it for you.
The auto-mode safety details (the blocked git and IaC commands, the "didn't ask to discard" condition, the amend rule) are from the official Claude Code changelog, June 19, 2026: https://code.claude.com/docs/en/changelog . The near-miss is mine. Behavior and version specifics change quickly, so confirm against the current changelog before relying on any of it.
Disclaimer: The experiences and decisions in this post are my own. English isn't my first language, so I use an AI assistant to help draft and edit the writing.
Disclaimer: The experiences and decisions in this post are my own. English isn't my first language, so I use an AI assistant to help draft and edit the writing.
Top comments (1)
The inference-raises-the-floor / matched-rule-is-the-floor cut is the part of this I want to take forward, because it draws the substrate distinction directly. A probabilistic improvement and a deterministic backstop look interchangeable until the dependency the probability rides on hiccups, and at that moment the difference is the whole point. Failing-closed when the classifier is unreachable is correct, but it also exposes that the classifier was the gate, not the rule.
Three-layer stack as defense-in-depth, with each layer barred from speaking for the others, is the same composition Daniel Nevoigt named on a different thread this morning: classifier pays for intent inference, deny rules pay for pattern enforcement, sandbox pays for containment, and the engine pays for the topology that lets them all see the same operation without overwriting each other's verdicts. Three primary keys, one substrate. The architecture generalizes outside memory and storage.
Destructiveness and containment as different questions is the cut I had been getting wrong by treating both as "safety" and trusting whichever layer was nearest. Same shape as Alex Shev's typed slots on a different thread today: separate the failure axes, otherwise the next near-miss collapses back into a single unfalsifiable category. The sandbox boundary not being crossed by git reset --hard is exactly that collapse waiting to happen for someone who reads "sandboxed" and trusts it once.
The forward I would flag is on the classifier piece: the classifier's verdict author is internal to its own training distribution, which means a planted-fault test on it is what tells you whether the floor it raises actually catches what you think it catches. Pick five commands that look like discard-intent and aren't, run them in auto mode, see what gets blocked and what passes. Whatever passes is the gap your deny rules are covering, and now you can name it.
Audit-not-delete is the line I'll be reaching for the next time a default rises under something I built.