Leitfäden

Claude Code hat meine Dateien gelöscht? Die Schicht, die es stoppt

Ein Löschschutz für Claude Code besteht aus vier Schichten, die verhindern, dass ein Agent Ihre Dateien löscht: einer Bestätigungsabfrage, einer Deny-Regel, einem PreToolUse-Hook und Arbeit, die committet und gepusht ist. ConvOps ergänzt isolierte Läufe und eine Freigabe vor dem Merge für die Läufe, die niemand beobachtet.

DM

David Marsa

Founder & CEO

Einsteiger30 Min. LesezeitVeröffentlicht am 09.10.2026

Zuletzt geprüft am 09.10.2026

Behandelte Tools und Modelle:Claude CodeOpenCodeKimi K3
Eine Datei fällt auf einen Aktenvernichter zu, vorbei an vier Wächtern: einer Abfrage mit erhobener Hand, die unbeaufsichtigte Läufe überspringen, einem Deny-Gitter, einem Hook-Sensortor und einer Ablage mit der gepushten Kopie.

Das können Sie danach

  • Wissen, was nach einer Löschung zurückkommt (committete Arbeit, archivierte Dateien) und was nicht.
  • Einen Deny-Block in die Einstellungen von Claude Code einfügen und wissen, welche Löschformen er übersieht.
  • Einen PreToolUse-Hook schreiben, der Löschungen blockiert und dem Agenten sagt, was er stattdessen tun soll, und ihn mit Beispiel-JSON testen.
  • Entscheiden, welche Schichten Ihre unbeaufsichtigten Läufe schützen, da diese Abfragen überspringen.
  • Dasselbe Schutzprinzip in OpenCode und Kimi Code CLI anwenden.

Das Wichtigste

  • Damit Claude Code Ihre Dateien nicht löscht, blockieren Sie Löschbefehle mit einer Deny-Regel und einem PreToolUse-Hook, und committen und pushen Sie, damit eine übersehene Löschung einen Rückweg hat.
  • In unseren Testläufen unter --dangerously-skip-permissions blockierten eine Deny-Regel und ein PreToolUse-Hook in Claude Code jeweils rm; Bestätigungsabfragen erscheinen in unbeaufsichtigten Läufen nie.
  • Deny-Regeln prüfen den Befehlstext, deshalb kamen find -delete, /bin/rm und ein Python-Einzeiler an ihnen vorbei; unser Hook fing die ersten beiden ab und übersah den dritten, weil ein Hook nur blockiert, was seine Muster benennen.
  • Eine Blockademeldung, die die sichere Alternative nennt (in den Ordner _archive/ des Projekts verschieben), hält den Agenten davon ab, um die Blockade herum zu improvisieren.
  • Ein Hook, der Text abgleicht, blockiert auch harmlose Befehle; testen Sie ihn mit Fixtures und nehmen Sie den Fehlalarm lieber in Kauf als eine übersehene Löschung.

Wenn Claude Code Ihre Dateien gelöscht hat, kommt nur zurück, was noch an einem anderen Ort existiert. Damit Claude Code nicht wieder Dateien löscht, pushen Sie Ihre Arbeit und richten dann eine Deny-Regel und einen Hook ein. Diese Anleitung baut jede Schicht für Claude Code in etwa 30 Minuten auf und zeigt, was jede einzelne übersieht.

Wir betreiben einen Löschschutz in jeder Claude-Code-Session in unserem eigenen Repository. Die Beispiele nutzen Marrowby Tiles, einen erfundenen Fliesenhändler; die Regeln und Muster entsprechen unseren.

Claude Code hat Dateien gelöscht: Was zurückkommt

Der Rückweg entsteht vor dem Löschen, nie danach.

Kommt zurückBleibt weg
Committete Dateien (lokal oder gepusht); nur gepushte Commits überstehen einen verlorenen oder geleerten OrdnerNicht committete Dateien, die rm, find -delete oder ein Skript entfernt hat
Dateien, die ein Hook nach _archive/ umgeleitet hat, statt sie zu löschenNicht committete Änderungen, die git checkout --, git reset --hard oder git restore verworfen hat

