graph watch
graph watch startet den File-Watcher-Daemon, der im Hintergrund auf Änderungen in content/ und assets/ reagiert und den Graph-Index inkrementell aktuell hält. Damit bleibt der Graph synchron, ohne dass du nach jedem vim oder git pull ein graph rebuild aufrufen musst.
Wofür ist das?
Solange der Watcher läuft, merkt sich Apparat jede Änderung an deinen Vault-Dateien und zieht sie sofort in den Graph nach:
- Neue oder geänderte Markdown-Datei → Parser +
upsertNode+ Kanten-Update. - Neues oder geändertes Asset → Asset-Knoten angelegt oder aktualisiert.
- Gelöschte Datei → Knoten entfernt, eingehende/ausgehende Kanten per Cascade mit gelöscht.
Editor-Quirks (Tempfile + Rename, Doppel-Events, halb geschriebene Dateien) fängt der Watcher ab: jede Änderung wartet 200 ms auf Ruhe, dann läuft ein SHA-256-Check gegen die letzte Version. Identische Inhalte sind No-Ops — das spart Parser-Läufe und hält die Log-Datei übersichtlich.
Container-only
Der Watcher läuft ausschließlich im Docker-Container. Die Voraussetzung ist die PHP-inotify-Extension, die im mitgelieferten Image ab Werk installiert ist. Auf dem Host (macOS, nativ-Linux ohne Extension, WSL-PHP) bricht apparat graph watch mit einer klaren Fehlermeldung ab — dort aktualisierst du den Graph manuell per apparat graph rebuild.
Diese Trennung ist bewusst: Ein Multi-Plattform-Watcher mit Polling-Fallback und Cloud-Sync-Heuristik wäre drei Code-Pfade für einen Randfall. Der Container ist die empfohlene Laufzeit — dort läuft der Watcher dauerhaft im Hintergrund parallel zur Web-Oberfläche.
Aufruf
apparat graph watch
Auf dem Host getippt, delegiert das apparat-Kommando den Aufruf transparent in den Web-Container des Mandanten — siehe Container-Kommandos werden automatisch im Container ausgeführt. Innerhalb eines Container-Shells (docker compose exec -u apparat web-local bash) läuft der Aufruf direkt.
Ohne Argumente beobachtet der Watcher alle in der Mount-Registry eingetragenen Vaults. Mit --vault schränkst du auf einen einzigen Vault ein — praktisch für gezielte Beobachtung oder Debugging:
apparat graph watch --vault=recherche apparat graph watch --vault=https://localhost/vaults/recherche apparat graph watch --vault=/var/apparat/vaults/recherche
Der Daemon läuft, bis er ein SIGINT oder SIGTERM erhält (Ctrl+C in der Shell, docker stop beim Container-Stop, Supervisor-Shutdown). SIGHUP lädt die Mount-Registry neu, ohne den Prozess zu stoppen — nützlich, wenn du mitten im Betrieb einen neuen Vault per vault init registriert hast.
Signalverhalten
| Signal | Wirkung |
|---|---|
SIGINT / SIGTERM |
Sauberer Shutdown: offene Watches werden freigegeben, der Prozess endet mit Exit-Code 0. |
SIGHUP |
Mount-Registry wird neu gelesen; neu hinzugekommene Vaults werden beobachtet, entfernte Vaults losgelassen. |
Änderungen an ~/.config/apparat/mounts.yaml (dem Registry-File) werden zusätzlich automatisch erkannt — dafür brauchst du kein SIGHUP zu schicken.
Logging
Der Watcher schreibt strukturierte Log-Zeilen (eine Aktion pro Zeile, JSON-artig) nach
storage/logs/apparat-watcher.log
Der Log-Kanal heißt apparat-watcher und ist in config/logging.php konfiguriert. Drei Ereignis-Klassen findest du dort:
watcher.upsert/watcher.asset/watcher.delete— reguläre Indexaktualisierungen.watcher.irregular— eine Datei konnte nicht als Entität geparst werden (NanoID-Mismatch, fehlende Pflichtfelder …). Der Watcher schreibt keinen Knoten, die Datei erscheint aber inapparat vault irregular.watcher.vault.*/watcher.reload.failure— Events rund um Mount-Registry-Reloads.
Einschränkungen
- Fließtext-Links auf noch nicht existierende Ziele werden beim Event fallen gelassen (das gleiche Verhalten wie beim
graph rebuild). Sobald das Ziel später angelegt wird, muss die linkende Datei noch einmal angefasst werden, damit die Kante materialisiert wird — oder du fährst einmalapparat graph rebuild. - Keine Rekursion in Unterverzeichnisse.
content/undassets/sind per Spec flach; Unterordner werden nicht beobachtet. - Kein Host-Watcher. Die Dateibeobachtung lebt im Web-Container (sie braucht eine Container-Extension). Wo sie nicht dauerhaft läuft, hältst du den Graph stattdessen punktuell per
apparat graph rebuildaktuell. Siehe oben.
Exit-Codes
| Code | Bedeutung |
|---|---|
| 0 | Sauberer Shutdown (SIGINT/SIGTERM). |
| 1 | Start abgebrochen (fehlende inotify-Extension, nicht auflösbarer Vault). |