jbergner f7c1486ff9
Some checks failed
release-tag / release-image (push) Failing after 9m22s
9.1.2
2026-08-29 20:22:17 +02:00
2026-08-29 17:02:35 +02:00
2026-08-29 20:22:17 +02:00
2026-08-29 19:51:30 +02:00
2026-08-29 20:22:17 +02:00
2026-08-29 17:02:35 +02:00
2026-08-29 17:02:35 +02:00
2026-08-29 17:02:35 +02:00
2026-08-29 17:02:35 +02:00
2026-08-29 17:02:35 +02:00
2026-08-29 17:02:35 +02:00
2026-08-28 16:22:23 +02:00
2026-08-29 17:02:35 +02:00
2026-08-28 11:29:58 +02:00
2026-08-29 20:22:17 +02:00

JARVIS Home Command v8 Skill Engine

JARVIS besitzt jetzt eine pluginfähige Skill Engine. Die bisherigen festen Home-Tools sind weiterhin vorhanden, werden aber als Core Skills in eine gemeinsame Registry eingehängt. Zusätzliche Fähigkeiten können ohne Änderung am Go-Core unter skills/<modul>/skill.json installiert und zur Laufzeit neu geladen werden.

Neue Architektur

Voice / Text
    │
    ▼
JARVIS Agent / Workflow Planner
    │
    ▼
Skill Registry
    │
    ├── Core Skills (Go)
    │     ├── calendar.*
    │     ├── tasks.*
    │     ├── recipes.*
    │     └── ...
    │
    └── Plugin Skills (jarvis.skill.v1)
          ├── skill.json
          ├── Input JSON Schema
          ├── Output JSON Schema
          └── beliebiges Executable / Script / Binary
    │
    ▼
Schema Validation
    │
    ▼
Skill Execution
    │
    ▼
standardisiertes JSON Result

Der Agent kann Core- und Plugin-Skills in demselben Workflow kombinieren. Ein Plugin-Skill erscheint für Ollama technisch als natives Function Tool; für den Rest des Systems ist er aber ein versioniertes Skill-Modul mit klarer Modulgrenze.

jarvis.skill.v1

Ein Modul kann mehrere Actions exportieren:

{
  "protocol": "jarvis.skill.v1",
  "id": "weather.local",
  "name": "Local Weather",
  "version": "1.0.0",
  "description": "Liefert lokale Wetterdaten.",
  "enabled": true,
  "runtime": {
    "type": "process",
    "command": "./weather",
    "timeout_ms": 5000
  },
  "permissions": {
    "network": true,
    "system_exec": false
  },
  "actions": [
    {
      "name": "forecast",
      "description": "Liefert eine Wettervorhersage für einen Ort.",
      "triggers": ["wetter", "vorhersage"],
      "mutates": false,
      "input_schema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "location": {"type": "string"}
        },
        "required": ["location"]
      },
      "output_schema": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "summary": {"type": "string"}
        },
        "required": ["summary"]
      }
    }
  ]
}

Prozess-Input

JARVIS startet den Prozess mit dem Skill-Verzeichnis als Working Directory und sendet genau ein JSON-Envelope auf stdin:

{
  "protocol": "jarvis.skill.v1",
  "request_id": "skill_...",
  "skill_id": "weather.local",
  "action": "forecast",
  "input": {"location": "Berlin"},
  "context": {
    "trace_id": "http_...",
    "now": "2026-08-29T10:20:00+02:00",
    "timezone": "Europe/Berlin"
  }
}

Prozess-Output

stdout muss genau eine JSON-Antwort enthalten. Debug-/Logausgaben gehören auf stderr.

{
  "protocol": "jarvis.skill.v1",
  "success": true,
  "data": {"summary": "..."},
  "message": "Wetterdaten geladen.",
  "warnings": [],
  "mutated": false
}

Fehler werden ebenfalls strukturiert zurückgegeben:

{
  "protocol": "jarvis.skill.v1",
  "success": false,
  "error": {
    "code": "UPSTREAM_UNAVAILABLE",
    "message": "Wetterdienst nicht erreichbar"
  }
}

Input wird vor dem Prozessstart validiert; data wird anschließend gegen output_schema validiert. Ein Skill mit ungültigem JSON oder falschem Schema kann damit nicht unkontrolliert in den Agent-Loop einspeisen.

Skill-Kombinationen

Der bestehende Workflow-Agent arbeitet jetzt auf der Skill Registry. Zum Beispiel kann eine zukünftige Anfrage wie

