Agent deleted user's main project repo via gh repo fork --fork-name rename behavior
Summary
Claude Code (Opus 4.7) deleted my main project GitHub repository (CryptoJones/GayHydra — a years-of-work fork of NSA/ghidra with 377 issues/PRs, 50+ releases, all my GitHub Actions history) by misinterpreting gh repo fork's fork-rename behavior, then running gh api repos/<repo> --method DELETE on what it believed was a duplicate fork. The "duplicate" was the original under a renamed alias.
Recovery via GitHub's 90-day Settings → Repositories → "Deleted repositories" → Restore UI is in progress as I write this, but the entire 5+ minutes between "fuck where's my repo" and "found the restore button" was avoidable. The agent had no guardrail stopping it from executing a destructive operation on a repo it didn't create in the current session.
Reproduction (conceptual)
Steps the agent took:
- Wanted to file upstream PRs to
NationalSecurityAgency/ghidra. I (the user) own a fork atCryptoJones/GayHydra(the Ghidra fork lives under a rebranded name). - Ran
gh repo fork NationalSecurityAgency/ghidra --fork-name=ghidra-nsa --clone=false --remote=false. - GitHub's API response:
"full_name": "CryptoJones/ghidra-nsa","parent": "NationalSecurityAgency/ghidra". The earlier "already exists" warning was aboutCryptoJones/GayHydra, but the API also returned this new-looking entry. - What actually happened on GitHub's side: A user can only own one fork of a given upstream. The
--fork-nameflag renamed my existingCryptoJones/GayHydratoCryptoJones/ghidra-nsa. There was no new repo. My main project just had a new name. - Agent interpreted the API response as "new sibling fork created", noted it was a "broken/duplicate fork", and ran
gh api repos/CryptoJones/ghidra-nsa --method DELETEto clean up. - That delete removed the original GayHydra (now renamed ghidra-nsa). Everything went with it.
Why this is a Claude Code (agent) problem, not just a user-script bug
A human running gh CLI interactively would have noticed:
- The
--fork-nameflag's behavior is documented but counterintuitive when a fork already exists; a human would have stopped to verify - A human would notice that
gh repo view CryptoJones/ghidra-nsa --json parentreturns the right parent but the content (gh repo clone+git log) shows their own fork's history, not upstream's
The agent flew past both signals. It saw:
- "creating duplicate fork" → "I should clean it up"
- API DELETE call → "✅ removed"
There's no built-in friction on gh api .../DELETE. The agent's self-instructions about "carefully consider blast radius before destructive actions" don't kick in because the agent didn't classify a single DELETE API call as destructive — it was "cleanup."
Suggested mitigations
- Treat
gh api .../--method DELETEandgh repo deleteas in the "always confirm with user" bucket, same tier asgit push --forceto main. The agent should never call these on a repo it didn't create in the current session without explicit user-typed confirmation containing the repo name. - Document the
gh repo fork --fork-namerename behavior in Claude Code's gh-CLI guidance, or detect the rename pattern (response includesfull_namedifferent from the requested upstream + a parent matching the upstream + the warning "X already exists"). - A "tools the agent shouldn't compose freely" allowlist for gh-CLI subcommands. Read operations are fine; mutating + destructive operations especially on shared state should require an extra layer.
Concrete user impact
- 5+ minutes of acute panic ("where's my main project")
- Full recovery requires UI step the user has to take (no API for
repos/.../restore) - Code is recoverable from local clone + Codeberg mirror, but 377 issues/PRs, all comments, all release-page metadata, all stars/watchers — only recoverable via Restore UI within 90 days
- The "blast radius" of one
DELETEwas years of project history
Versions
- Claude Code via the standard CLI
- Model: Opus 4.7 (
claude-opus-4-7) ghCLI: GitHub-hosted version (no special version)
What the agent saved to its own memory afterward
NEVER call `gh repo delete` or `gh api repos/.../<--method DELETE>` on any
user-owned repo without an explicit user message containing the literal repo
name and the word "delete".
That's the user's instance-local Claude memory, not a Claude Code default. It needs to be a default, not an opt-in lesson each Claude learns by destroying something first.
This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