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 (5)

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.

Collapse
 
zirkman profile image
Zirkman

Very sharp suggestion! You're right that catch rate only measures frequency and says nothing about the blast radius of what slips through, and a quiet gate on an irreversible path is quiet for the wrong reason. The per-class part I already run (each repo has a written merge policy, and auth/payments/migrations never qualify regardless of track record), but "prove rollback or containment before removing the gate" wasn't an explicit condition in mine — it is now. I'm adding it to the merge policy as a requirement for enabling any class: green checks + zero catches + one demonstrated rollback. Thanks for making the second metric explicit.

Collapse
 
skillselion profile image
Skillselion

Most people running skip-permissions do the first half of your demotion and quietly skip the second - the gate goes away and nothing replaces it, which is a different decision wearing the same flag. One caveat on the pattern-matching hook for destructive commands: blocklists catch the command shapes you predicted, and shell composition is specifically good at producing shapes you did not - the pipe-to-shell, the base64 decode that becomes an exec, the rm that arrives inside a heredoc. For anything long-running I have more confidence in the inverted version: a short allowlist of write-capable commands, everything else read-only by default. Same demotion, but the failure mode is a false block instead of a false pass. On gate 2, the VPS admin sessions are the one where I would want the rollback story spelled out: when the agent is the administrator and the report comes after the fact, what is your undo - snapshot before each session, or something finer-grained?

Collapse
 
kenimo49 profile image
Ken Imoto

"Demote the gate from human to code" is exactly what I landed on running publish pipelines on cron. Your chained-cleanup bite has a twin in mine. A publish step failed, the cleanup ran anyway, and I woke up to half-broken state that had already shipped downstream to three platforms before I even saw the error. The rule now is blunt: any failure kills every side effect below it in that run. Same shape as your "cleanup only after the new SHA is observed."

The repair was a written rule the next worker carries, not me watching harder. That part stuck. The ledger metric is what I want to steal, because I still eyeball every scheduled publish even though the automated checks catch more than I ever do.
So how do you write the per-repo merge policy down? Markdown the worker reads, or something the pipeline enforces?

Collapse
 
innovationsiyu profile image
Siyu

Your rule of removing gates whose catch rate is zero is exactly right, but it also forces the opposite question. Which gates should never be demoted? For me it is anything that touches another person's attention. In Opportunity Skill, discovery and message triage are automated, but outreach always stops for human confirmation. Sending a message to someone cannot be undone with a git revert. The failure it catches is not an error but an awkwardness that costs trust. Removing friction that slows you down is smart. Keeping friction that protects other people is design.