Gerade Dateien verloren? Gehen Sie in dieser Reihenfolge vor:

  1. Sehen Sie im Ordner _archive/ des Projekts nach.
  2. Führen Sie git status aus, um fehlende versionierte Dateien aufzulisten.
  3. Committet, aber nicht gepusht? git restore --source=HEAD --staged --worktree <path> holt die Datei aus Ihrem letzten lokalen Commit zurück.
  4. Führen Sie git fetch und dann git restore --source=origin/main <path> aus, um eine Datei im zuletzt gepushten Stand zurückzuholen (setzen Sie den Namen Ihres Branches ein).
  5. Hat ein Commit die Datei entfernt, nennt git log --diff-filter=D -- <path> diesen Commit.

Was diese Schritte nicht finden, ist von der Festplatte verschwunden.

Warum Claude Code Dateien löscht

Eine Rückfrage schützt die Person an der Tastatur. Für einen Lauf um 3 Uhr nachts tut sie nichts.

Agenten löschen aus ganz gewöhnlichen Gründen: Bittet man Claude Code, „neu anzufangen“, leert es zuerst den Ordner, und in unserem Test in einem Wegwerfordner wählte es von sich aus find -delete. Auch Git löscht: git reset --hard, git clean, git restore, git checkout -- und git stash drop verwerfen nicht committete Arbeit, und ein einfaches git stash versteckt sie, bis Sie sie mit git stash pop zurückholen.

Die Bestätigungsabfrage ist die schwächste Schicht. Menschen bestätigen, was sie nur überfliegen, und unsere geplanten Agentenläufe nutzen --dangerously-skip-permissions, sodass gar keine Abfrage erscheint.

KennzahlWertQuelle
Gefährliche Befehle, die menschliche Prüfer in einer kontrollierten Studie erkannten13,6 %Anthropic(wird in einem neuen Tab geöffnet), 2026
Gefährliche Befehle, die der Klassifikator des Auto-Modus von Claude Code in derselben Studie erkannte89 %Anthropic(wird in einem neuen Tab geöffnet), 2026
Dateien, die Claude Code bei einem Entwickler angeblich gelöscht hat48.000 in 103 SekundenTechRadar(wird in einem neuen Tab geöffnet), 2026

Sehen Sie, wie ConvOps vor jeden Merge einen Freigabeschritt setzt(wird in einem neuen Tab geöffnet), damit eine Löschung aus einem unbeaufsichtigten Lauf main nie ohne das Ja einer Person erreicht.

Welche Schicht eine Löschung wirklich stoppt

Die Deny-Liste ist eine Bremsschwelle. Der Hook ist eine Mauer mit bekannten Lücken. Gepushte Arbeit ist das Fundament.

Was ist eine Deny-Regel? Eine Deny-Regel ist eine Zeile in den Einstellungen von Claude Code, die jeden Bash-Befehl ablehnt, dessen Text auf ein Muster passt, etwa Bash(rm *).

Was ist ein PreToolUse-Hook? Ein PreToolUse-Hook ist ein Skript, das Claude Code vor einem Tool-Aufruf ausführt; endet das Skript mit Exit-Code 2, wird der Aufruf blockiert und der Agent liest die Meldung des Skripts.

Vier Schichten liegen zwischen der Löschung eines Agenten und Ihren Dateien, und nur die Bestätigungsabfrage entfällt, wenn niemand zusieht.

Eine Deny-Regel und ein Hook blockierten in unseren Testläufen jeweils für sich allein rm. Keine der beiden stoppte alles.

Jede Schicht lässt für sich allein etwas durch, eine Löschung per find -delete an der Deny-Regel vorbei und einen Python-Einzeiler am Hook vorbei, und die nächste Schicht fängt es ab.

