Files
jarvis-home/README.md
T
jbergner d6a50d8a0d
release-tag / release-image (push) Successful in 6m28s
Bugfix
2026-08-28 16:22:23 +02:00

16 KiB
Raw Blame History

JARVIS Home Command v6 – Native Tool Agent

Lokales Home-Dashboard in Go mit Ollama, Voice, RAG, Kalender, Aufgaben, Erinnerungen, Einkauf, Rezepten, Essensplanung und KI-Kanban.

v6 ersetzt den bisherigen Action-Planner im Chatpfad durch eine echte Tool-/Function-Calling-Architektur. Die KI darf den Home-State nicht direkt verändern. Sie wählt ein registriertes Tool und liefert dessen JSON-Arguments; Go validiert und führt es aus.

Architektur

Voice / Text
    │
    ▼
Conversation Window
    │
    ▼
Ollama Tool Agent
    │  native message.tool_calls
    ▼
Tool Registry + JSON Schema
    │
    ├── calendar_*
    ├── tasks_*
    ├── reminders_*
    ├── groceries_*
    ├── recipes_*
    ├── mealplan_*
    ├── kanban_*
    ├── rag_search
    └── system_get_time
    │
    ▼
Go Domain Services / Validator
    │
    ▼
Store
    │
    ▼
Domain Automations
    ├── Event -> Reminder
    ├── MealPlan + Recipe -> Groceries
    └── Task -> Kanban

Kernregel

Keine Tool-Ausführung = kein Commit.

Ein Modell darf also nicht mehr durch eine freie Chat-Antwort behaupten, es habe einen Termin oder Essensplan gespeichert. Mutations-Bestätigungen werden serverseitig aus dem tatsächlich persistierten Tool-Ergebnis formuliert.

Native Ollama Tools

JARVIS sendet JSON-Schemas direkt über das tools-Feld an Ollamas /api/chat. Die Modellantwort wird über message.tool_calls[].function.name und arguments ausgewertet.

Der Agent kann mehrere Schritte durchführen:

User: Plane morgen Nudeln mit Tomatensauce für vier Personen.

1. recipes_search
   -> recipe_id=r1

2. mealplan_create
   -> date resolved by Go
   -> recipe_id=r1
   -> servings=4

3. Home automation
   -> Zutaten skaliert in Einkaufsliste

4. Deterministische Commit-Antwort

Compatibility Selector

Nicht jedes lokale Modell emittiert tool_calls immer zuverlässig. Wenn eine eindeutige Home-Anfrage vorliegt, aber das Modell nur Prosa liefert, führt JARVIS einmalig einen JSON-Selector-Aufruf aus:

{
  "tool": "calendar_create",
  "arguments": {
    "title": "Zahnarzt",
    "when": {
      "kind": "relative",
      "offset_days": 1,
      "time": "15:30"
    }
  },
  "confidence": 0.99
}

Auch dieser Pfad darf nur registrierte Tools ausführen. Unbekannte Toolnamen werden abgelehnt.

Zeitmodell

Die KI berechnet Wochentage und relative Daten nicht mehr selbst. Sie liefert symbolische Zeitobjekte.

Heute:

{"kind":"relative","offset_days":0}

Morgen 15:30:

{"kind":"relative","offset_days":1,"time":"15:30"}

Montag:

{"kind":"weekday","weekday":"monday"}

Nächsten Montag:

{"kind":"weekday","weekday":"monday","force_next":true}

Explizites Datum:

{"kind":"absolute","date":"2026-08-31","time":"18:00"}

Erst das Go-Tool wandelt diese Struktur in einen RFC3339-Zeitstempel in JARVIS_TIMEZONE um.

Registrierte Tools

System / Wissen

  • system_get_time
  • rag_search

Kalender

  • calendar_list
  • calendar_create
  • calendar_update
  • calendar_delete

Aufgaben

  • tasks_list
  • tasks_create
  • tasks_update
  • tasks_delete

Erinnerungen

  • reminders_list
  • reminders_create
  • reminders_delete

Einkauf

  • groceries_list
  • groceries_add
  • groceries_update
  • groceries_remove

