Zuerst der wichtigste Hinweis dieser Seite. Eine frühere Fassung beschrieb ein Menü „Datenquellen" mit dem Knopf „+ Neue Quelle", einem Limit von „3 Quellen im kostenlosen Plan" und einem automatischen Feldzuordnen nach dem Speichern. Diese Oberfläche gibt es nicht. Im gesamten Webroot existiert kein Menüeintrag „Datenquellen", und der Endpunkt /api/datenquellen antwortet mit HTTP 404 — es gibt keine solche Schnittstelle. Auch die Feldzuordnung („welches Feld ist Titel, Beschreibung, Filter") ist keine Funktion des Systems.

Eine Anleitung, die eine Bedienung beschreibt, die es nicht gibt, ist schädlicher als keine Anleitung: Sie lässt dich Fehler suchen, die nicht existieren. Diese Seite beschreibt deshalb den Weg, der wirklich funktioniert.

Wie HYPDB.ONE Daten wirklich bekommt

Es gibt genau drei Wege, auf denen Daten ins System gelangen. Alle drei sind real und messbar:

  1. JSON-Dateien im Webroot unter /assets/data/. Die Themenseiten lesen sie live mit fetch(). Das ist der Weg für eigene Kennzahlen.
  2. Skills unter ~/.hermes/skills/. Eine SKILL.md beschreibt, wann und wie ein Agent ein Werkzeug benutzt. Das ist der Weg für Arbeitsanweisungen, nicht für Datensätze.
  3. Cronjobs, die Dateien neu schreiben. Das ist der Weg für Daten, die sich ohne dein Zutun ändern — der Status-Job schreibt seine Dateien alle 5 Minuten.

Eine direkte Datenbank-Verbindung aus dem Browser (MySQL, PostgreSQL) gibt es nicht. Das ist auch technisch der richtige Weg: Zugangsdaten einer Datenbank gehören nie in einen Browser. Wenn du eine Datenbank anbinden willst, läuft der Abruf über einen Cronjob oder Skill auf dem Server, und das Ergebnis landet als JSON-Datei im Webroot.

Live: die Datenquellen dieses System

Die folgende Übersicht misst die Seite selbst. Sie fragt jede Datei einzeln ab und meldet getrennt, ob wirklich JSON geliefert wurde — nicht nur, ob die Antwort „200" war.

DATENQUELLEN PRÜFEN… Messung läuft…
DateiLiefert JSONGröße
persona_registry.json——
persona_catalog_v3.json——
persona_state.json——
system_data_v3.json——
agenten_status.json——
telefonie_status.json——
skills.json——
level_rules.json——
voice_profiles.json——
evolution_history.json——

Warum hier der Inhaltstyp geprüft wird und nicht nur die Antwort. nginx liefert bei einem unbekannten Pfad die Startseite aus — mit HTTP 200. Ein fehlendes .json-File sieht deshalb erfolgreich aus. Deshalb zählt hier nur application/json als Treffer, und die Größe wird aus dem tatsächlichen Antworttext gemessen.

Schritt 1: Vorher prüfen, was das System schon liefert

SCHRITT 1/5

Bevor du eigene Daten anlegst, prüfe die vorhandenen Quellen. Ein großer Teil der Daten, die eine KI-Seite braucht, ist bereits da: Agenten-Status, Persona-Register, Stufenregeln, Telefonie-Status. Der Grund, warum das wichtig ist: Wer eine Datei anlegt, die es bereits gibt, erzeugt zwei Quellen für dieselbe Zahl — und ab dem Tag widersprechen sie sich.

Ein Beispiel aus diesem System: persona_registry.json und persona_catalog_v3.json nennen unterschiedliche Personenzahlen. Welche die führende ist, ist nicht geklärt. Solange das offen ist, zeigen Seiten beide Werte mit ihrer Quelle, statt sich auf eine zu festlegen.

Schritt 2: Eigene Datei anlegen

SCHRITT 2/5

Lege eine JSON-Datei unter /assets/data/ ab. Zwei Formen sind üblich:

Ein einzelnes Objekt — für Kennzahlen

{ "erstellt": "2026-10-04 12:00:00", "auftraege_offen": 3, "quote_erfuellt": 92, "kunden_gesamt": 148 }

Eine Liste — für Datensätze

[ { "produkt": "Fenster A", "preis": 29.90, "kategorie": "Fenster", "bestand": 142 }, { "produkt": "Sonnenschutz B", "preis": 49.90, "kategorie": "Beschattung", "bestand": 89 } ]

Speichere als UTF-8. Ein Byte-Order-Mark am Dateianfang macht die Datei für den JSON-Parser ungültig, obwohl sie im Texteditor fehlerlos aussieht.

Schritt 3: Die drei Fehler, die jede eigene Datei zerlegen

SCHRITT 3/5

Diese drei Punkte entscheiden, ob deine Datei auf einer Seite erscheint oder als leerer Platzhalter stehenbleibt:

  • Zahlen als Zahlen, nicht als Text. "preis": "29.90" ist eine Zeichenkette. Beim Rechnen wird daraus stillschweigend Text. Schreibe 29.90.
  • Kein Komma nach dem letzten Eintrag. Der häufigste JSON-Fehler. Das Parse bricht ab, die Seite zeigt gar nichts.
  • Keine Geheimnisse in der Datei. Passwörter und API-Schlüssel gehören nicht unter /assets/data/ — alles dort ist öffentlich abrufbar.

💡 Praxisregel: Benenne die Datei nach dem Inhalt, nicht nach dem Anlass. auftragsbestand.json überlebt einen Taskwechsel, zwischenergebnis_2026_10.json nicht. Sonst weiß in drei Monaten niemand mehr, welche Datei die gültige ist.

Schritt 4: An eine Seite binden

SCHRITT 4/5

Eine Datei im Webroot ist noch keine Anzeige. Sie muss von einer Seite abgerufen und in ein sichtbares Element geschrieben werden. Das kleinstmögliche Muster, das zuverlässig funktioniert:

// 1. Platzhalter mit id im HTML anlegen <span id="wert">—</span> // 2. Abruf mit Zeitgrenze function laden() { var ac = new AbortController(); var tid = setTimeout(function () { ac.abort(); }, 12000); fetch('/assets/data/deine_datei.json', { cache: 'no-store', signal: ac.signal }).then(function (r) { clearTimeout(tid); var ct = r.headers.get('content-type') || ''; if (ct.indexOf('json') < 0) { throw new Error('Kein JSON, sondern ' + ct); } return r.json(); }).then(function (d) { var el = document.getElementById('wert'); // IMMER getElementById if (el) el.textContent = String(d.auftraege_offen); }).catch(function (e) { var el = document.getElementById('wert'); if (el) el.textContent = 'nicht erreichbar'; }); } document.addEventListener('DOMContentLoaded', laden);

Drei Fallen, die alle statischen Prüfungen passieren

  • Eine Elementauswahl ohne Raute trifft nie. querySelector('id') sucht nach einem Tag mit diesem Namen und liefert null. Richtig ist getElementById('id') oder querySelector('#id'). Die Seite bleibt dann syntaktisch sauber, zeigt aber nichts — ohne jede Fehlermeldung.
  • Ohne Zeitgrenze hängt der Abruf ewig. Wenn der Dienst nicht antwortet, greift der Fehlerzweig nie, und der Platzhalter bleibt für immer stehen.
  • Objekte nicht mit String() in Zellen schreiben. Ein Objekt wird dann als [object Object] angezeigt. Immer das konkrete Feld lesen. Das Syntaxprüfwerkzeug meldet die Seite in diesem Zustand als fehlerfrei.

💡 Reihenfolge der Prüfung: Erst ansehen, ob die Datei über ihre Adresse JSON liefert. Dann die Seite laden und im Browser prüfen, ob der Wert im Text steht. Ein sauberes Ergebnis der Code-Prüfung sagt nichts darüber aus, was sichtbar ist — diese drei Fehler fallen nur im Browser auf.

Schritt 5: Aktuell halten

SCHRITT 5/5

Eine von Hand geschriebene Datei veraltet sofort. Es gibt zwei sinnvolle Wege:

  • Ein Cronjob schreibt die Datei neu. So arbeitet das System selbst: Der Job agenten-status-frisch schreibt agenten_status.json alle 5 Minuten. Das Intervall steht in der Job-Konfiguration des Profils, nicht in der Anzeige — eine frühere Fassung dieser Seite behauptete hier 30 Sekunden.
  • Ein Skill beschreibt den Abruf. Wenn die Daten aus einer API oder Datenbank kommen, gehört der Abruf in eine SKILL.md oder in das Skript des Cronjobs. Der Browser bleibt außen vor.

Für Live-Daten aus einer externen Quelle ist der Ablauf immer derselbe: abrufen, umformen, als JSON ins Webroot legen, Seite liest sie. Die Seite selbst ruft niemals deine Datenbank auf.

Wenn es nicht funktioniert

Die Datei liefert 200, aber die Seite zeigt nichts

Fast immer die nginx-Fallback-Falle: unbekannte Pfade liefern die Startseite mit HTTP 200. Prüfe den Inhaltstyp. Nur application/json zählt — und im Zweifel die Datei direkt auf der Platte ansehen, nicht nur die Antwort des Servers.

Der Platzhalter bleibt auf „—" stehen

Fast immer eine fehlgeschlagene Elementauswahl. getElementById verwenden und sicherstellen, dass id im HTML vor dem Skript steht. Läuft das Skript vorher, findet es das Element nicht.

Der Wert stimmt, aber der Text nicht

Prüfe den Inhaltstyp der Antwort. Kommt statt JSON eine HTML-Seite, wird jede Textzeile in ein Feld geschrieben — auch das sieht „halb plausibel" aus, ist aber der Fehler.

Der Wert erscheint, aber ohne Neuerung

Der Abruf ist dann korrekt, der Browser aber cached. Verwende cache: 'no-store' im Abruf. Prüfe außerdem, ob der Job, der die Datei schreibt, wirklich läuft.

Weiterführend