Der Stand lag ueber eine Bestandsaufnahme, drei Konzeptpapiere, vier Umsetzungsplaene und zwei Deploymentcenter-Dokumente verteilt - jedes mit eigener Reihenfolge, teils widersprueglich. Alle offenen Punkte daraus sind in docs/Roadmap.md zusammengefuehrt. Aufbau der neuen Roadmap - Statusvokabular: erledigt / beschlossen-offen / Entscheidung noetig / zurueckgestellt / Idee. Damit steht das Geparkte sichtbar drin, statt in einem Konzeptpapier zu verschwinden. - Herkunft-Spalte traegt das alte Kuerzel (S4, K2, B9, T4, F-A1, C1, DC1), damit die archivierten Papiere auffindbar bleiben, ohne sie zu lesen. - Abschnitt 1 Reihenfolge, 2 offene Entscheidungen, 3 die Vorhaben nach Bereich, 4 Ideenspeicher, 5 Chronik des Erledigten, 6 Modell-Einstufung, 7 Herkunftskarte. Was dabei sichtbar wurde - Neun Entscheidungen blockieren Arbeit, ohne dass sie Aufwand kosten - allen voran Matrix oder Rocket.Chat. Sie stehen jetzt gesammelt in Abschnitt 2 statt verstreut in den Diskussionsteilen der Konzepte. - B8 (keine Tiefenbegrenzung bei AgentComm) ist unveraendert offen. Das ist keine Theorie: A haelt sein Gate, waehrend es auf B wartet - ruft B nun A, warten beide bis zum Timeout. Der Testfall A13 dafuer fehlt bis heute. - Die vier Umsetzungsplaene vom 2026-08-05 sind alle unumgesetzt und waren in keiner Roadmap verzeichnet. Archiv Sechs Dokumente ziehen nach docs/archiv/: Bestandsaufnahme, Konzepte Backup/Finanz/Analyse, Linux-Portierung-Analyse, Lizenz-HardwareId-v2 (gegenstandslos - LicenseLabrador ist ersetzt), Deploymentcenter-Review und der 2.4-Integrationsplan. Sie bleiben als Begruendung lesbar, werden aber nicht mehr fortgeschrieben; das README ordnet jedes einzeln ein und warnt, dass ihre Quelltext-Verweise ins Leere gehen koennen. Bauplan bleibt Bauplan Taskboard, Audit, Staging, Memory, Agentenkommunikation, RocketChat und Deploymentcenter-Integration bleiben in docs/ - sie sind die Detailvorgabe fuer die Umsetzung, nicht Vorhabenlisten. Jedes bekommt oben eine Zeile, die seine Rolle und den Umsetzungsstand nennt und auf die Roadmap zeigt. Dasselbe fuer die vier Umsetzungsplaene: die Reihenfolge gilt in der Roadmap, nicht im Plan. Nebenbei repariert: Taskboard-Konzept und Teststrategie verwiesen auf AgentScheduler und ToolJobScheduler, die seit der Scanner-Konsolidierung geloescht sind. Alle Dokument-Verweise in docs/ sind geprueft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9.1 KiB
Umsetzungsplan: FileRW-Papierkorb + Cleanup-Job
Stand 2026-08-23: beschlossen, noch nicht gebaut. Eingeordnet als Punkt 3 der Roadmap — die Reihenfolge gilt dort, dieses Dokument ist der Bauplan.
Stand: 2026-08-05 Ziel:
FileRW.deletelöscht nicht mehr endgültig, sondern verschiebt in einen Papierkorb je Workspace. Ein Cron-Job räumt den Papierkorb nach X Tagen auf. Reihenfolge: Zuerst umsetzen — kleinster Eingriff, entschärft ein reales Risiko und ist Voraussetzung dafür,FileRW.deleteim Staging vonApproveaufAutoherunterzustufen (siehe Abschnitt 6).
1. Ausgangslage
HandleDeleteAsync in src/ClawdDotNet.Tools.FileRW/FileRWTool.cs:318 löscht
sofort und endgültig:
if (File.Exists(path)) { File.Delete(path); ... }
else if (Directory.Exists(path)) { Directory.Delete(path, true); ... }
Ein einziger Tool-Call mit path: "." räumt damit den kompletten Workspace
eines Agenten ab — ohne Rückweg. Gleichzeitig fehlt dem Agenten jede Möglichkeit,
gefahrlos aufzuräumen: Jede Aufräumaktion ist irreversibel.
Vorhandene Schutzmechanismen, die erhalten bleiben müssen:
| Mechanismus | Ort | Verhalten |
|---|---|---|
| Workspace-Einsperrung | WorkspacePath.Resolve |
absolute Pfade, .., ADS (:) verboten |
| Zugriffsstufen | IsActionAllowed |
delete im Shared nur bei sharedAccessLevel = Admin |
| Geschützte Pfade | IsPathProtected |
protectedPaths sind append-only, kein Löschen |
| Datei-Locks | GetFileLock |
pro Pfad ein SemaphoreSlim |
2. Zielverhalten
delete → verschiebt nach .trash/<yyyyMMdd_HHmmss>/<originalpfad>
list_trash → listet Papierkorb-Einträge mit Originalpfad und Löschzeitpunkt
restore → holt einen Eintrag an seinen Originalpfad zurück
purge → löscht endgültig (nur Admin, ausdrücklicher Opt-in)
Papierkorb-Layout (im jeweiligen Workspace-Root):
.trash/
├── 20260805_142233/
│ ├── _meta.json ← Originalpfad, Zeitpunkt, Agent, Typ
│ └── notizen.md ← der gelöschte Inhalt (Datei oder Verzeichnis)
└── 20260805_151002/
├── _meta.json
└── alte-recherche/
_meta.json:
{
"originalPath": "recherche/notizen.md",
"workspace": "personal",
"deletedAt": "2026-08-05T14:22:33Z",
"deletedBy": "senior_developer",
"type": "file"
}
Der Zeitstempel ist der Ordnername — damit braucht der Cleanup-Job keine
Metadatei zu lesen, um das Alter zu bestimmen (_meta.json ist Komfort,
keine Voraussetzung). Bei Kollision wird _1, _2 … angehängt, analog
HandleStockAddAsync.
3. Sicherheitsanforderungen
Diese Punkte sind nicht optional — ohne sie öffnet der Papierkorb neue Lücken:
-
.trashist für alle direkten Aktionen gesperrt.read,write,append,delete,copymit einem Pfad in.trash/werden abgelehnt. Sonst wäre der Papierkorb ein Ablageort, über den die Endungsprüfung (personalAllowedExtensions) umgangen werden kann: eine.exe„löschen" und aus dem Papierkorb an beliebiger Stelle wieder herausholen. Zugriff ausschließlich überlist_trash/restore/purge. -
listblendet.trashaus. Sonst verschmutzt der Papierkorb jede Verzeichnisauflistung und damit den Kontext des Agenten. -
Geschützte Pfade bleiben unantastbar. Die bestehende Prüfung in
HandleDeleteAsyncgreift vor dem Verschieben — einprotectedPathwandert auch nicht in den Papierkorb. -
restoreprüft das Ziel erneut vollständig:WorkspacePath.Resolveauf den Originalpfad, Endungsprüfung,IsPathProtected,IsActionAllowed. Der Originalpfad aus_meta.jsonist Eingabedatum, keine Wahrheit — eine manipulierte Metadatei darf keinen Ausbruch ermöglichen. -
Shared Workspace: ein Papierkorb je Agent —
.trash/<agentId>/<zeitstempel>/. Sonst sieht und restauriert Agent A die gelöschten Dateien von Agent B, undpurgeeines Agenten trifft alle. Im Personal Workspace entfällt die Ebene (dort ist nur ein Agent). -
purgenur beisharedAccessLevel = Admin(Shared) bzw. explizit im Personal Workspace. Der Regelweg zum endgültigen Löschen ist der Cleanup-Job, nicht der Agent. -
Kein Verschieben über Laufwerksgrenzen annehmen.
Directory.Movescheitert, wenn Workspace und.trashauf verschiedenen Volumes lägen — das ist per Konstruktion nicht der Fall (.trashliegt im Workspace-Root), aber der Fehlerfall wird sauber gemeldet statt zu einer Teilkopie zu führen.
4. Cleanup-Job
FileRWTool implementiert zusätzlich IToolJobProvider
(src/ClawdDotNet.Core/Tools/IToolJobProvider.cs). Die Infrastruktur ist
vollständig vorhanden — ToolJobScheduler kennt Cron, RunOnStart und
manuelles Auslösen; es braucht keinen neuen Scheduler.
public IReadOnlyList<ToolJobDefinition> GetJobDefinitions() =>
[
new("filerw_trash_cleanup", "Papierkorb aufräumen",
"Löscht Papierkorb-Einträge, die älter als retentionDays sind")
];
ExecuteJobAsync bekommt workspacePath und agentId bereits übergeben
(siehe Signatur des Interfaces). Der Job:
- liest
retentionDaysaustoolConfig(Default 14, Minimum 1), - durchläuft
.trash/*in Personal- und Shared-Workspace, - löscht Ordner, deren Zeitstempel älter als die Aufbewahrungsfrist ist,
- gibt immer
ToolJobResult.NoAction(logSummary)zurück — der Agent wird nie geweckt. Aufräumen ist kein Ereignis, das ein LLM-Run wert wäre (und kein Token kosten soll).
Der Shared-Papierkorb wird nur bereinigt, wenn der Job-Agent dort Admin-Rechte hat; andernfalls nur der eigene Unterordner. Damit räumt nicht jeder Agent bei jedem Tick fremde Einträge ab.
Beispielkonfiguration im Agenten:
"toolJobs": [
{
"jobId": "trash-daily",
"toolName": "FileRW",
"jobTypeId": "filerw_trash_cleanup",
"cron": "0 3 * * *",
"enabled": true,
"runOnStart": false
}
]
Achtung Zeitzone: ToolJobScheduler.RunToolJobAsync rechnet mit
DateTime.Now (lokal), die Papierkorb-Zeitstempel oben sind UTC. Das
Altersvergleich im Job daher konsequent in UTC durchführen
(DateTime.UtcNow), nicht mischen. Dieselbe Falle ist bereits aus der
Watchdog-Integration bekannt.
5. Umsetzungsschritte
Slice 1 — Papierkorb im Tool (Kern)
TrashPath-Helfer analogWorkspacePath: baut und validiert.trash-Pfade, kapselt die Agent-Ebene im Shared WorkspaceHandleDeleteAsyncauf Verschieben umstellen (Datei und Verzeichnis).trash-Sperre inGetAndValidatePath(greift für alle direkten Aktionen).trashausHandleListAsyncfiltern_meta.jsonschreiben (überAtomicFile, wie beim Stock-Index)- Tests:
tests/ClawdDotNet.Tools.Tests/FileRW/TrashTests.cs
Slice 2 — list_trash / restore / purge
- Drei Aktionen im
InputSchemaund imswitchergänzen restoremit vollständiger Zielprüfung (siehe 3.4)purgemit Admin-PrüfungDescriptiondes Tools ergänzen, damit das LLM den Papierkorb kennt- Tests: Restore an geschützten Pfad, Restore mit manipulierter
_meta.json, Restore mit inzwischen belegtem Zielpfad
Slice 3 — Cleanup-Job
IToolJobProvideranFileRWToolretentionDaysinFileRWToolSettings(Models/ToolSettingsViewModels.cs:68) + Designer-Property- Job-Definition in der UI auswählbar (läuft über die bestehende Job-Verwaltung, kein neuer Dialog)
- Tests mit
FakeTimeProvider(tests/ClawdDotNet.Core.Tests/Infrastructure/FakeTimeProvider.cs)
Slice 4 — Dokumentation
docs/ToolDevelopmentGuide.md: FileRW-Abschnitt (Zeile ~221) auf die neuen Aktionen aktualisieren- Prompt-Hinweis für Agenten: „Löschen ist reversibel, der Papierkorb wird nach X Tagen geleert" — sonst bleibt der Agent unnötig vorsichtig
6. Folgeentscheidung: Staging herunterstufen
StagingPolicy.DefaultRules (src/ClawdDotNet.Core/Staging/StagingPolicy.cs)
führt FileRW.delete heute als Approve — jede Aufräumaktion braucht eine
menschliche Freigabe. Das ist richtig, solange Löschen endgültig ist.
Mit dem Papierkorb ist es das nicht mehr. Empfehlung nach Slice 2:
["FileRW.delete"] = StagingDecision.Auto, // reversibel über .trash
["FileRW.purge"] = StagingDecision.Approve // endgültig → Freigabe
Damit kann der Agent selbstständig aufräumen (genau der Wunsch aus der Ideensammlung), ohne dass irreversible Aktionen ungefragt durchgehen.
7. Abnahmekriterien
- Ein gelöschter Ordner liegt vollständig im Papierkorb und ist per
restorewiederherstellbar. read/writeauf einen.trash-Pfad wird abgelehnt.restoreeiner.exein einen Workspace mitallowedExtensionsohne.exewird abgelehnt.- Ein
protectedPathlässt sich weiterhin nicht löschen. - Agent B sieht im Shared-Papierkorb nicht die Einträge von Agent A.
- Nach Ablauf von
retentionDaysist der Eintrag beim nächsten Job-Tick weg, ohne dass ein LLM-Run stattgefunden hat.