Rezepte

  • recipes_search
  • recipes_get
  • recipes_create

Essensplan

  • mealplan_list
  • mealplan_create
  • mealplan_update
  • mealplan_delete

Kanban

  • kanban_list
  • kanban_create
  • kanban_move
  • kanban_delete

Die vollständigen JSON-Schemas werden zur Laufzeit aus der Registry an Ollama gesendet und im Debug-Trace protokolliert. Du kannst sie außerdem direkt über GET /api/agent/tools ansehen.

Conversation Context

Der Agent bekommt weiterhin ein echtes user-/assistant-History-Fenster. Der komplette Home-State wird ihm aber nicht mehr bei jeder Anfrage in den Prompt geschoben.

Wenn JARVIS Informationen braucht, muss er ein Lese-Tool verwenden. Dadurch ist der Store die einzige Wahrheit.

Die letzte erfolgreiche Mutation wird für kurze Follow-ups als kompakte Session-Referenz gehalten:

kind=meal_plan id=meal_abc

Damit kann ein Folgekommando wie

Nein, doch Freitag.

den gerade veränderten Eintrag gezielt über mealplan_update korrigieren.

Autonomous Task Scout

Der Task Scout analysiert weiterhin Nutzertexte und Dokumente auf Verpflichtungen. Neu ist: Ein akzeptierter Scout-Kandidat schreibt nicht mehr direkt in den Store, sondern wird über dasselbe tasks_create-Tool ausgeführt.

Damit gibt es für KI-erzeugte Aufgaben nur noch einen validierten Schreibpfad.

Kalendertermine, Erinnerungen, JARVIS-Antworten und explizite Home-Kommandos bleiben als Scout-Quelle ausgeschlossen.

Domain Automations

Nach erfolgreicher Tool-Mutation werden die deterministischen Automationen synchron ausgeführt:

  • Kalendertermin -> automatischer Reminder 30 Minuten vorher
  • Rezept im Essensplan -> Zutaten in die Einkaufsliste
  • Portionen -> Zutatenmenge skaliert
  • Aufgabe -> verknüpfte Kanban-Karte
  • erledigte Aufgabe -> KI-Kanban auf DONE
  • gelöschte Aufgabe -> verwaiste KI-Karte entfernt

Manuell verschobene Kanban-Karten werden weiterhin als Override geschützt.

RAG

RAG ist jetzt selbst ein Tool: rag_search.

Das Modell erhält Dokumentauszüge nur dann, wenn es sie tatsächlich benötigt. Dadurch konkurriert ein großer RAG-Block nicht mehr bei jeder Home-Anfrage mit Conversation History und Tool-Schemas um Kontext.

Unterstützte Dokumente bleiben u. a. TXT, Markdown, CSV, JSON, YAML, XML, ICS, HTML, EML, DOCX sowie PDF über pdftotext und Bilder via lokalem Tesseract.

Voice

Die bestehende lokale Pipeline bleibt erhalten:

Browser Mic
 -> Go
 -> ffmpeg
 -> whisper.cpp
 -> Tool Agent
 -> Piper
 -> Browser Audio

Der globale Voice-Button und die Mikrofonbuttons je Modul bleiben erhalten. Der Modulname wird als Gesprächskontext mitgesendet; die konkrete Toolwahl bleibt beim Agenten.

Debug Trace v2

EXPORT DEBUG enthält jetzt zusätzlich Tool-Agent-Events:

  • agent.request
  • ollama.tools.request
  • ollama.tools.response
  • agent.tool_call
  • agent.tool_result
  • agent.selector_request
  • agent.selector_response
  • agent.completed
  • state.before_command
  • state.after_command

Beispiel:

{
  "trace_id": "...",
  "component": "agent",
  "stage": "tool_call",
  "data": {
    "tool": "mealplan_create",
    "arguments": {
      "title": "Pommes Currywurst",
      "when": {"kind":"weekday","weekday":"sunday"},
      "meal": "lunch"
    }
  }
}