Committen und pushen, bevor ein Agent etwas anfasst

Ungepushte Arbeit geht mit dem Ordner verloren, in dem sie liegt.

Bevor Sie Claude Code starten, sichern Sie alles auf dem Remote:

git status
git add src/ data/products.json
git commit -m "Save work before the agent run"
git push

Starten Sie den Agenten nur auf einem sauberen Arbeitsverzeichnis, das mit dem Remote auf dem aktuellen Stand ist. Unsere Workflows pushen das Ergebnis jedes Schritts, bevor sie weitergehen, und ein Stop-Hook verhindert, dass eine Session mit ungepushter Arbeit endet. Führen Sie riskante Arbeit in einem Git-Worktree aus, etwa ~/marrowby-shop-run-0412, oder in einem isolierten Lauf, der vom Remote startet.

Deny-Regeln in Claude Code anlegen

Deny-Regeln prüfen den Text eines Befehls, nicht das, was der Befehl tut.

Dieser Block gehört in die .claude/settings.json des Projekts:

{
  "permissions": {
    "deny": [
      "Bash(rm *)",
      "Bash(rmdir *)",
      "Bash(git rm *)",
      "Bash(git clean *)",
      "Bash(git reset *)",
      "Bash(git restore *)",
      "Bash(git checkout -- *)",
      "Bash(git stash drop *)",
      "Bash(git stash clear *)",
      "Bash(git push --force *)",
      "Bash(git push -f *)"
    ]
  }
}

Bash(rm *) und das ältere Bash(rm:*) verhielten sich in Version 2.1.295 gleich, auch unter --dangerously-skip-permissions. Laut Anthropics Dokumentation zu den Berechtigungsmodi(wird in einem neuen Tab geöffnet) blockieren Deny-Regeln „in jedem Modus, einschließlich bypassPermissions“, und der Auto-Modus zählt dort zu diesen Modi. Die Dokumentation zu Berechtigungen(wird in einem neuen Tab geöffnet) hält außerdem fest, dass eine Deny-Regel „keine Sicherheitsgrenze um das Programm“ ist. In unserem Lauf löschten find -delete, /bin/rm und ein python3 -c-Einzeiler jeweils die Datei; sh -c 'rm ...' wurde abgefangen.

Einen Hook einrichten, der blockiert und einen Ausweg nennt

Eine Blockade ohne Alternative bringt dem Agenten bei, Sie zu umgehen.

Die vollständige .claude/settings.json mit einem hooks-Schlüssel neben permissions (Hooks-Leitfaden(wird in einem neuen Tab geöffnet)):

{
  "permissions": {
    "deny": [
      "Bash(rm *)",
      "Bash(rmdir *)",
      "Bash(git rm *)",
      "Bash(git clean *)",
      "Bash(git reset *)",
      "Bash(git restore *)",
      "Bash(git checkout -- *)",
      "Bash(git stash drop *)",
      "Bash(git stash clear *)",
      "Bash(git push --force *)",
      "Bash(git push -f *)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3",
            "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/delete-guard.py"],
            "timeout": 5
          }
        ]
      }
    ]
  }
}

${CLAUDE_PROJECT_DIR} zeigt auf das Projektverzeichnis, sodass der Pfad auch dann stimmt, wenn der Agent den Ordner wechselt. Ein falscher Skriptpfad lässt python3 mit Exit-Code 2 enden, sodass jeder Bash-Aufruf mit dem Fehler can't open file blockiert wird. Im Fehlerfall wird also blockiert statt durchgelassen, und schon der erste Befehl zeigt es.

Und das Skript, .claude/hooks/delete-guard.py:

import json, re, sys

ARCHIVE = ("file deletion is denied, archive instead: move it to _archive/ "
           "in this project (mkdir -p _archive && mv <path> _archive/)")
