32 KiB
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_timerag_search
Kalender
calendar_listcalendar_createcalendar_updatecalendar_delete
Aufgaben
tasks_listtasks_createtasks_updatetasks_delete
Erinnerungen
reminders_listreminders_createreminders_delete
Einkauf
groceries_listgroceries_addgroceries_updategroceries_remove
Rezepte
recipes_searchrecipes_getrecipes_create
Essensplan
mealplan_listmealplan_createmealplan_updatemealplan_delete
Kanban
kanban_listkanban_createkanban_movekanban_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.requestollama.tools.requestollama.tools.responseagent.tool_callagent.tool_resultagent.selector_requestagent.selector_responseagent.completedstate.before_commandstate.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:
CLEAR TRACE- Ablauf einmal reproduzieren
EXPORT DEBUG- 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
localStoragegespeichert - 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:
kanban_recommendals internes Tool mit festem JSON-Schema- Native
message.tool_callswerden bevorzugt ausgewertet - Kompatibilitäts-Retry im JSON-Modus für Modelle ohne zuverlässiges Tool Calling
- Parser akzeptiert zusätzlich JSON in Markdown-Fences oder eingebettetem Begleittext
- Bei leerem/abgeschnittenem Modelloutput wird kein HTTP-502/
unexpected end of JSON inputmehr 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 Wocheohne weitere Präzisierung bedeutet bei Planungswünschen die nächsten sieben Kalendertage- der API-Response enthält
plan, das HUD zeigtPLAN · 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_mealplanaggregiert 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ührbarMODEL– Whisper-Modell fehltFFMPEG– Audio-Konverter fehltLOCAL– 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 -dmöglicherweise nicht, weil Docker das alte Image weiterverwendet. Für den ersten Start von v7.6 daher einmaldocker compose build --no-cache jarvisausfü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-Schemajarvis.skill.worker.v1– Enrollment, Registry, Heartbeat und Deregistrationjarvis.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.13Dockerfile.node– Node.js 22Dockerfile.golang– Go 1.23 ToolchainDockerfile.rust– Rust ToolchainDockerfile.c– GCC / CDockerfile.cpp– G++ / CMakeDockerfile.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.sockin Worker-Containern - keine
--privilegedWorker - 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 therenderState()-localsttLabel. The resultingReferenceErrorstopped 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/#ttsDOM 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-chipelements via#sttStatus/#ttsStatus. - Static UI assets are served with
Cache-Control: no-storeto prevent an oldapp.jsfrom 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.