Prüfe das Wetter für Samstag und verschiebe den Grilltermin auf Sonntag,
wenn Regen gemeldet ist.

zu einem Ablauf werden wie:

skill_weather_local_forecast
        ↓
calendar_list
        ↓
calendar_update

Die KI entscheidet über Auswahl und Reihenfolge; jeder einzelne Skill-Call wird separat gegen sein JSON-Schema geprüft.

Mutationen und Bestätigungen

Plugin-Actions können deklarieren:

{
  "mutates": true,
  "requires_confirmation": true
}

Bei requires_confirmation=true führt JARVIS den Skill nicht sofort aus. Stattdessen wird der exakte Skill-Name inklusive Arguments als serverseitige Pending Action gespeichert. Ein anschließendes ja führt genau diesen vorgemerkten Call aus — ohne erneute Interpretation durch das Modell.

Auch für Plugin-Skills gilt weiterhin: success=false kann niemals zu einer serverseitigen Erfolgsmeldung werden.

Sicherheit der Process Runtime

Process-Skills sind für lokale, vertrauenswürdige Plugins gedacht. Der Runner setzt derzeit:

  • Skill-Verzeichnis als Working Directory
  • separates Timeout pro Aufruf
  • Output-Größenlimit
  • minimale Environment-Liste statt Vererbung der kompletten JARVIS-Umgebung
  • kein systemweiter Entry-Point ohne zusätzliche Freigabe
  • Input-/Output-Schema-Validierung
  • Debug-Trace für Request, Runtime und Result

JARVIS_SKILL_ALLOW_SYSTEM_EXEC=false verhindert standardmäßig, dass ein Manifest direkt /bin/..., python3, node usw. als Entry-Point auswählt. Plugin-eigene Executables unter dem Skill-Verzeichnis funktionieren weiterhin.

Wichtig: Ein nativer Prozess ist keine harte Sicherheits-Sandbox gegen absichtlich bösartigen Code. Der Docker-Container ist eine äußere Grenze, aber ein vertrauenswürdiges Plugin kann innerhalb seiner OS-Rechte handeln. permissions.network ist in v8 eine deklarative Capability für Transparenz und zukünftige Sandbox-Runtimes; sie blockiert Netzwerkzugriffe der Process-Runtime noch nicht. permissions.system_exec wird dagegen für den direkten Manifest-Entry-Point erzwungen. Die Registry ist bewusst so gebaut, dass später weitere Runtime-Typen wie WASM oder separate Container ergänzt werden können.

Installation und Reload

Skills liegen standardmäßig unter:

./skills

Docker mountet sie nach:

/app/skills

Nach dem Hinzufügen oder Ändern eines Skills muss JARVIS nicht neu kompiliert werden. Entweder im UI RELOAD verwenden oder:

POST /api/skills/reload

Status:

GET /api/skills

Der Debug-Export enthält ebenfalls die geladene Skill Registry.

Konfiguration

JARVIS_SKILLS_DIR=./skills
JARVIS_SKILLS_ENABLED=true
JARVIS_SKILL_PROCESS_ENABLED=true
JARVIS_SKILL_ALLOW_SYSTEM_EXEC=false
JARVIS_SKILL_MAX_TIMEOUT_MS=30000
JARVIS_SKILL_MAX_OUTPUT_KB=1024

Unter skills/_template/ liegt ein kopierbarer Modulframe. skills/demo-text/ ist ein kleines ausführbares Beispiel. Ordner mit führendem _ werden vom Loader ignoriert.


Bestehender Home-Core

Die folgenden Abschnitte beschreiben die weiterhin vorhandenen Core-Funktionen. Technisch werden sie in v8 als Core Skills registriert; ihre bisherigen Function-Namen bleiben aus Kompatibilitätsgründen unverändert.

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
}
  • 124 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 MontagSonntag-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.

v9 Distributed Skill Mesh

v9 verschiebt Plugin-Code aus dem JARVIS-Master in eigenständige Runtime-Worker. Der Agent sieht weiterhin eine Skill Registry, aber eine Action kann jetzt von drei Providern stammen:

core    -> deterministische Go-Domain-Services im Master
plugin  -> lokaler Prozess-Skill (native Entwicklung; in Docker standardmäßig aus)
remote  -> HTTP Skill Worker in eigenem Container/Host