PATTERNS = [
    (r"\brm\s+-rf\b", "rm -rf is irreversible recursive deletion, " + ARCHIVE),
    (r"(?<!-)\brm\b", ARCHIVE),
    (r"\brmdir\b", ARCHIVE),
    (r"\bfind\b.*\s-delete\b", ARCHIVE),
    (r"\bgit\s+checkout\s+--\s+", "git checkout -- reverts uncommitted work"),
    (r"\bgit\s+reset\b", "git reset can destroy commit history"),
    (r"\bgit\s+restore\b", "git restore reverts uncommitted work"),
    (r"\bgit\s+clean\b", "git clean deletes untracked files"),
    (r"\bgit\s+stash\b", "git stash can drop uncommitted work"),
    (r"\bgit\s+push\b.*\s(?:-f|--force)\b", "force push overwrites remote history"),
]
MESSAGE_ARG = re.compile(r"""(?:^|\s)(?:-m|--message)(?:=|\s+)(?:"[^"]*"|'[^']*'|\S+)""")

def main():
    try:
        command = json.load(sys.stdin)["tool_input"]["command"]
    except Exception:
        return 0
    scanned = MESSAGE_ARG.sub(" ", command)
    for pattern, reason in PATTERNS:
        if re.search(pattern, scanned):
            print(f"BLOCKED: Destructive command detected.\n  Reason: {reason}\n"
                  f"  Command: {command}", file=sys.stderr)
            return 2
    return 0

sys.exit(main())

Jede Zeile hat einen Grund:

  • Exit-Code 2 blockiert den Aufruf; der Agent liest stderr.
  • (?<!-)\brm\b erfasst jedes rm-Token, auch /bin/rm. Der Lookbehind lässt docker run --rm weiterhin zu.
  • Nicht lesbare Eingaben enden mit 0: So legen sie nie eine Session lahm, bleiben aber ungeprüft.
  • Kein Muster für Interpreter. Einzeiler mit os.remove und shutil.rmtree kommen durch: Der Hook blockiert nur, was seine Muster benennen.

Ein Hook läuft bei jedem Bash-Aufruf, ganz gleich, was man dem Agenten gesagt hat (Graph Engineering). Deshalb gehört eine solche Regel in einen Hook und nicht in eine CLAUDE.md, die immer weiter wächst.

Den Hook testen, bevor Sie ihm vertrauen

Ein ungetesteter regulärer Ausdruck ist eine Vermutung.

Leiten Sie eine Beispiel-Payload in das Skript:

echo '{"tool_name":"Bash","tool_input":{"command":"find exports -mindepth 1 -delete"}}' \
  | python3 .claude/hooks/delete-guard.py; echo "exit $?"

Legen Sie für jede Befehlsform eine Fixture an, auch für erwartete Lücken:

BefehlErwartet
rm -rf exports/Exit 2
git checkout -- src/Exit 2
docker run --rm alpine trueExit 0
git commit -m "Never rm -rf exports, archive instead"Exit 0
python3 -c "import os; os.remove('exports/product-feed.csv')"Exit 0, eine bekannte Lücke
git push -f origin mainExit 2
grep -rn "rm -rf" scripts/Exit 2, eine bekannte Überblockierung

Schließen Sie mit einer echten Blockade ab: Bitten Sie Claude Code in einem Wegwerfordner, eine Testdatei zu löschen.

Ein Löschversuch, Schritt für Schritt verfolgt

Die beste Blockade ist die, von der sich der Agent selbst erholt.

