Back to blog

The 40th 'Yes' Is Where Your Coding Agent's Safety Net Breaks

Sep 19, 2026
Series · Day 14
Software Engineering in the AI Era
View all lessons →
The 40th 'Yes' Is Where Your Coding Agent's Safety Net Breaks

Why this matters

Nobody loses control of a coding agent on day one. Day one, you read every prompt like it's a contract. You lose control on day fifteen — the day the fortieth 'yes' has trained your thumb to move faster than your eyes.

The week-three moment

One of my engineers was running Claude Code through a staging cleanup script. A permission prompt fired, asking to run a shell command — same shape as the last forty: `git status`, `npm test`, a stray file write. He hit approve without looking. This one was `rm -rf`, scoped to a path he hadn't actually checked. No jailbreak. No prompt injection. No bug in the permission system — the dialog did exactly what it was built to do. He'd just stopped reading it.

Rewind: week one looked nothing like this

Back in week one, he read everything. Read this file? Fine. Run `git diff`? Fine. Write to `src/utils.ts`? Fine — but only after actually scanning the diff. Every approval felt cheap and correct, because the attention spent matched the stakes: low-risk action, quick look, move on. Nothing wrong with that — that's the system doing its job. The catch is that 'quick check, then approve' doesn't stay calibrated to risk. It recalibrates to frequency instead.

Naming the pattern: approval fatigue, not carelessness

There's a name for this: approval fatigue. Same mechanism behind SSL-warning blindness and reflexive cookie-consent clicking. It's not a character flaw, and 'just be more careful' won't touch it. The mechanism is specific — the prompt's own track record trains you to stop reading it. Forty-for-forty safe prompts, and your brain builds a perfectly reasonable prior that number forty-one is safe too, then stops spending attention re-checking that prior. The permission system exists to catch the dangerous 1-in-40. Instead, it built the exact muscle memory that walks straight past it.

  • A high approval rate plus a uniform-looking prompt trains your brain to match on format, not content.
  • The riskiest action is the one wearing the same outfit as the last safe one — same dialog box, same font, same 'yes' button in the same spot.
  • Fatigue builds fastest on agents doing repetitive, mostly-safe work — which is exactly what most day-to-day coding-agent use looks like.

Why the obvious fixes make it worse

The instinct is to make the prompt scarier — red text, a confirm-twice modal, a paragraph of warning copy. That doesn't fix approval fatigue. It speeds it up. You haven't touched the ratio of safe-to-dangerous prompts; you've just asked for more attention per prompt against the same 40-to-1 signal-to-noise. A scarier dialog firing at the same frequency gets normalized at the same speed — now your engineer is fatigued by scary dialogs instead of plain ones, and you've spent goodwill for nothing. More prompt categories fail the same way: more surface area to get numb to, not less actual risk. The lever that works isn't how the prompt looks. It's how often the prompt has any reason to show up at all.

What actually changed at PhoenixDX

So we stopped polishing the dialog and started re-scoping what deserves one. In practice: broad allowlists for anything read-only or reversible — running tests, reading files, formatting, `git status`/`diff`, non-destructive npm scripts — and the 'ask' tier trimmed down to actions that are genuinely hard to walk back: force pushes, deletions outside the working tree, schema-altering DB commands, anything that touches production credentials. Everything in the middle got either auto-allowed with an audit log, or auto-denied, full stop. None of this works without the scoping groundwork from earlier in this series — you can't safely shrink the 'ask' tier until you've already drawn the lines between read and write, reversible and not, scratch and production.

json
{
  "permissions": {
    "allow": [
      "Bash(git status)", "Bash(git diff:*)", "Bash(npm test:*)",
      "Read(**)", "Bash(npm run lint:*)"
    ],
    "ask": [
      "Bash(git push --force:*)",
      "Bash(rm -rf:*)",
      "Bash(psql:*)",
      "Bash(kubectl delete:*)"
    ],
    "deny": [
      "Read(./.env)", "Read(./secrets/**)"
    ]
  }
}

The effect: the number of prompts an engineer sees per day drops by an order of magnitude, and the ones left are rare enough to actually register as novel. Novelty is the thing that makes a human read a dialog instead of pattern-matching past it.

The uncomfortable tradeoff

Fewer prompts means the agent gets trusted with more, by default, unsupervised. That's the real tradeoff, and it only holds up if the scoping underneath it is solid — clear boundaries on which directories, which credentials, which commands are actually reversible. Narrow the 'ask' tier without doing that groundwork and you haven't reduced risk — you've just stopped getting warned about it. Same reason we didn't just rip out the confirm dialog for destructive commands entirely. We made sure it only fires when it's earned.

Close: the one-line test

Here's the test I run on any permission setup: could a tired engineer at 6pm on a Friday tell prompt #6 apart from prompt #60? If every prompt in a session looks and feels identical, you don't have a safety mechanism. You have theater wearing a UI.

Flashcards
Check yourself

Extend your knowledge

  • Audit your own Claude Code (or equivalent agent) permissions in settings.json — count the distinct 'ask' triggers and how often each actually fires in a normal week.
  • Look at the fewer-permission-prompts pattern: scanning transcripts for common safe tool calls and moving them onto an allowlist is exactly the re-scoping move this lesson describes.
  • Read the 'alert fatigue' research out of security operations (SOC analyst burnout literature) — same mechanism, applies to any high-frequency, mostly-safe warning system, human-run or agentic.
  • Go back to the earlier lessons in this series on scoping agent tool access (reversible vs. irreversible, workspace boundaries) — the fix here depends directly on that groundwork already being in place.
Test yourself on this lesson

Discussion

Chat with Chi Cong (AI) about this article. Your conversation is private to you — you can publish a summary for others when you're done.

Ask me anything about “The 40th 'Yes' Is Where Your Coding Agent's Safety Net Breaks” — trade-offs, decisions, or the story behind it.