Auto-approve safely: a rule pattern guide

Which commands your AI agent can run silently, which should always prompt, and the regex / glob / prefix patterns that hold up across Claude Code, Codex, Gemini, and Copilot CLI.

Once you have permission control set up — meaning every dangerous tool call your AI agent makes lands somewhere you can review it — the next move is to drown out everything that isn’t dangerous. If your phone buzzes for every cat package.json, you’ll start ignoring buzzes for things that matter. The fix is rules.

This post is a practical guide: which commands to auto-approve, which to always prompt, and what the patterns actually look like. The patterns are tool-agnostic — they apply whether you’re using Claude Code, Codex CLI, Gemini CLI, or Copilot CLI — though I’ll show how PromptBeat handles them at the end.

The taxonomy: three buckets

Every command an AI agent might run falls into one of three buckets:

  • Read-only. The command observes state but doesn’t change it. Auto-approve silently.
  • Mutating but reversible. The command changes state in ways you could undo if you noticed. Auto-approve conditionally — specific patterns yes, broad patterns no.
  • Mutating and hard to reverse. Network calls, force operations, package installs, secrets-related. Always prompt.

Most rule-engine mistakes come from putting things in the second bucket that belong in the third.

Bucket 1: Auto-approve silently

These are the commands that should never bother you. If you’re prompting on these, you’re training yourself to ignore prompts.

# Filesystem reads
ls *
cat *
head *
tail *
find . -type f *
file *

# Search
grep *
rg *
ag *
fd *

# Project introspection
git status
git diff *
git log *
git branch
git show *
git stash list

# Language tooling, pure-read
node --version
python --version
npm list *
pip list
pip show *

# Tests (almost always safe — they just run)
npm test *
pytest *
go test *
cargo test *
mvn test *

Pattern type: prefix. The first word locks the command, the rest is wildcard. PromptBeat lets you express this as a prefix rule on the tool name plus the command stem — e.g. tool=Bash, prefix=git status, scope=session or forever.

One subtle thing: tests can fail in ways that mutate state (a test that calls a real API, drops a real DB row, sends a real email). If you’re doing integration testing, downgrade npm test to bucket 2.

Bucket 2: Approve once, decide on patterns

These commands change state, but the change is local and reversible. Auto-approve specific patterns; never auto-approve the broad form.

# Local file writes — auto-approve only inside your project
write_file path=/Users/me/projects/foo/**

# git commits with no remote interaction
git commit -m *
git add *

# Local builds
npm run build
yarn build
cargo build *
make

# Editing files in known-safe paths
edit_file path=src/**
edit_file path=tests/**

# Branch operations (no force, no remote)
git checkout *
git checkout -b *
git merge --no-ff *

Pattern type: glob on the path argument, or regex when you need stricter matching. The broad form (git commit *) is safe; the form to never auto-approve is anything with --force or --no-verify.

If your rule engine supports priorities, give the auto-deny rule a higher priority than the auto-approve rule. That way git commit -m "wip" --no-verify hits the deny rule first, and the approve rule never sees it.

Bucket 3: Always prompt (or auto-deny)

These are the commands you cannot let an AI agent run unattended. Either always prompt, or auto-deny outright.

# Force / destructive
rm -rf *
rm -fr *
git push *
git push --force *
git push -f *
git reset --hard *
git clean -fd *

# Package installs (supply-chain risk)
pip install *
npm install *
yarn add *
cargo add *
go install *

# Network calls of any kind
curl *
wget *
fetch *

# Anything sudo
sudo *

# Anything that reads secrets
cat .env *
cat **/.env*
echo $SECRET*
env *

# Database operations
DROP *
DELETE *
TRUNCATE *

Pattern type: regex with anchors. The reason regex matters here is that “contains --force” will match commands that mention --force in a comment, or in a filename. \b--force\b matches it as a word boundary. Avoid catastrophically backtracking patterns — if your rule engine supports a ReDoS guard, leave it on.

Time-boxing: rules that expire

The pattern that makes auto-approve actually safe is letting it expire. You’re working in ~/projects/foo/ all afternoon — auto-approve writes there, but only for this session, not forever. PromptBeat calls this “Approve for session” — a pattern stored against the chat session ID, swept when the session ends.

The mental model: standing rules for things you’ll always be okay with (running tests, reading files), session rules for project-specific things (writes inside this directory, commits to this branch), and one-off approvals for everything else.

Checking your rules without running anything

Before trusting a rule, dry-run it against the last 100 commands your agent ran. If a rule auto-resolves a command you’d have wanted to see, the rule is wrong. The audit log makes this easy — export the last week of permission requests, replay them through your rule engine, count the false positives.

The rough target: ninety percent of commands auto-approved silently, ten percent on your phone. If you’re much higher than that, you’re probably approving things you shouldn’t. If you’re much lower, the rules need more work.

PromptBeat’s rule engine ships with 8 templates

Pattern matching by exact / prefix / glob / regex, priorities, rate limits, and ReDoS-safe regex execution. Auto-resolved requests never broadcast.

Get the app

← Back to all posts

Feedback