Der Hook blockiert die Löschung des Agenten per find -delete mit Exit-Code 2, seine Meldung nennt den Ordner _archive/ des Projekts, und der Agent verschiebt die Dateien stattdessen dorthin, sodass nichts gelöscht wird.

  1. Auslöser. Marrowby Tiles gibt den Auftrag: „Produkt-Feed-Export neu erzeugen, komplett von vorn.“ Der Agent führt find exports -mindepth 1 -delete aus (Markierung 1).
  2. Blockade. Der Hook erkennt \bfind\b.*\s-delete\b und endet mit Exit-Code 2; seine Meldung nennt _archive/ in diesem Projekt (Markierung 2).
  3. Umleitung. Der Agent führt mkdir -p _archive && mv exports/* _archive/ aus (Markierung 3).
  4. Ergebnis. 2 Elemente verschoben, 0 gelöscht: _archive/product-feed.csv und _archive/old/ (Markierung 4).

Was bei einem Löschschutz schiefgeht

Wir erklären lieber eine unnötige Blockade, als einen Ordner wiederherzustellen.

Eine reine Lesesuche nach „rm -rf“ wird blockiert, weil der Hook Text abgleicht, und diesen Fehlalarm behalten wir bewusst: Eine unnötige Blockade ist besser als eine übersehene Löschung.

Vier Fehler, auf die wir gestoßen sind, jeweils mit ihrer Regel:

  • Eine Suche wurde blockiert. Ein reines Lese-grep -rn "rm -rf" scripts/ schlug an. Regel: den Fehlalarm behalten (im Zweifel blockieren), ebenso seine Fixture.
  • Commit-Nachrichten lösten den Hook aus. „Never rm -rf exports“ wurde wie ein Befehl erkannt. Regel: -m- und --message-Argumente in Anführungszeichen vorher herausfiltern.
  • Der Archivpfad verließ das Projekt. Unsere Blockademeldung nannte einen Ordner im Wurzelverzeichnis unseres Repositorys, und ein Testagent in einem anderen Projekt verschob seine Dateien dorthin. Regel: _archive/ in diesem Projekt nennen.
  • Ein Git-Befehl vernichtete Arbeit. git checkout -- auf zwei Ordnern löschte nicht committete Arbeit. Regel: auch die Löschbefehle von Git per Deny-Regel und Hook sperren.

Wenn niemand zusieht

Rückfragen sind keine Kontrolle für unbeaufsichtigte Läufe. Gates und Isolation sind es.

Unsere unbeaufsichtigten Läufe überspringen Rückfragen absichtlich. Drei Kontrollen tragen sie:

KontrolleWas sie tutWas sie nicht tut
Deny-Regeln und der HookBlockieren in lokalen Läufen die Löschformen, die sie benennenFormen abfangen, die sie nicht benennen
Isolierter LaufFührt jeden Job in einer eigenen Umgebung aus, etwa marrowby-run, ausgehend von gepushten Commits, sodass eine Löschung Ihre Kopie nicht erreichtEinen Befehl innerhalb des Laufs stoppen
Freigabeschritt vor dem MergeEine Person gibt frei, bevor eine Änderung, auch eine Löschung, main erreichtEinen Befehl während des Laufs stoppen

Unsere Workflows halten dort für eine Freigabe an, wo das Risiko liegt (Human in the Loop), und unsere Reparaturschleife für die Website läuft in einer isolierten Umgebung.

Kopieren Sie den Deny-Block und den Hook noch heute. Führen Sie Ihre unbeaufsichtigten Agenten-Jobs dann als ConvOps-Tasks aus(wird in einem neuen Tab geöffnet), mit einem Freigabeschritt vor dem Merge und einem isolierten Lauf.

Derselbe Schutz in OpenCode und Kimi Code CLI

Ein Schutzprinzip, drei Dateien.

Wir haben diesen Schutz in Testprojekten geprüft; im Alltag läuft unser Schutz in Claude Code.

Dieselbe Löschprüfung vor der Ausführung steckt in der jeweils eigenen Datei jedes Tools: ein PreToolUse-Hook in Claude Code, ein tool.execute.before-Plugin in OpenCode und ein hooks-Eintrag in Kimi Code CLI.

OpenCode 1.18.31

In OpenCode stoppten Deny-Regeln in permission.bash zwar rm und find -delete, doch dann löschte der Agent mit einem Python-Einzeiler. Ein Plugin, .opencode/plugins/delete-guard.js, prüft jeden bash-Befehl in tool.execute.before, mit os.remove und shutil.rmtree unter seinen Mustern, und wirft eine Meldung, die _archive/ nennt. Es blockierte alle sechs Formen, die wir ausprobierten, und der Agent archivierte stattdessen. opencode run --pure überspringt Plugins, den Schutz eingeschlossen.

Kimi Code CLI 0.31.1

Kimi Code CLI (es betreibt Modelle wie Kimi K3) nimmt einen PreToolUse-Hook in ~/.kimi-code/config.toml auf:

[[hooks]]
event = "PreToolUse"
matcher = "Bash"
command = "node ~/.kimi-code/hooks/delete-guard.mjs"

Das Skript endet mit Exit-Code 2 und derselben Meldung und blockierte im yolo-Modus alle sechs Formen. Hooks stehen nur in der Benutzerkonfiguration, nie im Projekt. Die native Regel Bash(rm *) griff nie bei einem Pfad mit Schrägstrich; Bash(rm */**) greift.