Danach folgt ein separates tool_result mit dem real gespeicherten Objekt. Damit lässt sich eindeutig unterscheiden, ob ein Fehler aus Tool-Auswahl, Arguments, Validator, Store oder UI stammt.

Konfiguration

JARVIS_ADDR=:8080
JARVIS_DATA=./data/store.json
JARVIS_RAG_DATA=./data/rag.json
JARVIS_WAKE_WORD=jarvis
JARVIS_TIMEZONE=Europe/Berlin

OLLAMA_URL=http://localhost:11434
OLLAMA_MODEL=auto
OLLAMA_EMBED_MODEL=auto

# allgemeiner Chat
OLLAMA_NUM_CTX=16384
OLLAMA_NUM_PREDICT=1200
OLLAMA_TEMPERATURE=0.15

# Native Tool Agent
OLLAMA_AGENT_NUM_CTX=16384
OLLAMA_AGENT_NUM_PREDICT=700
OLLAMA_AGENT_TEMPERATURE=0
JARVIS_AGENT_MAX_STEPS=6

# Scout / Kanban strukturierte Calls
OLLAMA_PLANNER_NUM_CTX=8192
OLLAMA_PLANNER_NUM_PREDICT=700
OLLAMA_PLANNER_TEMPERATURE=0

JARVIS_HISTORY_TOKENS=3200

TASK_SCOUT_INTERVAL=2m
HOME_AUTOMATION_INTERVAL=1m
KANBAN_AI_INTERVAL=5m

JARVIS_DEBUG_TRACE=true
JARVIS_DEBUG_DIR=./data/debug

Für kleine lokale Modelle ist Temperatur 0 beim Tool-Agent bewusst empfohlen.

Start

ollama serve
ollama list

Dann:

cp .env.example .env   # optional
./scripts/doctor.sh
go run ./cmd/homehub

Dashboard:

http://localhost:8080

Empfohlene Tests nach dem Upgrade

Alten Chat einmal über CLEAR CHAT leeren, dann z. B.:

Trage morgen Zahnarzt um 15:30 Uhr in den Kalender ein.
Welche Termine habe ich morgen?

Sonntag wären Pommes Currywurst toll, zu Mittag.
Was gibt es Sonntag zu Mittag?

Plane Montag Nudeln mit Tomatensauce zum Abendessen für vier Personen.
Verschiebe das auf Freitag.

Füge zwei Liter Milch zur Einkaufsliste hinzu.
Was steht auf der Einkaufsliste?

Bei einem Fehler:

  1. CLEAR TRACE
  2. Ablauf einmal reproduzieren
  3. EXPORT DEBUG
  4. JSON hier bereitstellen

Tests

go test ./...
go vet ./...
go build ./cmd/homehub
node --check internal/ui/static/app.js

Die Tests enthalten native Tool Calls, einen mehrstufigen recipes_search -> mealplan_create-Ablauf, den JSON-Selector-Fallback und die Garantie, dass unbekannte Tools den Store nicht verändern.

Zusätzliche UI-Variante: Clean Design

Die Oberfläche enthält jetzt zusätzlich einen umschaltbaren Clean-Modus mit heller, minimaler, Apple-inspirierter Optik.

  • Umschalten direkt im Command-Bereich über JARVIS | CLEAN
  • Einstellung wird im Browser per localStorage gespeichert
  • Funktionsumfang bleibt identisch, es ändert sich nur das visuelle Design

v7 Clean App – eigene Informationsarchitektur

Der CLEAN-Modus ist jetzt keine reine Farbvariante des HUDs mehr, sondern eine eigene Multi-Screen-App.

  • Home – Assistant, nächste Termine, offene Aufgaben, nächstes Essen und Systemstatus
  • Kalender – 7-Tage-Kalender plus Erinnerungen
  • Aufgaben – fokussierte Aufgabenansicht mit KPIs und Voice-Trigger
  • Kanban – eigenständige Vollbild-Workflow-Ansicht
  • Essen & Einkauf – Essensplanung, Einkaufsliste und Rezepte auf einem Screen
  • Wissen & System – RAG, Dokumente, Sprachpipeline und Telemetrie

