Nestor G Pestelos Jr · Writing · Print

Your Agent's Plan B Will Destroy Your Data

Published March 25, 2026. Revised September 3, 2026.

TL;DR

An AI agent's locally rational escalation, git stash --include-untracked to unblock a pull, permanently destroyed 24 untracked files. A written rule in markdown was not enough. Only a PreToolUse hook that mechanically blocks the command prevents data loss.


The March 25, 2026 version is at agents-plan-b-destroy-data-20260325.

Twenty-four files disappeared from my working tree on a Tuesday afternoon without error or warning. I asked Claude Code to commit pending changes in my knowledge vault. Five git commands later, three days of conversation backups and an irreplaceable research note were gone.

The root cause was not a software defect. It was an autonomous coding agent executing a locally rational sequence that proved fatal to data. Claude had full context on my vault conventions through instruction files, and committing changes was a daily routine.

What was in the working tree

The working tree held three groups of uncommitted files:

Total: 29 files, 24 never committed to git.

The cascade

My instruction file requires running git pull --rebase before every commit to prevent remote divergence. Claude followed that rule.

Step 1: The rebase fails.

error: cannot pull with rebase: You have unstaged changes.

The five modified Readwise files blocked the rebase.

Step 2: Claude attempts a standard stash.

Claude chose a standard git pattern: stash changes, pull, and pop. Because git stash captures tracked files, it created an entry, yet unstaged index states left modified files in the tree.

**Step 3: Claude escalates to --include-untracked.**

Because the working tree remained dirty, Claude escalated to git stash --include-untracked. This swept every untracked file into the stash. All 24 untracked files vanished from disk.

Step 4: The pull still fails.

Modified files still remained in the tree. The pull remained blocked, and two separate stashes now held copies of the data.

Step 5: Claude drops both stashes.

git stash drop stash@{1} && git stash drop stash@{0}

This command permanently destroyed the data. Dropping a stash purges unreferenced objects during garbage collection. Committed versions of tracked files remain safe in the repository database. Untracked files captured by --include-untracked have no prior commit. Dropping the stash deletes the only copy in existence.

Twenty-four files vanished permanently. No recovery path, no git reflog, and no undo.

The unnecessary escalation

**Untracked files never block git pull --rebase.**

Only unstaged modifications to tracked files block a rebase. The 24 untracked files would have survived endless pulls. Claude stashed them because --include-untracked was the next escalation in its playbook. It resolved a phantom problem and destroyed real data.

Policy versus mechanism

A written rule in markdown is insufficient; agents overlook instructions when problem-solving. My configuration already prohibited destroying user documents, yet Claude violated the principle through an unexpected side effect.

Layer 1: The policy rule

I added a strict directive to CLAUDE.md under Safety & Permissions:

> Never use git stash --include-untracked or git stash -u. Untracked files in a stash are permanently destroyed on drop or failed pop. If tracked files block rebase, commit them first. Untracked files never block pull or rebase. Leave them alone.

Layer 2: The enforcement hook

Policy informs; mechanisms enforce. I created a PreToolUse hook that intercepts shell tool calls before execution and matches against destructive patterns:

#!/usr/bin/env bash
set -euo pipefail

INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // ""')

if [ "$TOOL_NAME" != "Bash" ]; then
  exit 0
fi

COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

if echo "$COMMAND" | grep -qE 'git\s+stash\s+.*(-u\b|--include-untracked)'; then
  echo "BLOCKED: git stash --include-untracked / -u destroys untracked files irreversibly." >&2
  exit 2
fi

exit 0

Exit code 2 forces Claude Code to abort the tool call. Whether the model forgets the rule, misreads index state, or insists stashing is appropriate, the shell hook blocks execution. Policy states what to avoid; mechanism makes violations impossible.

Three failure modes of agent escalation

Agents become dangerous when trying to be helpful. This incident involved no hallucination. Claude recognized that git pull --rebase required a clean working tree, and that git stash temporarily shelves modifications. It escalated to --include-untracked only when the simpler command failed. Every step was locally rational; the cascade was catastrophic.

This reveals three hazards in autonomous workflows:

  1. Uncalibrated escalation: Plan B expands blast radius without verifying necessity.
  2. Silent destruction: Files vanished without error codes. Because the command succeeded, the agent assumed safety.
  3. Irreversibility blindness: Models struggle to separate reversible from irreversible operations. Shelving tracked files is reversible; dropping untracked files is permanent.

Human vigilance cannot govern autonomous execution. Build mechanical safeguards: pre-execution tool hooks, shell wrappers, and restricted execution profiles. Written rules are guidance. Executable hooks are boundaries. The gap between a file on disk and a commit in git is where data dies.

Back to top