Protokolle

  • jarvis.skill.v1 Skill-/Action-Definition inklusive Input-/Output-Schema
  • jarvis.skill.worker.v1 Enrollment, Registry, Heartbeat und Deregistration
  • jarvis.skill.invoke.v1 Remote-Ausführung und Resultat

Worker-Lifecycle

Worker startet
  -> POST /api/mesh/enroll
  -> Master prüft Enrollment Token
  <- worker_id + zufälliges Session Access Token + Lease
  -> PUT /api/mesh/workers/{id}/skills
  -> periodisch POST /api/mesh/workers/{id}/heartbeat
  -> Master nimmt registrierte Actions in die Skill Registry auf
  -> Master ruft POST http://worker/v1/invoke
  -> Worker validiert Input, führt Skill aus, validiert Output
  -> bei sauberem Shutdown DELETE /api/mesh/workers/{id}

Bleibt ein Heartbeat länger als die Lease aus, entfernt der Master den Worker und seine Actions automatisch aus der aktiven Registry. Mehrere Worker dürfen denselben Skill/Action-Namen als Replik bereitstellen; der Master verteilt Aufrufe round-robin und probiert bei einem Transportfehler den nächsten Provider.

Runtime-Worker Images

Unter workers/docker/ liegen fertige Dockerfiles für:

  • Dockerfile.python Python 3.13
  • Dockerfile.node Node.js 22
  • Dockerfile.golang Go 1.23 Toolchain
  • Dockerfile.rust Rust Toolchain
  • Dockerfile.c GCC / C
  • Dockerfile.cpp G++ / CMake
  • Dockerfile.csharp .NET SDK 8 / C#

Alle Images verwenden denselben kleinen Go-basierten jarvis-skill-worker. Die jeweilige Sprache/Toolchain ist nur die Laufzeit für den Skill-Code.

Docker Compose starten

Zuerst einen eigenen Enrollment Token setzen, z. B. in .env:

JARVIS_MESH_ENROLLMENT_TOKEN=bitte-einen-langen-zufaelligen-wert-verwenden

Master/Ollama:

docker compose up -d --build jarvis ollama

Alle Runtime-Worker:

docker compose --profile skill-workers up -d --build

Oder nur Python:

docker compose --profile skill-workers up -d --build skill-python

Das mitgelieferte Python-Beispiel liegt unter skills/python/example-text und registriert skill_example_python_text_uppercase.

Skill-Verteilung

Jeder Worker bekommt sein eigenes /skills-Volume:

skills/
  python/
    mein-python-skill/
      skill.json
      main.py
  node/
  go/
  rust/
  c/
  cpp/
  csharp/

Der Worker scannt nur seine Runtime-Gruppe. POST /api/mesh/workers/{id}/reload fordert einen laufenden Worker auf, /skills neu einzulesen und seine Registry erneut beim Master zu veröffentlichen.

Docker Controller über docker.sock

Der Master kann optional den Docker Engine Unix Socket verwenden:

- /var/run/docker.sock:/var/run/docker.sock

Konfiguration:

JARVIS_DOCKER_CONTROLLER_ENABLED=true
JARVIS_DOCKER_SOCKET=/var/run/docker.sock
JARVIS_DOCKER_SKILL_LABEL=com.jarvis.skill-service
JARVIS_DOCKER_SKILL_LABEL_VALUE=true

Wichtig: Zugriff auf docker.sock entspricht praktisch administrativem Docker-/Host-Zugriff. Deshalb implementiert der JARVIS-Controller bewusst nur list, start, stop und restart. Vor jeder Mutation listet er die Docker-Container neu und akzeptiert ausschließlich eine exakte vollständige Container-ID, die aktuell das konfigurierte Label mit dem exakten Wert besitzt. Er bietet keine allgemeinen exec, create, remove, Volume- oder Image-Operationen an.

Compose versieht die Skill-Worker mit:

labels:
  com.jarvis.skill-service: "true"
  com.jarvis.skill-runtime: python
  com.jarvis.worker-name: python-main

API:

GET  /api/docker/skill-services
POST /api/docker/skill-services/{full-container-id}/start
POST /api/docker/skill-services/{full-container-id}/stop
POST /api/docker/skill-services/{full-container-id}/restart

Im Screen Wissen & System werden sowohl enrolled Remote Worker als auch gelabelte Docker Skill Services angezeigt. Dort können Worker-Skills neu geladen und Container gestartet/gestoppt/neugestartet werden.

Mesh API