Desktop verwendet eine permanente linke Sidebar. Unter 850 px wechselt die Navigation in eine mobile Bottom-Bar. Die letzte Clean-Ansicht sowie das ausgewählte Design werden lokal im Browser gespeichert. Der bestehende JARVIS/HUD-Modus bleibt vollständig verfügbar.

v7.1 – Kanban AI Reliability Fix

AI ORGANIZE verwendet jetzt ebenfalls Ollamas native Tool-Calling-Schnittstelle statt freien JSON-Text zu parsen.

Ablauf:

  1. kanban_recommend als internes Tool mit festem JSON-Schema
  2. Native message.tool_calls werden bevorzugt ausgewertet
  3. Kompatibilitäts-Retry im JSON-Modus für Modelle ohne zuverlässiges Tool Calling
  4. Parser akzeptiert zusätzlich JSON in Markdown-Fences oder eingebettetem Begleittext
  5. Bei leerem/abgeschnittenem Modelloutput wird kein HTTP-502/unexpected end of JSON input mehr ausgelöst. Die synchronisierten Task-Karten bleiben deterministisch erhalten.

Der Debug-Trace enthält jetzt kanban.tool_request, kanban.tool_response, kanban.json_retry_* und gegebenenfalls kanban.deterministic_fallback.

v7.2 – Workflow Planner / Unteraufgaben

Komplexe Home-Anfragen werden nicht mehr künstlich auf genau einen Tool-Aufruf reduziert. Wenn ein lokales Modell keine nativen Tool-Calls liefert, verwendet JARVIS einen schema-strikten Workflow Planner:

{
  "goal": "Abendessen für sieben Tage planen",
  "steps": [
    {
      "id": "s1",
      "task": "Abendessen für Tag 1 planen",
      "tool": "mealplan_create",
      "arguments": {
        "title": "Gemüsepfanne mit Reis",
        "when": {"kind": "relative", "offset_days": 0},
        "meal": "dinner"
      }
    }
  ],
  "confidence": 0.96
}
  • 1–24 Unteraufgaben pro Workflow
  • jede Unteraufgabe muss ein registriertes Tool verwenden
  • alle Schritte laufen weiterhin durch die Go-Tool-Registry und deren Validatoren
  • kreative Planungswünsche (plane, erstelle, generiere) dürfen sinnvolle Vorschläge selbst auswählen
  • harte persönliche Fakten (z. B. Allergien) werden nicht erfunden
  • ganze Woche ohne weitere Präzisierung bedeutet bei Planungswünschen die nächsten sieben Kalendertage
  • der API-Response enthält plan, das HUD zeigt PLAN · N SCHRITTE
  • Debug-Trace: agent.workflow_plan_request, agent.workflow_plan_response, agent.workflow_plan

v7.3 – Recipe-First Meal Planning & Grocery Pipeline

Die Essensplanung ist jetzt recipe-first:

  • generierte Wochen-/Mehrfachpläne verwenden bevorzugt vorhandene Rezepte aus dem Rezeptbuch
  • jeder geplante Recipe-Slot speichert recipeId; bei zu wenigen Rezepten dürfen vorhandene Rezepte wiederholt werden statt Zutaten zu erfinden
  • bei komplett leerem Rezeptbuch darf der Workflow zunächst vollständige Rezepte mit Zutaten/Schritten erzeugen und sie danach einplanen
  • neue Tools: recipes_list, recipes_update, groceries_sync_mealplan
  • groceries_sync_mealplan aggregiert Mengen über alle verknüpften Rezepte und meldet Mahlzeiten ohne Rezeptzuordnung separat
  • automatische Einkaufssynchronisation betrachtet jetzt 14 statt 8 Tage, sodass auch eine kommende Montag–Sonntag-Woche vollständig erfasst wird
  • alte freie Mealplan-Titel werden automatisch mit bestehenden Rezepten verknüpft, wenn die Textähnlichkeit eindeutig genug ist
  • Rezeptänderungen aktualisieren die abgeleitete Einkaufsliste automatisch
  • im UI können Rezepte jetzt über ✎ bearbeitet werden; der Einkauf-Screen hat zusätzlich ↻ AUS PLAN

