graph rebuild

graph rebuild baut den Beziehungs-Graph eines Vaults komplett aus den Markdown- und Asset-Dateien neu auf. Das Kommando ist idempotent (ein zweiter Lauf ändert nichts, wenn sich nichts geändert hat) und wiederaufnahmefähig (ein abgebrochener Lauf lässt den Graph in benutzbarem Zustand; der nächste Lauf vollendet ihn).

Wofür ist das?

Der Graph ist ein abgeleiteter Lese-Index. Er ist kein eigenständiger Wahrheits-Speicher — alles darin ist aus den Dateien rekonstruierbar. Du greifst zu graph rebuild:

Der Befehl scannt content/*.md und assets/* genau einmal, schreibt für jede Datei einen Knoten (plus seine Kanten bei Entitäten) und entfernt am Ende Knoten, deren Quelldatei es nicht mehr gibt. Danach lässt er SQLite ANALYZE laufen, damit der Query-Planer frische Statistiken hat.

Aufruf

apparat graph rebuild

Ohne --vault gilt die gewohnte Vault-Auflösung: CWD (apparat graph rebuild in einem Vault-Verzeichnis), der einzige registrierte Vault, sonst interaktive Auswahl.

apparat graph rebuild --vault=recherche
apparat graph rebuild --vault=https://localhost/vaults/recherche
apparat graph rebuild --vault=/home/max/vaults/recherche

Optionen

Option Bedeutung
`--vault=<name url
--no-progress Unterdrückt die Fortschrittsanzeige. Nützlich in CI-Logs und bei --no-interaction.
--async Startet einen Hintergrund-Worker (via pcntl_fork) und kehrt sofort zurück. Der Rebuild läuft detached weiter; den Fortschritt fragst du mit --status ab.
--status Zeigt den aktuellen Hintergrund-Rebuild-Status für den Vault (PID, Start-Zeit, Fortschritt, Endzustand).

Ausgabe

Während des Laufs siehst du eine Fortschritts­anzeige pro verarbeiteter Datei. Am Ende fasst Apparat zusammen, was geschrieben wurde:

Vault "recherche" rebuilt:
  entities written: 128 / 128 content file(s) scanned
  assets written:   37 / 37 asset file(s) scanned
  edges written:    412
  stale nodes pruned: 0
✅ Graph is in sync with the vault.

Fallen beim Parsen irreguläre Dateien an (kaputtes YAML, fehlende Pflichtfelder, NanoID-Mismatch), listet das Kommando sie einzeln auf und beendet mit Exit-Code 1:

Vault "recherche" rebuilt:
  entities written: 127 / 128 content file(s) scanned
  ...
❌ 1 irregular file(s) could not be indexed:
  content/2024-02-14--broken--Bbbbbbbb.md
    - nanoid_mismatch — Frontmatter id "Aaaaaaaa" does not match filename suffix "Bbbbbbbb".

Die irregulären Dateien stehen parallel weiterhin in der Ausgabe von apparat vault irregular; graph rebuild verweigert in dem Fall nur die Indizierung, löscht aber keine Daten.

Meldet der Lauf zusätzlich Warnungen (z.B. Bilder ohne alt-Text oder verwaiste Frontmatter-Relations), gibt das Kommando eine Zählzeile aus und verweist auf apparat vault validate für die Detail-Liste. Der Exit-Code bleibt in dem Fall 0, solange es keine irregulären Dateien gab — Warnungen sind nicht-blockierend.

Exit-Codes

Code Bedeutung
0 Rebuild erfolgreich, keine irregulären Dateien.
1 Mindestens eine irreguläre Datei oder ein Systemfehler (Vault nicht auflösbar, Graph-DB nicht schreibbar).

Hintergrund-Rebuild für große Vaults

Für kleine Vaults (bis ca. 10.000 Entitäten) läuft der Rebuild synchron mit Fortschritts­anzeige in unter 30 Sekunden. Bei deutlich größeren Vaults möchtest du die CLI nicht so lange blockieren — dafür gibt es --async:

apparat graph rebuild --async

Apparat forkt einen Worker-Prozess, legt eine Status­datei unter <vault>/.apparat/graph-rebuild-status.json an und kehrt sofort zurück:

✅ Started background rebuild of vault "recherche" (pid 24417).
  Poll progress via `apparat graph rebuild --status` or `--vault=<name> --status`.

Den Fortschritt fragst du jederzeit ab:

apparat graph rebuild --status
Vault "recherche" — background rebuild status
  pid:         24417
  started at:  2026-04-23T12:34:56+00:00
  progress:    4870 / 12400 file(s)
  state:       running

Wenn der Worker fertig ist:

  progress:    12400 / 12400 file(s)
  state:       completed
  finished at: 2026-04-23T12:38:12+00:00
✅ Background rebuild completed cleanly.

Bei Fehlern zeigt --status den state: failed mit der Original-Fehlermeldung. Ein zweiter --async-Aufruf während ein Worker noch läuft wird abgelehnt — dafür gibt es explizit die Kontrolle per --status, bevor du einen neuen Lauf anstößt.

Voraussetzung: die pcntl-Extension (Teil der Standard-PHP-CLI-Installation unter Linux, im Docker-Container sowieso vorhanden). Ohne pcntl bricht --async mit einer klaren Fehlermeldung ab.

Verwandte Aufgaben

graph rebuild arbeitet rein lesend an deinen Markdown-Dateien — Pfade, Links und Titel im Vault bleiben unangetastet. Das Umschreiben von Pfaden ist Aufgabe von entity rename und entity edit. Wer den Graph laufend aktuell halten will, statt ihn periodisch neu zu bauen, nutzt die Datei­beobachtung. Auf dem Host genügt in der Regel der automatische Abgleich beim nächsten apparat-Aufruf — siehe Grundgedanke.