POST   /api/mesh/enroll
GET    /api/mesh/workers
PUT    /api/mesh/workers/{id}/skills
POST   /api/mesh/workers/{id}/heartbeat
POST   /api/mesh/workers/{id}/reload
DELETE /api/mesh/workers/{id}

Die Enrollment-Anfrage enthält den Bootstrap-Token. Der Master gibt danach pro Worker ein kryptografisch zufälliges Session Access Token aus. Dieses Token authentifiziert Worker -> Master Heartbeats/Registry und Master -> Worker Invoke/Reload. Enrollment-/Access-Token werden vom Debug-Trace als Secrets redigiert.

Remote Invoke

Der Master sendet an den Worker:

{
  "protocol": "jarvis.skill.invoke.v1",
  "request_id": "remote_...",
  "skill_id": "example.python.text",
  "action": "uppercase",
  "input": {"text": "Hallo"},
  "context": {
    "trace_id": "http_...",
    "now": "2026-08-29T10:20:00+02:00",
    "timezone": "Europe/Berlin"
  }
}

Die gleiche trace_id läuft damit vom User-Request über Agent/Workflow und Master bis in den Remote-Worker.

Sicherheitsmodell

Remote Skill Worker sind eine deutlich stärkere Prozessgrenze als Code im Master-Container, aber Container sind nicht automatisch eine perfekte Sandbox. Für untrusted Skills weiterhin sinnvoll:

  • keine unnötigen Host-Volumes
  • kein docker.sock in Worker-Containern
  • keine --privileged Worker
  • minimale Netzwerkfreigaben
  • Ressourcenlimits in Compose/Orchestrator
  • Secrets nur gezielt pro Worker injizieren

Der Master bekommt den Docker-Socket nur für den expliziten Service-Controller. Die Runtime-Worker bekommen ihn nicht.

1 Container = 1 Skill ist ebenfalls möglich

Der generische Worker kann sowohl mehrere Unterordner unter /skills als auch einen direkt auf /skills/skill.json gemounteten Einzel-Skill laden. Damit kann ein besonders sensibler Skill einen vollständig eigenen Container bekommen, während normale Skills gemeinsam einen Runtime-Worker nutzen.

Wenn der Master die Worker später über den Docker-Controller starten soll, müssen die Container bereits existieren. Dafür z. B. einmal:

docker compose --profile skill-workers build
docker compose --profile skill-workers create

Anschließend erkennt GET /api/docker/skill-services auch die gestoppten, gelabelten Container und die UI kann sie starten. Der Controller erstellt oder entfernt absichtlich keine Container.

v9.1 Home Control Skill Pack

v9.1 ergänzt das Skill Mesh um dedizierte Remote-Integrationen für Philips Hue, UniFi Network, UniFi Protect, Proxmox VE, Dockge/Compose, Netzwerkdiagnose/Wake-on-LAN und ntfy. Außerdem unterstützt das Skill-Protokoll jetzt runtime.env_from, sodass Secrets aus Worker-ENVs nur explizit an den jeweiligen Skill-Prozess weitergegeben werden.

Details, ENV-Beispiele und Workflow-Ideen stehen in HOME-CONTROL-SKILLS.md.

v9.1.1 Clean UI State Render Fix

  • Fixes a Clean-UI JavaScript scope regression where renderCleanHome() referenced the renderState()-local sttLabel. The resulting ReferenceError stopped the render chain before groceries, meals, recipes and later modules were refreshed.
  • Voice status labels are now derived through shared helpers (sttStatusLabel / ttsStatusLabel).
  • Dashboard module renderers are isolated with safeRender, so an optional card can no longer prevent unrelated modules such as the grocery list from updating.
  • Adds a regression test for the exact failure.

v9.1.2 Render Pipeline Reliability

  • Fixed a fatal Clean/HUD state rendering regression caused by dereferencing non-existent #stt / #tts DOM nodes after the voice diagnostics update.
  • System status rendering is now isolated behind safeRender('system-status', ...); a HUD/status failure can no longer suppress groceries, skills, activity, chat, calendar, tasks, recipes or other state panels.
  • Voice tooltips now target the actual .status-chip elements via #sttStatus / #ttsStatus.
  • Static UI assets are served with Cache-Control: no-store to prevent an old app.js from surviving a container/image update.
  • Added a UI regression test that rejects direct JavaScript dereferences of DOM IDs that do not exist in index.html.
Description
No description provided
Readme 7.5 MiB
Languages
Go 89.4%
Python 5.1%
HTML 3.7%
Shell 1.3%
Dockerfile 0.3%
Other 0.2%