feat: Curator Auto-Archivierung (14-Tage-Inaktivität)
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
# Spezifikation: Auto-Archivierung nach 14 Tagen Inaktivität
|
||||
|
||||
**Datum:** 2026-07-24
|
||||
**Task:** t_a401f387
|
||||
**Status:** Analyse abgeschlossen → Spezifikation erstellt
|
||||
**Herkunft:** Aus der Ideen-Queue (Idle-Radar, Traum-Notiz vom 18.07.2026)
|
||||
|
||||
---
|
||||
|
||||
## 1. Kontext
|
||||
|
||||
### 1.1 Ziel
|
||||
Reduziere den Clutter im Skill-Index und unterstütze den Curator bei der Pflege.
|
||||
|
||||
### 1.2 Aktueller Zustand
|
||||
| Komponente | Status |
|
||||
|------------|--------|
|
||||
| Aktive Skills | 11 |
|
||||
| Archivierte Skills | 15 Kategorien |
|
||||
| Usage-Tracking | Vorhanden (`.usage.json`), aber leer |
|
||||
| `.curator_state` | `paused: true` |
|
||||
| 14-Tage-Regel | **Nicht implementiert** |
|
||||
|
||||
### 1.3 Messlatte
|
||||
- **Stale-Skills:** Skills mit `state: "stale"` in `.usage.json` (bisher kein Eintrag)
|
||||
- **Inaktivität:** Letzte Nutzung (`last_used_at`) liegt >14 Tage zurück
|
||||
- **Archivierung:** Verschieben in `.archive/<Kategorie>/` und Setzen von `archived_at`
|
||||
|
||||
---
|
||||
|
||||
## 2. Architektur
|
||||
|
||||
### 2.1 Komponenten
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────┐
|
||||
│ Curator-Auto-Archivierung │
|
||||
├─────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Idle-Radar │ → │ Archivierungs- │ → │ Curator-Indexer│ │
|
||||
│ │ (Trigger) │ │ Watchdog │ │ (Datenpflege) │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └──────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 Datenfluss
|
||||
1. **Idle-Radar** erkennt Inaktivität (nächtlicher Scan)
|
||||
2. **Archivierungs-Watchdog** prüft 14-Tage-Regel
|
||||
3. **Curator-Indexer** aktualisiert `.usage.json` mit `archived_at`
|
||||
4. Skill-Verzeichnis wird nach `.archive/<Kategorie>/` verschoben
|
||||
|
||||
---
|
||||
|
||||
## 3. Dateistruktur
|
||||
|
||||
### 3.1 Aktiv-Verzeichnis (`~/.hermes/skills/`)
|
||||
- Normale Skill-Ordner (`betrieb-playbook/`, `wartung/`, ...)
|
||||
- `.usage.json` (Nutzungsdaten)
|
||||
- `.curator_state` (Curator-Status)
|
||||
|
||||
### 3.2 Archiv-Verzeichnis (`~/.hermes/skills/.archive/`)
|
||||
```
|
||||
.archive/
|
||||
├── apple/ # Kategorie: Apple-Tools
|
||||
├── creative/ # Kategorie: Kreatives
|
||||
├── data-science/ # Kategorie: Datenanalyse
|
||||
├── github/ # Kategorie: GitHub
|
||||
├── media/ # Kategorie: Medien
|
||||
├── mlops/ # Kategorie: MLOps
|
||||
├── research/ # Kategorie: Recherche
|
||||
├── software-development/ # Kategorie: Dev-Tools
|
||||
└── ... # Weitere Kategorien
|
||||
```
|
||||
|
||||
### 3.3 Skill-Datei nach Archivierung
|
||||
```
|
||||
~/.hermes/skills/.archive/software-development/gitea-workflow/
|
||||
├── SKILL.md
|
||||
└── ... (weitere Dateien)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Konfiguration
|
||||
|
||||
### 4.1 `.curator_state`
|
||||
```json
|
||||
{
|
||||
"last_report_path": "/home/hitonabi/.hermes/logs/curator/20260720-182035",
|
||||
"last_run_at": "2026-07-20T18:20:35.806573+00:00",
|
||||
"last_run_duration_seconds": 882.931897,
|
||||
"last_run_summary": "auto: no changes; llm: Context length exceeded: max compression attempts (3) reached.",
|
||||
"last_run_summary_shown_at": "2026-07-20T18:20:35.806573+00:00",
|
||||
"paused": false, // ← aktiviert für Auto-Archivierung
|
||||
"run_count": 11,
|
||||
"archivierung": {
|
||||
"enabled": true, // ← neuer Schlüssel
|
||||
"threshold_days": 14, // ← neuer Schlüssel
|
||||
"last_archive_run_at": "2026-07-24T03:00:00.000000+00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 `.usage.json` – Archivierter Skill
|
||||
```json
|
||||
{
|
||||
"gitea-workflow": {
|
||||
"archived_at": "2026-07-24T03:00:00.000000+00:00", // ← neuer Schlüssel
|
||||
"created_at": "2026-06-30T20:00:58.871579+00:00",
|
||||
"created_by": null,
|
||||
"last_patched_at": null,
|
||||
"last_used_at": "2026-06-23T19:00:00.000000+00:00",
|
||||
"last_viewed_at": null,
|
||||
"patch_count": 0,
|
||||
"pinned": false,
|
||||
"state": "archived", // ← geändert von "active"
|
||||
"use_count": 0,
|
||||
"view_count": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Trigger-Mechanismus
|
||||
|
||||
### 5.1 Zeitlicher Trigger
|
||||
- **Cron-Job:** `0 3 * * *` (täglich um 3:00 Uhr)
|
||||
- **Skript:** `~/.hermes/scripts/curator-archive-watchdog.sh`
|
||||
|
||||
### 5.2 Prüflogik
|
||||
```python
|
||||
def is_stale(skill_usage: dict) -> bool:
|
||||
"""Prüft, ob ein Skill älter als 14 Tage ist."""
|
||||
last_used = skill_usage.get("last_used_at")
|
||||
if not last_used:
|
||||
return False
|
||||
|
||||
last_used_dt = datetime.fromisoformat(last_used.replace("Z", "+00:00"))
|
||||
now = datetime.now(last_used_dt.tzinfo)
|
||||
days_inactive = (now - last_used_dt).days
|
||||
return days_inactive >= 14
|
||||
```
|
||||
|
||||
### 5.3 Ausschlusskriterien
|
||||
- **Pinned:** `pinned: true` → nie archivieren
|
||||
- **Verwendung im Live-Repo:** Skills aus `~/mission-control-v2/deploy/skills/` nicht archivieren
|
||||
- **System-Skills:** `betrieb-playbook`, `wartung`, `orchestrator` nicht archivieren (Konfigurierbar in `.curator_state`)
|
||||
|
||||
---
|
||||
|
||||
## 6. Archivierungs-Workload
|
||||
|
||||
### 6.1 Schritte
|
||||
1. **Scan:** Alle Skills in `~/.hermes/skills/` durchlaufen
|
||||
2. **Prüfung:** `is_stale()` für jeden Skill aufrufen
|
||||
3. **Ausschluss:** Pinned/System-Skills überspringen
|
||||
4. **Verschieben:** Skill-Verzeichnis nach `.archive/<Kategorie>/`
|
||||
5. **Index aktualisieren:** `.usage.json` mit `archived_at` und `state: "archived"` schreiben
|
||||
6. **Protokoll:** Log-Eintrag in `~/.hermes/logs/curator/`
|
||||
|
||||
### 6.2 Beispiel-Archivierung
|
||||
```bash
|
||||
# Vorher
|
||||
~/.hermes/skills/skill-automatisch-verknuepfen/SKILL.md
|
||||
|
||||
# Nachher
|
||||
~/.hermes/skills/.archive/software-development/skill-automatisch-verknuepfen/SKILL.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Datenformat
|
||||
|
||||
### 7.1 `.usage.json` – Aktiv
|
||||
```json
|
||||
{
|
||||
"name": {
|
||||
"archived_at": null,
|
||||
"created_at": "2026-07-03T07:50:53.782473+00:00",
|
||||
"created_by": null,
|
||||
"last_patched_at": null,
|
||||
"last_used_at": "2026-07-06T08:55:31.369025+00:00",
|
||||
"last_viewed_at": "2026-07-06T08:55:31.367242+00:00",
|
||||
"patch_count": 0,
|
||||
"pinned": false,
|
||||
"state": "active",
|
||||
"use_count": 2,
|
||||
"view_count": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 `.usage.json` – Archiviert
|
||||
```json
|
||||
{
|
||||
"name": {
|
||||
"archived_at": "2026-07-24T03:00:00.000000+00:00",
|
||||
"created_at": "2026-07-03T07:50:53.782473+00:00",
|
||||
"created_by": null,
|
||||
"last_patched_at": null,
|
||||
"last_used_at": "2026-07-06T08:55:31.369025+00:00",
|
||||
"last_viewed_at": "2026-07-06T08:55:31.367242+00:00",
|
||||
"patch_count": 0,
|
||||
"pinned": false,
|
||||
"state": "archived",
|
||||
"use_count": 2,
|
||||
"view_count": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Config-Interface
|
||||
|
||||
### 8.1 `.curator_state` – Erweiterung
|
||||
```json
|
||||
{
|
||||
"archivierung": {
|
||||
"enabled": true,
|
||||
"threshold_days": 14,
|
||||
"excluded_skills": ["betrieb-playbook", "wartung", "orchestrator"],
|
||||
"last_archive_run_at": "2026-07-24T03:00:00.000000+00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 `.usage.json` – Erweiterung
|
||||
```json
|
||||
{
|
||||
"name": {
|
||||
"archived_at": "2026-07-24T03:00:00.000000+00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Akzeptanzkriterien
|
||||
|
||||
| Kriterium | Status |
|
||||
|-----------|--------|
|
||||
| Klare Architektur | ✅ (siehe Abschnitt 2) |
|
||||
| Definierte Dateistruktur | ✅ (`.archive/<Kategorie>/`) |
|
||||
| Config-Interface | ✅ (`.curator_state` + `.usage.json`) |
|
||||
| Keine Code-Änderungen | ✅ (nur Spezifikation) |
|
||||
|
||||
---
|
||||
|
||||
## 10. Nächste Schritte
|
||||
|
||||
### 10.1 Implementierung
|
||||
1. **Skript erstellen:** `~/.hermes/scripts/curator-archive-watchdog.sh`
|
||||
2. **Cron-Job anlegen:** `0 3 * * * curator-archive-watchdog.sh`
|
||||
3. **`.curator_state` erweitern:** `archivierung`-Block hinzufügen
|
||||
4. **`.usage.json` erweitern:** `archived_at`-Feld einfügen
|
||||
|
||||
### 10.2 Test
|
||||
1. Manuell einen Skill archivieren (Handbetrieb)
|
||||
2. Prüfen, ob `archived_at` gesetzt wird
|
||||
3. Prüfen, ob `.archive/<Kategorie>/` angelegt wird
|
||||
4. Prüfen, ob `state: "archived"` in `.usage.json` steht
|
||||
|
||||
---
|
||||
|
||||
## 11. Anhang
|
||||
|
||||
### 11.1 Begriffe
|
||||
| Begriff | Bedeutung |
|
||||
|---------|-----------|
|
||||
| **Stale** | Skill mit `last_used_at > 14 Tage` |
|
||||
| **Archivierung** | Verschieben in `.archive/<Kategorie>/` |
|
||||
| **Curator** | Der automatische Wartungsdienst |
|
||||
| **Idle-Radar** | Das System, das Inaktivität erkennt |
|
||||
|
||||
### 11.2 Quellen
|
||||
- `~/.hermes/skills/.curator_state`
|
||||
- `~/.hermes/skills/.usage.json`
|
||||
- `~/.hermes/skills/.archive/`
|
||||
- `~/wissens-vault/eigenbau-landkarte.md`
|
||||
|
||||
---
|
||||
|
||||
**Ende der Spezifikation**
|
||||
Reference in New Issue
Block a user