# Novaberg — The Nova Anima Resonance System **Eine kognitive Architektur für persönliche KI — mit emergenter Persönlichkeit, intrinsischer Neugier und emotionaler Intelligenz. Lokal, privat, deins.** 🇬🇧 [English version](README.md) --- **Nova** ist ein lokaler, privatsphäre-orientierter persönlicher KI-Assistent mit einer kognitiven Architektur. Kein einfacher Chatbot, sondern ein System aus spezialisierten Agenten, geschichtetem Gedächtnis, emotionaler Intelligenz und einem autonomen Hintergrundagenten. Nova entwickelt eigene Interessen, Ziele und Emotionen, die ihr Gespräch und Denken beeinflussen — mit einem eigenen Emotionsstrang neben dem des Nutzers. **Leitgedanke:** Das LLM ist ein Sprachprozessor, kein Wissensspeicher. Echtes Wissen liegt in PostgreSQL, Redis und im Web. Intelligenz entsteht aus der parallelen Bewertung durch spezialisierte Perspektiven. --- ## Überblick Ein einzelner Gesprächszug läuft durch **zwei** Graphen, nicht durch einen: - **Human Graph** (5 Knoten) — Perzeption → Enricher → EI-Calc → Salienz → Dispatcher. Klassifiziert, was der Nutzer gesagt hat, lädt Kontext, berechnet Emotion und Salienz und speichert, was es wert ist. Er erzeugt bewusst keine Antwort. - **Character Graph** (18 Knoten) — DB-Zugriff → EI-Calc → Enricher → Emotionale Gravitation → Reducer → Router → Planner → Agent-Dispatch → Gesprächsvektor → Responder → Thinker → Tribunal → Evaluate, danach Novas eigene Perzeption, Salienz und Speicherung. Hier entsteht die Antwort — und hier nimmt Nova ihren eigenen Zug genauso wahr und merkt ihn sich genauso, wie sie es mit dem des Nutzers tut. Verbunden sind beide über eine Redis-Ereigniswarteschlange: Der Human Graph hinterlässt ein Ereignis, ein Konsument startet einen Character-Graph-Lauf, und die Antwort erreicht den Client über einen WebSocket. Ein dritter Graph, der **Agent Graph** (3 Knoten), bedient Züge, die von Agenten stammen statt von Menschen. - **Pixie** (Hintergrund) — der autonome Hintergrundagent. Sechzehn Agenten konkurrieren nach Priorität: Promotion und Decay über beide Gedächtnisschichten, Charakter-Destillation, Wiedervorlage, Recherche, Kalibrierung, Wissenslücken, Timeline und Notizen. Geschichtetes Gedächtnis: | Schicht | Technologie | Zweck | |---------|-------------|-------| | Kurzzeit (KZG) | Redis + Vektorsuche | Aktive Gedanken, TTL-basiert | | Langzeit (LZG) | PostgreSQL | Verfestigte Erinnerungen mit Ebbinghaus-Decay | | Knowledge Graph | PostgreSQL | Entitäten, Fakten, bi-temporales Modell | | Charakter-Hash | PostgreSQL | Destillierte Persönlichkeitsprofile und die daraus abgeleiteten Charakter-Räder | Multi-Channel: Desktop-Client (GTK4) und Telegram-Bot nutzen dieselbe FastAPI-Server-Instanz. --- ## Screenshots ### Chat — Kognitive Pipeline in Echtzeit ![Chat mit Pipeline-Stages](images/nova-ui-chat-1.png) Jede Nachricht durchläuft die vollständige kognitive Pipeline. Die Stage-Indikatoren unter der Konversation zeigen jeden Verarbeitungsschritt in Echtzeit: Die Perzeption klassifiziert Intent und Emotion, der Router bestimmt den Verarbeitungspfad, der Enricher lädt relevanten Kontext aus dem Gedächtnis, der Gesprächsvektor formt Novas eigene Gesprächsintention, und der Responder generiert die Antwort. Das ist keine Dekoration — es ist die Live-Spur der kognitiven Pipeline: fünf Knoten auf dem Wahrnehmungspfad, achtzehn weitere auf dem Pfad, der die Antwort formt. ![Chat — Gespräch ohne Stages](images/nova-ui-chat-2.png) Dieselbe Konversation nach dem Verblassen der Pipeline-Stages. Markdown-Rendering, native Emoji-Darstellung und klare visuelle Trennung zwischen User- und Assistenten-Nachrichten. Novas Persönlichkeit entsteht aus geschichteter Charakter-Destillation, nicht aus einem statischen System-Prompt. ### Emotionale Intelligenz — Plutchik-Oktagon ![Emotions-Panel mit Radar-Diagrammen](images/nova-ui-emotion-2.png) Novas **eigener** emotionaler Zustand über die 8 Plutchik-Sektoren (Freude, Zuversicht, Angst, Überraschung, Trauer, Enttäuschung, Ärger, Neugier) — der Perspektive-Selector schaltet zwischen ihrem und dem des Nutzers um, beide werden durchgehend getrennt geführt. Zwei Radar-Diagramme vergleichen das aktuelle Session-Profil mit der länger laufenden emotionalen Landschaft im Kurzzeitgedächtnis. Darunter alle 16 kanonischen Emotionen mit ihren aktuellen Werten. Das Session-Radar zeigt, was jetzt passiert; das KZG-Radar zeigt den emotionalen Fingerabdruck über Wochen der Konversation. ### Session — Analyse auf Turn-Ebene ![Session-Panel](images/nova-ui-session-1.png) Jeder Gesprächs-Turn wird mit seinen analytischen Metadaten gespeichert: klassifizierter Intent, erkannte Emotion und Gesprächsmodus. Die Zusammenfassung oben wird automatisch aus dem Session-Kontext generiert. Das ist das Rohmaterial, aus dem der Enricher situative Awareness für den Responder aufbaut — hier sichtbar für Kalibrierung und Debugging. ### Kurzzeitgedächtnis (KZG) ![KZG-Panel](images/nova-ui-shorttermmemory-1.png) Novas Kurzzeitgedächtnis-Einträge, hier für User „nova" — Novas eigene Gedanken. Jeder Eintrag trägt einen Salienz-Score, thematische Tags, eine Dimensions-Klassifikation und einen TTL-Countdown. Einträge über dem Promotions-Tor — 0.94 auf der hier gezeigten Skala, das sind 0.7 vor der Salienz-Kurve — sind Kandidaten für die Konsolidierung ins Langzeitgedächtnis durch den Pixie-Hintergrundagenten. Der Inhalt ist Novas eigene Perspektive: „Für Nova gibt es kaum etwas Besseres als eine reife Tomate frisch vom Strauch." ### Langzeitgedächtnis (LZG) ![LZG-Panel](images/nova-ui-longtermmemory-1.png) Konsolidierte Erinnerungen, die den Promotions-Prozess überlebt haben. Jeder Eintrag hat ein Gewicht (verstärkt durch Abruf — der Testing Effect), eine Wissens-Dimension und Zeitstempel für Erstellung und letzte Verstärkung. Das ist die persistente Schicht — Erinnerungen hier verfallen nach der Ebbinghaus-Vergessenskurve, werden aber bei jedem Abruf durch den Enricher gestärkt. ### Charakter — Emergente Persönlichkeitsprofile ![Charakter-Panel — Novas Selbstmodell](images/nova-ui-character-1.png) Fünf destillierte Persönlichkeitsprofile, hier für Nova selbst. Das sind keine handgeschriebenen Beschreibungen, sondern das Ergebnis von Pixies Charakter-Destillationsagent, der periodisch Kurzzeit- und Langzeitgedächtnis zu strukturierten Profilen verdichtet. Das Kern-Profil erfasst, wer Nova geworden ist; das Adaptiv-Profil spiegelt ihre aktuellen Beschäftigungen; Intentionen und Emotionen beschreiben ihre Kommunikationsmuster und emotionale Grundlinie; das Beziehungs-Profil modelliert ihre Wahrnehmung des Nutzers. Alle fünf Schichten fließen in den Identitäts-Block des Responders ein. ### Charakter-Räder — der Teil, der handelt ![Charakter-Panel — die zwei Charakter-Räder](images/nova-ui-character-2.png) Aus diesen Profilen werden zwei **Charakter-Räder** abgeleitet, und die sind der Teil, der handelt statt beschreibt. Jedes stellt Einzelfragen an den destillierten Charakter — zwölf für die Zuwendung, zehn für die Initiative —, die ein LLM mit *nicht erkennbar*, *angedeutet* oder *ausgeprägt* beantwortet; der Faktor daraus wird **gerechnet**, nie geschätzt. Die Zuwendung gewichtet, wie stark die Belange des Gegenübers zählen, wenn Nova entscheidet, was sie sich merkt; die Initiative verschiebt die Achse, die bestimmt, wer das Gespräch führt. Jede Einzelbewertung wird neben der Zahl abgelegt, sodass sich jeder Faktor von Hand nachrechnen lässt — die Speichenliste unter jedem Diagramm **ist** diese Herleitung, keine Verzierung. Der orangene Punkt zeigt, wie weit das Ergebnis von der Nabe abliegt, normiert gegen die Spanne auf seiner eigenen Seite. Das ist wesentlich: Ein Rad kann **genau** auf seinem Nullpunkt landen, während die Fläche deutlich zu einer Seite hängt — dann heben sich zwei Gruppen von Speichen gegenseitig auf. Deshalb tragen beide Räder ein Herkunftsfeld: Ein gemessener Nullwert darf nicht aussehen wie einer, der nie erhoben wurde. ### Gesprächsvektor — wie Nova entscheidet, was für ein Zug das wird ![Gesprächsvektor-Panel](images/nova-ui-vector-1.png) Bevor der Responder ein Wort schreibt, wird das Gespräch in einem Raum aus 64 Sektoren verortet, die zu 14 Clustern gehören — und der Cluster entscheidet, welche rhetorischen Strategien überhaupt zur Verfügung stehen. Hier ist der Sektor *Werkstatt*, ein arbeitendes, konstruktives Register, und die sieben Strategien sind dagegen eingestuft: zwei passen, zwei sind selten, zwei sind ausgeschlossen, eine ist die Kernstrategie des Clusters. Die Prozentwerte sind Novas eigene Affinität aus ihrem Charakter; die Etiketten sind das, was die Landschaft zulässt. Wo beide sich widersprechen, gewinnt die Landschaft — und das Panel sagt, ob der Korridor eingehalten wurde. Darunter ist die Initiative-Achse in die drei Maße zerlegt, aus denen sie entsteht, plus den Charakterversatz aus dem Rad weiter oben. Das ist die Zahl, die entscheidet, ob Nova den Zug als „der Nutzer führt" oder „ich führe" behandelt — und die Schwelle daneben ist die weiterhin geltende Konstante, nicht die, die der Kalibrier-Agent inzwischen gemessen hat. Die übrigen Blöcke sind das Arbeitsmaterial: Wissenslücken, die sich für diesen Turn qualifiziert haben, Erinnerungen, die die Gravitation hereingezogen hat, und der Farbton, den der Responder mitbekommt. Nichts davon steht in einem Prompt. Alles ist gerechnet, und alles ist sichtbar, während es geschieht. ### Antrieb — Ziele, die verfallen ![Ziele-Panel](images/nova-ui-goals-1.png) Novas eigene Langzeitziele, jedes mit der Emotion, die es trägt, und einem Motivationswert, der über die Zeit fällt. Verblasste Einträge sind unter die Schwelle verfallen und ziehen nicht mehr. Das ist keine Konfiguration — die Ziele entstehen aus dem, worüber sie nachgedacht hat, und wirken zurück darauf, was sie für merkenswert hält. ### Gravitationsgraph — was woran zieht ![Gravitationsgraph-Panel](images/nova-ui-gravitation-1.png) Dieselben Ziele als kräftebasierte Karte, dazu die Turns des laufenden Gesprächs. Eine Linie heißt, dass das Embedding des Turns einem Ziel nahe genug kam, um Zug auszuüben; durchgezogen sind langfristige Ziele, gestrichelt mittelfristige. Die eingefärbten Flächen sind thematische Cluster, in die die Ziele fallen. Das ist das deutlichste Bild dafür, warum Nova ungleichmäßig behält. Ein Turn, der in einer Region landet, zu der es sie ohnehin zieht, wird anders gewichtet als einer, der das nicht tut — nicht weil eine Regel es sagt, sondern weil der Abstand im Embedding-Raum kleiner ist. --- ## Technologie-Stack - **Backend:** Python, FastAPI, LangGraph, APScheduler - **Datenbanken:** PostgreSQL 16 mit pgvector, Redis Stack - **LLM:** Ollama (lokal) mit Gemma 4 oder Mistral Small 3.2; optional Anthropic Claude API - **Embedding:** `nomic-embed-text-v2-moe` via Ollama - **Suchmaschine:** SearXNG (Docker) - **Desktop-Client:** GTK4 (PyGObject) + WebKitGTK mit SSE-Pipeline-Visualisierung - **Chat-Integration:** Telegram Bot (Long Polling, Whitelist) --- ## Voraussetzungen - **OS:** Linux (entwickelt auf Nobara). Windows/Mac technisch möglich, nicht getestet. - **Hardware:** - **GPU** mit ≥ 24 GB VRAM (getestet: AMD Radeon 7900 XTX) - **RAM** ≥ 64 GB — erforderlich, nicht nur empfohlen - **CPU** mit vielen Kernen (getestet: Ryzen 9 7900X3D) - **Software:** - Docker + Docker Compose - Ollama (host-native, nicht containerisiert) - GTK4, WebKitGTK, PyGObject (auf Fedora/Nobara vorinstalliert) ### Modell-Footprint Nova betreibt parallel drei Modelle — zwei Sprachmodelle und eines für Embeddings: | Modell | Ausführung | Zweck | Größe | |--------|-----------|-------|-------| | `gemma4-gpu` | GPU (VRAM) | Chat, Agenten, Responder | ~17 GB | | `nomic-embed-text-v2-moe` | GPU (VRAM) | Embeddings für KZG/LZG/Entity Resolution | ~1,0 GB | | `qwen36-cpu` | CPU (RAM) | Pixie — alles im Hintergrund, Sprache wie Analyse | ~24 GB | Gemma läuft ausschließlich auf der GPU. Der Hintergrundagent hat seine Arbeit früher auf zwei CPU-Modelle verteilt, eines für Sprache und eines für Analyse; er benutzt jetzt ein einziges für beides — daher drei Modelle statt vier. Das CPU-Modell liegt im RAM, dazu PostgreSQL, Redis und der Server-Prozess, und es ist das große. Deshalb sind 64 GB keine Empfehlung, sondern Voraussetzung — mit weniger fängt das System an zu swappen, und Swapping zerstört den Pixie-Durchsatz. Ollama läuft bewusst host-native, damit die GPU direkt ansprechbar ist. Die Dienste im Container verbinden sich über `host.docker.internal`. --- ## Quick Start ### 1. Repo klonen ```bash git clone https://github.com/Claus2702/novaberg.git cd novaberg ``` ### 2. Projektverzeichnis einrichten Das Repository liegt in einem Projektverzeichnis neben den Runtime-Dateien: ``` / ├── novaberg/ # geklont ├── searxng/ # Runtime-State für SearXNG (leer anlegen, wird beim ersten Start befüllt) ├── matrix/ # Runtime-State für Matrix — nur für den Matrix-Kanal (Schritt 6) │ ├── config/ # AS-Registrierung + Tokens (aus den Mustern ausfüllen) │ ├── data/ # Synapse-Daten, homeserver.yaml, Signaturschlüssel │ └── state/ # Raum-Kennung und Bild-Fingerabdruck (leer anlegen) ├── .env # Secrets (aus Template erzeugen) └── docker-compose.yml # (aus Template erzeugen) ``` ```bash cd .. mkdir searxng cp novaberg/.env.template .env cp novaberg/docker-compose.template.yml docker-compose.yml # Nur für den Matrix-Kanal (Schritt 6): cp -r novaberg/matrix matrix mkdir -p matrix/state ``` ### 3. `.env` ausfüllen Mindestens diese Werte setzen: - `ANTHROPIC_API_KEY` — nur falls `LLM_PROFILE=claude` genutzt wird Die Telegram-Schlüssel (`TELEGRAM_BOT_TOKEN`, `TELEGRAM_USER_MAP`) werden **nicht mehr gebraucht**: Der Telegram-Kanal ist am 24.08.2026 abgeschaltet, der Dienst steht nicht mehr in der Compose-Datei. `telegram_bot/` liegt weiter im Repositorium — der Dienst ist aus, der Code ist nicht gelöscht. Setze sie nur, wenn Du den Kanal zurückholst; der Compose-Block steht auskommentiert an seiner alten Stelle in `docker-compose.template.yml`. ### 4. Ollama einrichten Zwei Ollama-Instanzen auf unterschiedlichen Ports (GPU + CPU): ```bash OLLAMA_HOST=0.0.0.0:11434 ollama serve & # GPU OLLAMA_HOST=0.0.0.0:11435 ollama serve & # CPU ``` Modelle laden: ```bash # GPU — Chat und Embedding ollama pull gemma4-gpu ollama pull nomic-embed-text-v2-moe # CPU — Pixie-Hintergrundarbeit ollama pull qwen36-cpu ``` Die Modelfiles (Quantisierung, Kontextgröße, System-Prompts) liegen in `ollama/modelfiles/` als Referenz. ### 5. Dienste starten ```bash docker compose up -d ``` Dienste: - PostgreSQL auf `:5432` - Redis auf `:6379` - SearXNG auf `:8080` - Nova-Server auf `:8000` - Synapse auf `:8008` und der Matrix-Connector — **erst nach Schritt 6**; ohne ihn starten beide Behälter in einer Schleife neu Der Telegram-Kanal ist am 24.08.2026 abgeschaltet und nicht mehr Teil des Stapels. `telegram_bot/` liegt weiter im Repositorium — der Dienst ist aus, der Code ist nicht gelöscht, und der Compose-Block steht auskommentiert an seiner alten Stelle. ### 6. Matrix-Kanal (optional) Das ist der Fernkanal: Nova vom Handy aus erreichbar, über einen VPN-Tunnel, in einem echten Matrix-Client. **Es ist kein Bot.** Ein Bot hat genau einen Absender — alles, was Du am Desktop schreibst, erschiene im Kanal als `[Du] ...` aus Novas Mund. Novaberg meldet stattdessen einen *Application Service* an, der im Namen jedes Nutzers seines Namensraums senden darf: Eine Desktop-Äußerung erscheint als Nachricht von **Dir**, Novas Antwort als Nachricht von **Nova**. Die Begründung steht in `docs/novaberg-matrix-kanal_k.md`. Vier Dinge müssen vor dem ersten Start existieren. Keins davon ist optional. **a) Die Datenbank.** Synapse besteht auf `C`-Sortierung, und das ist nachträglich nur über einen Neuaufbau änderbar — also jetzt, nicht nach dem ersten Fehler: ```bash docker compose up -d postgres docker compose exec -T postgres psql -U ki -d postgres -c \ "CREATE DATABASE synapse WITH OWNER ki TEMPLATE template0 LC_COLLATE='C' LC_CTYPE='C';" ``` **b) Die Homeserver-Konfiguration.** Synapse seine Geheimnisse und den Signaturschlüssel erzeugen lassen, dann das Muster darüberlegen und die drei erzeugten Werte übernehmen: ```bash docker run --rm -v "$(pwd)/matrix/data:/data" \ -e SYNAPSE_SERVER_NAME=novaberg.de -e SYNAPSE_REPORT_STATS=no \ ghcr.io/element-hq/synapse:latest generate cp matrix/data/homeserver.template.yaml matrix/data/homeserver.yaml # dann eintragen: registration_shared_secret, macaroon_secret_key, form_secret ``` `server_name` steckt in **jeder** Nutzer- und Raum-Kennung und ist nachträglich nicht änderbar. Eine Domain nehmen, nicht die Adresse des Wirts — die kommt aus DHCP und wechselt. **c) Der Application Service.** Zwei Tokens, frei wählbar, aber lang, zufällig und voneinander verschieden. Sie gehören in **zwei** Dateien: Der Homeserver liest die eine, der Connector die andere, und weichen sie ab, weist jede Seite die andere ab. ```bash cp matrix/config/novaberg-as.template.yaml matrix/config/novaberg-as.yaml cp matrix/config/as-tokens.env.template matrix/config/as-tokens.env openssl rand -hex 32 # as_token -> in beide Dateien openssl rand -hex 32 # hs_token -> in beide Dateien ``` **d) Die zwei Konten.** Eins für Dich, eins für Nova: ```bash docker compose up -d synapse docker compose exec -T synapse register_new_matrix_user \ -c /data/homeserver.yaml -u meister -p '' --no-admin docker compose exec -T synapse register_new_matrix_user \ -c /data/homeserver.yaml -u nova -p "$(openssl rand -base64 24)" --no-admin ``` Novas Passwort wird nie gebraucht — der Application Service spricht für sie über seinen `as_token`. Deins ist das, womit Du Dich anmeldest. Danach `docker compose up -d` und einen Client (FluffyChat, Fractal, Element) auf `http://:8008` richten, angemeldet als `meister`. Den Raum legt der Connector beim ersten Lauf an; seine Kennung liegt in `matrix/state/` — **ohne diesen Mount legt jeder Neustart einen neuen Raum an**, und der Verlauf des alten bleibt liegen, ohne dass etwas anschlägt. Zwei Dinge tut dieser Aufbau nicht: Vor Synapse steht **kein TLS**, außerhalb eines VPN-Tunnels gehen also Passwort und jede Nachricht im Klartext über die Leitung; und `matrix/config/avatar-nova.png` wird nicht mitgeliefert — ein beliebiges Bild dorthin legen gibt der Figur ein Profilbild, weglassen geht auch. ### 7. Desktop-Client starten (optional) ```bash # Abhängigkeiten installieren (Fedora/Nobara — das meiste ist vorinstalliert) sudo dnf install -y python3-requests python3-websocket-client python3-markdown # Starten python3 novaberg/client/main.py ``` --- ## Konfiguration Die zentrale Konfiguration liegt in `server/config.py`. Alle Parameter sind über Umgebungsvariablen überschreibbar (siehe `.env.template`). **Wichtige Schalter:** | Variable | Werte | Effekt | |----------|-------|--------| | `LLM_PROFILE` | `lokal`, `claude` | Umschaltung zwischen Ollama und Anthropic API | | `OLLAMA_CONNECTOR` | `mistral`, `gemma4`, `qwen36` | Modell-Stack innerhalb von `lokal`. Vorgabewert ist `qwen36` — genau der Satz oben. **Der Name bezeichnet das Hintergrundmodell, nicht das antwortende** — `gemma4` und `qwen36` fahren beide Gemma auf der GPU und unterscheiden sich nur auf der CPU-Seite. Die beiden anderen Connectors erwarten CPU-Modelle, die erst gebaut werden müssen. | Feingranulare Parameter (Pixie-Intervalle, KZG-Thresholds, Such-Limits etc.) sind ebenfalls in `config.py` dokumentiert und über `PIXIE_*`-, `KZG_*`-, `NOTIZEN_*`-Variablen steuerbar. > **Sicherheitshinweis (Dev-Only-Defaults):** > Die Default-Werte in `config.py` und `docker-compose.template.yml` enthalten PostgreSQL-Credentials `ki:ki`. Diese sind ausschließlich für die lokale Entwicklungsumgebung gedacht. Für einen Produktionsbetrieb müssen `POSTGRES_URL` bzw. `POSTGRES_PASSWORD` zwingend in der `.env` auf eigene, sichere Werte gesetzt werden. Die `.env` darf nicht ins Repository eingecheckt werden. --- ## Dokumentation Die Architektur ist ausführlich dokumentiert in `docs/`: - `novaberg-architecture.md` — Gesamtübersicht - `novaberg-graph.md` — Graph-Architektur und Pipeline - `novaberg-pixie.md` — Hintergrundagent - `novaberg-memory.md` — Gedächtnis-Schichten - `novaberg-ei.md` — Emotionale Intelligenz - `novaberg-node-*.md` — Einzelne Pipeline-Knoten (23 Dokumente) - `novaberg-thinking-curiosity_k.md` — Neugier und intrinsische Motivation - `novaberg-thinking-drive_k.md` — Antrieb, Ziele und Dual-Emotion - `novaberg-roadmap.md` — Projektchronik - `novaberg-backlog.md` — Zukunftskonzepte --- ## Troubleshooting **Ollama nicht erreichbar aus Container:** Prüfen ob `host.docker.internal` aufgelöst wird. Unter Linux ist `extra_hosts: - "host.docker.internal:host-gateway"` in der Compose-Datei nötig (bereits eingetragen). **SearXNG liefert keine Ergebnisse:** Engines können durch Rate-Limits blockiert sein. Settings-Datei unter `searxng/settings.yml` anpassen — nach dem ersten Start hat SearXNG sie dort abgelegt. **PostgreSQL-Verbindung schlägt fehl:** Der Server hat `depends_on.postgres.condition: service_healthy`. Wenn der Healthcheck fehlschlägt, prüfen ob Port 5432 auf dem Host bereits belegt ist. **Gemma 4 JSON-Output bricht ab:** Bekanntes Problem (Ollama #15260). Workaround ist im Code implementiert (Cleanup-Pipeline in `config.py`). --- ## Status Nova ist aktiv in Entwicklung. Einzelentwicklung, keine externen Beiträge vorgesehen. Die Roadmap in `docs/novaberg-roadmap.md` zeigt den historischen Fortschritt, `novaberg-backlog.md` die offenen Konzepte. --- ## Lizenz Lizenziert unter der Apache License, Version 2.0.