2026-02-06 · Authensor

How to Prevent AI Agents from Force Pushing to Git

To prevent AI agents from running git push --force and destroying your repository history, use SafeClaw action-level gating to block destructive git commands. SafeClaw intercepts shell_exec actions matching --force, --force-with-lease, reset --hard, and branch -D before execution. Install with npx @authensor/safeclaw.

The Risk

git push --force overwrites the remote repository's commit history with whatever the local branch has. If the agent's local branch is behind, divergent, or corrupted, force push replaces the real history with the broken one. Every developer who has already pulled the original commits now has a broken reference. Ongoing pull requests break. CI pipelines fail. If nobody has a local copy of the overwritten commits, that work is permanently gone.

git reset --hard is equally dangerous locally — it discards all uncommitted changes and resets to a previous commit. No confirmation, no undo. Combined with a force push, an agent can erase work both locally and remotely in two commands.

AI coding agents generate git commands frequently. "Push my changes" can become git push --force if the agent detects a conflict and decides to resolve it the fast way. "Clean up the branch" can become git reset --hard HEAD~5. These aren't bugs in the agent — they're reasonable interpretations of ambiguous instructions that happen to be destructive.

Git branch protection rules on GitHub/GitLab help for protected branches, but they don't cover all branches, don't prevent local destruction, and don't stop git reset --hard from wiping uncommitted work.

The One-Minute Fix

Step 1: Install SafeClaw.

npx @authensor/safeclaw

Step 2: Get your free API key at safeclaw.onrender.com (7-day renewable, no credit card).

Step 3: Add this policy rule:

- action: shell_exec
  pattern: "git push.--force|git push.-f|git reset --hard|git branch -D|git clean -f"
  effect: deny
  reason: "Destructive git operations blocked"

Done. The agent can still commit, push, pull, and branch — just not destroy history.

Full Policy

name: block-destructive-git
version: "1.0"
defaultEffect: deny
rules:
  # Block force push (all variants)
  - action: shell_exec
    pattern: "git push.*(-f|--force|--force-with-lease)"
    effect: deny
    reason: "Force push blocked — use normal push"

# Block hard reset
- action: shell_exec
pattern: "git reset --hard"
effect: deny
reason: "Hard reset blocked — use soft reset or stash"

# Block force branch deletion
- action: shell_exec
pattern: "git branch\\s+(-D|--force.-d|-d.--force)"
effect: deny
reason: "Force branch deletion blocked"

# Block git clean with force
- action: shell_exec
pattern: "git clean\\s+(-f|--force)"
effect: deny
reason: "Force clean blocked — untracked file deletion prevented"

# Block checkout that discards changes
- action: shell_exec
pattern: "git checkout\\s+--\\s+\\."
effect: deny
reason: "Bulk discard of changes blocked"

# Allow safe git operations
- action: shell_exec
pattern: "git (status|diff|log|add|commit|push(?!.--force)|pull|fetch|branch(?!.-D)|checkout(?!.*-- \\.)| stash|merge|rebase)"
effect: allow
reason: "Non-destructive git operations permitted"

What Gets Blocked

These action requests are DENIED:

{
  "action": "shell_exec",
  "command": "git push origin main --force",
  "agent": "code-assistant",
  "result": "DENIED — Force push blocked — use normal push"
}
{
  "action": "shell_exec",
  "command": "git reset --hard HEAD~3",
  "agent": "refactor-agent",
  "result": "DENIED — Hard reset blocked — use soft reset or stash"
}
{
  "action": "shell_exec",
  "command": "git branch -D feature/important-work",
  "agent": "cleanup-bot",
  "result": "DENIED — Force branch deletion blocked"
}

What Still Works

These safe actions are ALLOWED:

{
  "action": "shell_exec",
  "command": "git push origin feature/my-branch",
  "agent": "code-assistant",
  "result": "ALLOWED — Non-destructive git operations permitted"
}
{
  "action": "shell_exec",
  "command": "git commit -m 'fix: resolve null pointer in auth module'",
  "agent": "code-assistant",
  "result": "ALLOWED — Non-destructive git operations permitted"
}

Your agent can still do all normal git work — staging, committing, pushing, pulling, branching. It just can't rewrite or destroy history.

Why Other Approaches Don't Work

Git branch protection rules (GitHub, GitLab) protect specific branches on the remote, but the agent can still force push to unprotected branches, and they do nothing about git reset --hard locally wiping your uncommitted work.

Git hooks (pre-push) can block force push, but agents with shell access can bypass hooks with --no-verify. Hooks are also per-repository — you'd need to install them in every repo.

Prompt instructions ("never force push") are not enforceable. The agent may decide force push is necessary to resolve a conflict, or a prompt injection can override the instruction entirely.

SafeClaw evaluates every shell_exec action against pattern rules in sub-millisecond time, before the command runs. It cannot be bypassed from the prompt layer. Deny-by-default means unknown git flags are blocked. Every denied action is logged with a tamper-proof audit trail (SHA-256 hash chain). Built with 446 tests, TypeScript strict mode, zero third-party dependencies. The client is 100% open source under MIT license.

Cross-References

Try SafeClaw

Action-level gating for AI agents. Set it up in your browser in 60 seconds.

$ npx @authensor/safeclaw