DEV Community

Cover image for How I Learned to Stop Worrying and Love --dangerously-skip-permissions
Zirkman
Zirkman

Posted on

How I Learned to Stop Worrying and Love --dangerously-skip-permissions

The flag is called --dangerously-skip-permissions. A year ago, a few weeks into learning the then-new Claude Code, I got tired of approving every shell command and turned it on — on my main machine, no container, no VM. Every command auto-approved, including any command that could have wiped the disk.

It never wiped anything. My throughput jumped visibly within days. And it started a pattern I have since repeated often enough to name it: find the human approval gate that no longer catches anything, remove it, and replace it with an automated check.

This is the story of four of those gates — three removed, one I am deciding on now.

Context

I'm a solo AI consultant and full-stack developer in Slovakia. I run multiple repos in parallel — my own products and client projects — with Claude Code as the primary implementation engine. Everything below is my real working setup, not a thought experiment.

Gate 1: per-command approval

Approving every Bash command feels like control. In practice it is mostly latency: after a few days you are pattern-matching on the shape of the command and pressing yes.

So I made the YOLO decision and ran with --dangerously-skip-permissions for several weeks. I want to be honest about the order of operations: the trust came after the leap, not before it. What justified it retroactively was a simple observation — in weeks of auto-approved commands, the number of times the removed gate would have saved me was zero.

Then I replaced my attention with something that doesn't get tired: hooks. A pre-execution hook pattern-matches destructive commands (recursive deletes and friends) and blocks them before they run. The gate didn't disappear — it was demoted from human to code.

Gate 2: my own server

On the strength of that experience I put Claude on my VPS and made it the server's administrator. Today I do the same thing over SSH from local sessions: the agent connects, diagnoses, fixes, and I read the report afterwards.

Same pattern, bigger blast radius, same result: the catch rate of me hovering over every command on the server was not worth the hovering.

Gate 3: the implementation itself

This summer the pipeline looks like this. I write an assignment — for bigger things, a vision document. The agent interviews me about the unclear parts, then writes a GitHub issue, or a series of issues with an explicit dependency graph. Each issue is written to be self-contained: context and why first, settled decisions with the rejected alternatives named, scope and out-of-scope, verifiable acceptance criteria. The issue has to carry a first-time reader with zero context from the original conversation — because that is exactly what the worker agent will be.

Then I type /orchestrate-task queue 57 55 (a custom slash command) and walk away. Per issue, a worker with fresh context, in its own git worktree:

  • implements the issue,
  • writes tests, and the pipeline mutation-validates them — mutate the implementation, require the suite to go red; a test that survives mutation of the code it claims to cover gets rewritten or thrown away,
  • runs a self-review, then a hostile critic review in a separate fresh context,
  • runs a cross-vendor review — the diff goes to a different vendor's model (codex exec review) precisely because it does not share the implementer's blind spots,
  • runs a blind assignment review — a fresh reviewer gets only the original issue text and the final diff, without the implementer's narrative, and answers one question: does this diff actually implement this assignment?
  • fixes what the reviews found, or opens follow-up issues for what doesn't belong in this change,
  • updates the documentation,
  • commits and pushes to a feature branch and opens a PR.

What's left for me is the final PR review and two words: "merge" and "deploy". This runs across several projects in parallel.

The cross-vendor stage earned its place with data. On one production repo, the cross-vendor pass returned 7 findings — including 2 concurrency data-loss bugs — that both same-model review stages had missed. My working explanation, not a vendor claim: reviewers running on the same base model as the implementer tend to nod along the same reasoning grooves. A different model family disagrees differently. Since then, cross-vendor review is a standing stage for anything touching security or data integrity.

The two times it bit me

Removing gates is not free, and I have the scars to prove it.

Once, a worker running in a git worktree explicitly cd-ed into the repo's main checkout and ran git reset --hard there — moving a real branch of the main repo, not its own isolated copy. Recovered from reflog. The rule that came out of it is now in every worker brief: never cd out of your worktree, and run pwd -P before any destructive git command.

Another time I let a run chain a PR merge with post-merge cleanup in one command. The merge failed; the cleanup half executed anyway — deleted the branch and closed the PR. Reflog again. The rule: cleanup runs only after the new main SHA has actually been observed. Never chain a verification gate with the action it is supposed to guard.

Neither incident put a human gate back. Each became a rule that every future run carries. Trust is not restored by supervising harder; it is restored by encoding the failure.

Gate 4: auto-merge — the one I'm deciding now

Today every PR still ends with me. And the honest observation is the same one as a year ago: my final review increasingly finds nothing the pipeline has not already found. That is the signal. It is the same threshold at which the earlier gates went.

The removal will not be a global flip. The design is per-repo: each repo gets a written merge policy that classifies how trustworthy its verification actually is — real test suite? CI? deploy smoke checks? The default is auto-merge OFF with the reason written down, and a repo earns the flag per class of change, never on day one. Deploy, spending money, anything irreversible — those stay human.

Why bother at all: a human reading every PR caps the fleet at what one human can read. A few parallel agents fit through that gate. Dozens do not.

The metric

I don't think "trust in AI" is a feeling you talk yourself into. It is a number you read off your own ledger: when did this gate last catch something the automated checks missed? If the answer is "months ago", the gate is no longer a control — it is a queue. Remove it, automate the check it used to perform, and spend the recovered attention on the next gate up.

The word YOLO was only accurate the first time. Every leap since has been reading the ledger.

How do you decide when your agents' output no longer needs you in the loop?

Top comments (1)

Collapse
 
seasonkoh profile image
WebAZ

I like the gate-catch-rate metric, but I would pair it with a second one: what is the worst side effect that can escape this gate before another control notices? A gate can have caught nothing for months because the path is mature, yet still be the wrong one to remove if its failure is irreversible. The pattern I trust is change-class specific: measure catch rate, prove rollback or containment, encode the failure as a deterministic check, and keep a compact receipt of what the automated run changed. Then autonomy is earned per transition class rather than granted to the whole agent.