Ganz gleich, welches Tool Sie verwenden, die Reihenfolge bleibt dieselbe: pushen, sperren, Hook einrichten, testen.

Schritte

  1. Arbeit committen und pushen

    Führen Sie git status aus, committen Sie alles und pushen Sie, bevor Sie Claude Code starten. Führen Sie riskante Arbeit in einem Git-Worktree oder einem isolierten Lauf aus, der vom Remote startet. Ergebnis: Nichts, was Ihnen wichtig ist, existiert nur auf Ihrer Festplatte.

  2. Deny-Regeln in Claude Code anlegen

    Fügen Sie einen permissions.deny-Block in die .claude/settings.json des Projekts ein, der rm, rmdir, git rm, git clean, git reset, git restore, git checkout auf einen Pfad, git stash drop und clear sowie Force-Push abdeckt. Ergebnis: Claude Code verweigert diese Befehle, auch unter --dangerously-skip-permissions.

  3. Einen PreToolUse-Hook einrichten, der den sicheren Weg nennt

    Speichern Sie delete-guard.py in .claude/hooks/ und binden Sie es als PreToolUse-Hook mit dem Bash-Matcher ein. Ergebnis: Ein passender Befehl endet mit Exit-Code 2, und der Agent liest eine Meldung, die ihn anweist, die Dateien nach _archive/ in diesem Projekt zu verschieben.

  4. Den Hook mit Beispiel-JSON testen

    Leiten Sie für jede Löschform eine Beispiel-Payload in das Skript und prüfen Sie den Exit-Code: 2 für Löschungen, 0 für docker run --rm und für Commit-Nachrichten. Lösen Sie dann in einem Wegwerfordner eine echte Blockade aus. Ergebnis: eine Fixture-Liste, die auch die bekannte Lücke und die bekannte Überblockierung festhält.

  5. Unbeaufsichtigte Läufe isolieren

    Führen Sie geplante Agenten-Jobs in einer isolierten Umgebung aus, die von gepushten Commits startet, mit einem Freigabeschritt vor dem Merge. Ergebnis: Eine Löschung während eines Laufs erreicht weder Ihre Kopie noch main ohne das Ja einer Person. Erstellen Sie unter https://my.convops.app/register ein kostenloses ConvOps-Konto, um sie als Tasks auszuführen.

Häufige Fragen

Was verhindert, dass Claude Code Dateien löscht?

Vier Schichten verhindern, dass Claude Code Dateien löscht: eine Bestätigungsabfrage, eine Deny-Regel in .claude/settings.json, ein PreToolUse-Hook, der jeden Bash-Aufruf prüft, und ein Rückweg aus committeter, gepushter Arbeit und isolierten Läufen. Nur die letzten drei wirken in unbeaufsichtigten Läufen, die Abfragen überspringen. Eine Deny-Regel prüft den Befehlstext, deshalb kommen find mit -delete und /bin/rm an ihr vorbei, und ein Hook blockiert nur die Muster, die er benennt.

