Warum 90 GB deiner Festplatte verschwunden sind: der Dependency-State, den gelöschte Worktrees zurücklassen

Dein Laptop sagt, die Festplatte ist fast voll. Du leerst den Downloads-Ordner, prunst ein paar Docker-Images, startest neu, und zwei Wochen später sagt er dasselbe. Der eigentliche Übeltäter ist ein Verzeichnis, das du wahrscheinlich nie geöffnet hast: ~/.hermes/installs. Es taucht nie als großer Prozess auf und erscheint nie in du -sh ~/Downloads — es wächst einfach still vor sich hin.
Der Grund ist einfach, und es ist kein Bug. Jedes Mal, wenn du den Agent in einem hermes -w-Worktree, einem Review-Tree oder einem Scratch-Clone bootest, bereitet Hermes eine dedizierte Dependency-Umgebung für diesen Checkout vor — eine Python-Umgebung, eine Test-Umgebung, die PM-Runtime, grob 200 MB pro Tree. Wenn der Tree verschwindet, verschwindet diese Umgebung nicht. PR #133808, gemerged am 7. Oktober 2026, schließt diese Lücke.
Der State ist an den Pfad gekeyt
Zuerst: was das Ding eigentlich ist. Dependency-State liegt unter <hermes home>/installs/<install_key>/, wobei install_key kein Projektname ist, sondern ein Hash des Pfads:
# pm/environments.py
def install_key(project_root: Path) -> str:
canonical = str(Path(project_root).resolve())
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()[:16]
Also bekommen zwei Worktrees desselben Repositorys unterschiedliche Keys und unterschiedliche Umgebungen, weil ihre Pfade sich unterscheiden. Das ist Absicht: Der ganze Sinn eines Worktrees ist Isolation, und eine gemeinsame Dependency-Umgebung über Trees hinweg würde sie zunichtemachen.
Der Preis dafür ist, dass die Isolation eine Lebensdauer hat. git worktree remove, der Startup-Pruner, hermes worktree prune und sogar ein manuelles rm -rf auf den Tree lassen installs/<key>/ alle unberührt. Der Dependency-State existiert pro Checkout-Pfad; der Checkout ist weg, der State nicht, und nichts referenziert ihn mehr.
Die Zahlen im PR machen die Größenordnung konkret. Auf einem Entwickler-Host hielt ~/.hermes/installs nach zwei Wochen Worktree-Kampagnen 499 Einträge mit insgesamt 92 GB, von denen 402 Einträge (80 GB) einen Checkout verzeichneten, der nicht mehr existiert — 360 davon unter .worktrees/ — mit einem Median-Alter von vier Tagen. Nur 76 Einträge gehörten zu lebenden Checkouts. Mehr als vier Fünftel des Platzes war Ghost-State.
Der Fix: ein Datensatz entscheidet, was ein Waise ist
Das neue pm/install_states.py macht etwas bewusst Unspektakuläres. Jedes State-Verzeichnis, das erfolgreich synchronisiert wurde, enthält inputs/.project-root, geschrieben von record_activation_inputs, das den Checkout benennt, zu dem es gehört. Die Prüfung ist schlicht, ob dieser Pfad noch da ist.
Das Subtile daran ist, dass „nicht da“ nicht „gelöscht“ bedeutet. Ein Daten-Root, der mit einem Container geteilt wird (-v ~/.hermes:/opt/data), oder ein nicht gemountetes Volume verzeichnen ebenfalls Pfade, die der aktuelle Prozess nicht sehen kann. Das Urteil wird daher auf nachweislich gelöscht verengt: Der Checkout muss irgendwo gesessen haben, wo dieser Prozess es beobachten kann — unter dem Daten-Root, dem installs/ gehört, oder direkt in einem .worktrees/-Verzeichnis, das noch existiert. State-Verzeichnisse ohne jeglichen Datensatz werden nie angefasst.
Die Rückgewinnung ist gleichermaßen konservativ. Alles, was noch gehalten wird, bleibt:
- das
.install.lockkann nicht genommen werden (ein Prozess nutzt es); - jede Generation unter
environments/hat noch ein lebendes Lease (etwas liest sie); - ein Lock, das sich nicht einmal öffnen lässt, zählt als gehalten.
Diese Neigung ist richtig. Eine Dependency-Umgebung zu löschen, die in Benutzung ist, bricht die laufende Session; eine zu behalten, die hätte gehen sollen, kostet nur Festplatte.
So holst du es jetzt zurück
Es gibt keine Migration durchzuführen. Zwei Pfade erledigen die Arbeit automatisch:
hermes pm gc # die Ausgabe bekommt einen abschließenden Eintrag: N install state dir(s) of deleted checkouts
hermes worktree prune # holt State nach dem Branch-Durchlauf zurück, für Trees, die weg sind
Der Pruner, der bei jedem Hermes-Start läuft, tut es ebenfalls, sodass im normalen Gebrauch der State eines gelöschten Worktrees beim nächsten hermes-Start oder beim nächsten pm gc verschwindet. Die Startup-Rückgewinnung ist fail-soft — ein Fehler wird auf Debug-Level geloggt und blockiert den Start nie.
Um zuerst zu sehen, was du mit dir herumträgst:
du -sh ~/.hermes/installs # gesamt
ls ~/.hermes/installs | wc -l # Anzahl der Einträge
hermes worktree list # Alter, Größe, Urteil und Grund für jeden Tree in .worktrees/
hermes worktree list ist der sichere Pre-Flight: Es gibt vor dem Prunen ein Urteil und den Grund für jeden Tree aus. Es löscht nie uncommittete getrackte Änderungen, einzigartige ungepushte Commits oder in Benutzung befindliche Trees, und reine Untracked-Scratch-Trees werden vor dem Entfernen nach ~/.hermes/archive/worktree-prune/ archiviert.
Wie sich das von den anderen Disk-Stories unterscheidet
Wir haben hier einige festplattenbezogene Probleme behandelt, und die Mechanismen sind verschieden genug, dass man sie auseinanderhalten sollte:
- ein Update, das die Festplatte sprengt dreht sich um temporäre Artefakte während
hermes update; - der Datenverlust durch einen dirty Worktree dreht sich um einen Pruner, der Trees löschte, die er hätte behalten sollen;
- dieser hier geht in die entgegengesetzte Richtung: etwas, das hätte gelöscht werden sollen, wurde nicht gelöscht. Das Cleanup erreichte den Tree, aber nicht den Dependency-State, den der Tree zurückließ.
Die ersten beiden sind Guardrail-Bugs; dieser ist eine Abdeckungslücke. Zusammen ergeben sie das Bild auf der Dependency-Seite, und Speicher auf 78 % seiner früheren Größe zu senken deckt die Datenseite ab — Sessions und Caches —, wenn du beide Hälften willst.
Die Kurzfassung
~/.hermes/installs/speichert Dependency-State, gekeyt nach dem Hash des Checkout-Pfads, eine rund 200 MB große Umgebung pro Worktree oder Scratch-Clone;- das Löschen des Trees löschte diesen State nie — nicht
pm gc, nicht Worktree-Prune, nichtrm -rf; - jetzt holen
hermes pm gc,hermes worktree pruneund der Startup-Pruner allen State zurück, dessen Checkout nachweislich gelöscht ist, und lassen alles hinter einem gehaltenen Lock oder Lease in Ruhe; - auf einem Host gemessen: 499 Einträge bei 92 GB, 402 davon Waisen (80 GB), 92 GB runter auf 18 GB nach der Rückgewinnung.
Wenn du regelmäßig Worktrees öffnest oder Wegwerf-Clones hochziehst, führe heute einmal du -sh ~/.hermes/installs aus. Ist die Zahl größer als erwartet, ist hermes pm gc die ganze Antwort.