Beispiel:

Erstelle einen Essensplan für die ganze Woche, nur Abendessen.
→ recipes_list
→ 7 × mealplan_create mit recipe_id
→ automatische Zutatenaggregation

Was muss ich dafür einkaufen?
→ groceries_sync_mealplan
→ deterministische Einkaufsliste aus den gepflegten Rezeptzutaten

Zutaten werden dabei niemals frei aus einem Gerichtsnamen erfunden. Ohne Rezeptzuordnung meldet JARVIS die betroffene Mahlzeit als fehlende Rezeptbasis.

v7.4 – Confirmed Actions / Kalender-Löschfix

Bestätigungsdialoge wie Soll ich den Termin löschen? werden jetzt als konkrete serverseitige Pending Tool Action gespeichert. Ein anschließendes ja wird nicht erneut vom LLM interpretiert, sondern führt exakt das vorgemerkte Tool mit der zuvor gelesenen Entity-ID aus.

Zusätzliche Invariante: Wenn ein Schreib-Tool success:false liefert, darf freie Modellprosa niemals eine erfolgreiche Änderung behaupten. Die Antwort wird dann deterministisch aus dem Toolfehler erzeugt.

Der Debug-Export enthält hierfür runtime.pending_tool_confirmation sowie Trace-Stufen agent.pending_tool_set und agent.pending_tool_execute.

Clean UI Polish v7.5

Der Clean-Modus besitzt stärkere Textkontraste für Chat-Hervorhebungen, sekundäre Metadaten, Eingaben und Karten. Helle JARVIS-Cyan-Vererbungen werden im Clean-Modus gezielt überschrieben.

v7.5.1 – Clean Home Grid Fix

Die Clean-Home-Seite verwendet jetzt ein bewusstes 12-Spalten-Raster: Begrüßung + nächster Termin = 7/5, Aufgaben + Essen = 6/6 und Local AI = volle Breite. Dadurch entstehen auf großen Displays keine ungenutzten Restspalten mehr.

Docker Voice / Whisper (v7.6)

Im Docker-Betrieb ist whisper-cli jetzt Bestandteil des JARVIS-Images. Beim Image-Build wird whisper.cpp (standardmäßig v1.9.1) kompiliert und /usr/local/bin/whisper-cli in das Runtime-Image kopiert. Damit ist STT nicht mehr davon abhängig, dass auf dem Host ./local-tools/whisper-cli liegt.

Das Whisper-Modell bleibt als Volume unter /models, damit die große Modelldatei nicht bei jedem Build im Image landet. Für das Standard-Setup muss auf dem Host vorhanden sein:

./models/ggml-small.bin

Der schnellste Weg, Voice vollständig vorzubereiten, ist:

./scripts/setup-docker-voice.sh
docker compose build --no-cache jarvis
docker compose up -d

Das Setup-Script lädt das Whisper-small-Modell sowie die deutsche Piper-Stimme herunter und legt das Piper-Linux-Paket passend zur Host-Architektur unter ./local-tools ab.

Diagnose im Container

docker compose exec jarvis /app/scripts/doctor.sh

oder nur Whisper:

docker compose exec jarvis sh -lc 'command -v whisper-cli && whisper-cli --help >/dev/null && ls -lh /models/ggml-small.bin'

Im HUD wird bei nicht bereitem STT jetzt unterschieden zwischen:

  • BIN – Whisper-Binary fehlt oder ist nicht ausführbar
  • MODEL – Whisper-Modell fehlt
  • FFMPEG – Audio-Konverter fehlt
  • LOCAL – STT ist vollständig einsatzbereit

Die API liefert zusätzlich die aufgelösten Binary-/Modellpfade und konkrete Diagnosefehler unter system.voice. Auch docker compose logs jarvis schreibt beim Start den Voice-Status mit den einzelnen Komponenten.

Hinweis: Wenn du von einer älteren Version aktualisierst, reicht docker compose up -d möglicherweise nicht, weil Docker das alte Image weiterverwendet. Für den ersten Start von v7.6 daher einmal docker compose build --no-cache jarvis ausführen.