Wer muss verhindern, dass Claude Code Dateien löscht?

Entwickler und Teams, die Claude Code auf echten Repositories einsetzen, brauchen einen Löschschutz, vor allem wenn Agenten-Jobs unbeaufsichtigt oder nach Zeitplan laufen. Das Ergebnis: Eine Löschung wird blockiert, oder die Arbeit existiert weiterhin auf dem Remote. ConvOps führt solche Jobs als Tasks mit einem isolierten Lauf und einem Freigabeschritt vor dem Merge aus, sodass eine Löschung während eines Laufs weder Ihre lokale Kopie noch main ohne das Ja einer Person erreicht.

Hat Claude Dateien gelöscht?

Um festzustellen, ob Claude Code Dateien gelöscht hat, prüfen Sie die Bash-Aufrufe der Session auf Löschformen: rm, rmdir, find mit -delete, git checkout auf einen Pfad, git reset --hard, git clean oder einen python3 -c-Einzeiler. Führen Sie dann git status aus, um zu sehen, welche versionierten Dateien fehlen. Eine Datei, die ein Bash-Befehl entfernt hat, ist von der Festplatte verschwunden, sofern sie nicht committet war (gepusht oder lokal) oder ein Hook sie stattdessen in einen Ordner _archive/ verschoben hat.

Wie verhindere ich, dass Claude Dateien löscht?

Committen und pushen Sie Ihre Arbeit, bevor Claude Code startet. Fügen Sie dann Deny-Regeln für rm, rmdir und destruktive Git-Befehle in .claude/settings.json ein, richten Sie einen PreToolUse-Hook ein, der mit Exit-Code 2 endet und den Agenten anweist, Dateien stattdessen nach _archive/ zu verschieben, und testen Sie den Hook, indem Sie Beispiel-JSON in ihn leiten. Führen Sie unbeaufsichtigte Jobs schließlich in isolierten Läufen aus. Deny-Regeln prüfen nur den Befehlstext, deshalb decken der Hook und gepushte Arbeit ab, was sie übersehen.

Warum hat Claude meine Projekte gelöscht?

Claude Code löscht Dateien, wenn eine Aufgabe nach Zurücksetzen klingt: Bittet man es, neu anzufangen, leert es zuerst den Ordner, und in unserem Test wählte es von sich aus find mit -delete. Git-Befehle, die Arbeit zurücksetzen, etwa git checkout auf einen Pfad, git reset --hard oder git clean, löschen ebenfalls nicht committete Änderungen. Ohne Deny-Regel oder Hook steht nichts zwischen dem Befehl und der Festplatte.

Kann Claude gelöschte Dateien wiederherstellen?

Claude Code holt nur zurück, was außerhalb der Arbeitsdateien existiert: Commits, lokal oder gepusht (nur gepushte überstehen einen verlorenen oder geleerten Ordner), und Dateien, die ein Hook in einen Ordner _archive/ umgeleitet hat, statt sie zu löschen. Nicht committete Arbeit, die ein Bash-Löschbefehl oder ein Git-Zurücksetzen entfernt hat, bleibt verloren. Isolierte Läufe in ConvOps starten von gepushten Commits in einer eigenen Umgebung, sodass eine Löschung darin Ihre lokale Kopie nicht erreichen kann.

Wirken Deny-Regeln auch im bypassPermissions-Modus?

Ja. In unseren Testläufen mit Claude Code 2.1.295 und --dangerously-skip-permissions blockierte die Deny-Regel Bash(rm *) den Befehl rm, und ein PreToolUse-Hook mit Exit-Code 2 blockierte ihn ebenfalls, was zu Anthropics Dokumentation der Berechtigungsmodi passt. Die Einschränkung: Dieselbe Deny-Regel ließ find mit -delete, /bin/rm und einen Python-Einzeiler die Datei löschen, weil Deny-Regeln den Befehlstext prüfen, nicht das, was ein Befehl tut.