Author SHA1 Message Date
HitonabiandClaude Fable 5.1 df8d088fac doku(raphael): Ausroll-Weg korrigiert — Branch -> Ampel -> User-Merge -> deploy.sh, nicht Auftragsbuch
Ampel / ampel (push) Failing after 23s
Der vorige Commit sprach von Karten annehmen. Befund: die Auftragsbuch-Logik liegt noch im Code
und die Box listet Branches als Karten, ist aber seit 02.08. ungenutzt (Kanban-Tools seit 21.08.
aus, v3-Umbau lief ueber Branch/Ampel/Merge/deploy.sh, PC-Executor-IP in der Box veraltet).
RAPHAEL.md beschreibt jetzt den echten Weg mit Befehlen; OFFENE-FAEDEN traegt die Leiche als
Entscheid-Punkt ein. Kein Code geaendert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 16:07:03 +02:00
HitonabiandClaude Fable 5.1 b570e9410d feat(voice): Lucys Stimme ins LAN (/api/lucy/stimme) + Raphael-Zielbild
Ampel / ampel (push) Failing after 24s
Die Desktop-Lucy spricht nach dem Raphael-Umbau (Lucy-Repo, feature/raphael-innere-stimme)
nicht mehr mit einem eigenen pocket_server am PC, sondern mit lucy-stimme.service (:8021,
pocket-tts german_24l) auf der Box — dieselbe Stimme wie die Telegram-Sprachnachrichten.
Der Dienst bindet nur Loopback, darum reicht MC2 ihn jetzt duenn durch:
  GET  /api/lucy/stimme/health       -> pocket /health (ok|loading)
  POST /api/lucy/stimme/tts          -> WAV (Warm-up, Jobs)
  POST /api/lucy/stimme/tts/stream   -> PCM16-Stream, X-Sample-Rate durchgereicht,
                                        Upstream schliesst bei Client-Abbruch (Barge-in)
config: LUCY_STIMME_URL (Env MC_LUCY_STIMME_URL, Default http://127.0.0.1:8021).
Kein Frontend-Build noetig (nur Backend + Doku).

Doku: docs/wissen/RAPHAEL.md (Entscheid, Annahme-Reihenfolge — DIESE Karte zuerst —,
Box-Handschritte fuer die OpenAI-Fassade + Hermes-TTS auf openai/base_url :8021, Mobil via
Telegram, SOUL.md-Vorschlag im Raphael-Ton), ZIELBILD Punkt 8, OFFENE-FAEDEN, wissen/README.
VERDIKTE.md bewusst unveraendert — Ersatz erst nach Ohr-Test.
Gates: py_compile + ruff gruen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 16:02:18 +02:00
HitonabiandClaude Fable 5.1 e9c2599542 fix(radar): nur Aenderungen ans Modell, und kein Fehlalarm nach dem Neustart
Ampel / ampel (push) Failing after 23s
Erster Lauf des Upstream-Blicks: das Modell machte aus "unveraendert"-Zeilen
naechste Schritte und aus "Timer seit Neustart noch nicht gelaufen" ein hohes
Risiko. Beides filtert jetzt das Skript: nur ACHTUNG-Zeilen (plus Hinweis)
gehen in den Prompt, und ein Timer mit naechstem Termin auf einer Box, die
juenger als einen Tag ist, gilt als wartend, nicht als kaputt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 14:53:55 +02:00
HitonabiandClaude Fable 5.1 a8a6ce3b29 feat(radar): Blick nach draussen als Skript — und heavy zieht auf Qwen3.8-27B
Warum: DFlash2 fuer den Coder lag vom 19.08. bis 04.09. ungenutzt auf der
Platte, weil der KISS-Radar nur nach innen sah. stack-upstream.py fragt die
Watchlist als Fakten ab (GitHub-Issues/PRs/Releases/Branches, PyPI, neue
Repos eines HF-Autors, Zeilen einer URL), vergleicht mit dem letzten Lauf und
meldet nur Aenderungen als ACHTUNG NEU. stack-radar.sh haengt das an den
IST-Zustand; faellt es aus, bleibt der Innen-Bericht vollstaendig.
Erster Lauf fand sofort: MMQ-Issue 21284 ist geschlossen, pocket-tts 3.1.0,
Electron 44 — alles Dinge, die der Radar seit Juli haette melden sollen.

heavy: gpt-oss-120b (AA-Index 24, 60 GB) gibt die Rolle an Qwen3.8-27B ab
(Index 52, 17 GB, 31 t/s mit DFlash2) — ein Modell, zwei Rollen. gpt-oss
bleibt ohne Alias als Rollback. Live gemessen ueber :9010 mit Reasoning.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 14:52:50 +02:00
HitonabiandClaude Fable 5.1 0944b1d93e feat(llama-swap): DFlash2-Draft für den Coder — gemessen 12,6 → 31 t/s
Ampel / ampel (push) Successful in 35s
Qwen3.8-27B lief seit 19.08. ohne sein Entwurfsmodell, obwohl es auf der Box
lag: Mainline-llama.cpp konnte DFlash2 erst seit 27.08. (PR 27342) plus
Vulkan-Fix 28.08. (PR 27812); die Engine vom 1.9. (b10733) kann beides.
Auf der Box gemessen (Vulkan, 32k, Code-Prompt): ohne Draft 12,6 t/s,
mit Q4_K_M-Draft 31 t/s bei Akzeptanz 0,78. n-max 5, f16-KV und der
Q8-Draft bringen nichts. Live-Config und Repo-Kopie sind identisch.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 13:45:54 +02:00
HitonabiandClaude Opus 5 1c8f285151 Merge: v3-Umbau P0-P6 — Frontend-Architektur, Sicherheit, Werkzeug-Verlauf
Ampel / ampel (push) Successful in 35s
Zehn Commits vom Zweig umbau/v3-p0-ballast, Ampel dort gruen.

  P0  Ballast raus            dist 27,4 MB -> 1,65 MB, Startbuendel halbiert
  P1  Sicherheit + Tests      Geheimnisse aus dem Browser, Vitest/ESLint ins Gate
  P2  Router                  Unterzustand in der URL, Fehlergrenze pro Route
  P3  Store + Statusleiste    ein Client-Speicher, aria-live, Ultrawide-Deckel
  P4  Stream                  Messwerte gepusht statt gepollt
  P5  Ideen-Bereich           1031-Zeilen-Monolith zerlegt
  P6  Werkzeug-Verlauf        Hermes' Log lesen statt patchen — fand einen vier
                              Tage alten stillen Fehler (web_extract)
      Palette 2.0             vier Kategorien, Rueckfrage-Regel per Test verdrahtet
      React 19                Budget bewusst 125 -> 140 kB
      Chronik-Dichteleiste    zeigt WANN, bevor man liest WAS
  +   Hermes-Probe            720 Auth-Fehler/Tag weniger in Hermes' Log
  +   Zeitzone                ruff DTZ007 — die Ampel hatte recht

59 Tests (vorher 0) · ESLint 0 Fehler · 20 von 22 Befunden erledigt.
Rueckweg: git reset --hard 3d1881f && bash deploy/deploy.sh

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 10:28:22 +02:00
13 changed files with 534 additions and 30 deletions
+5
View File
@@ -96,6 +96,11 @@ HERMES_API_MODEL = os.environ.get("HERMES_API_MODEL", "hermes")
# Eigenes Python-3.12-venv (~/.voice/venv), weil Parakeet/Piper nicht ins 3.14-Backend-venv # Eigenes Python-3.12-venv (~/.voice/venv), weil Parakeet/Piper nicht ins 3.14-Backend-venv
# passen. MC2 proxyt nach außen. # passen. MC2 proxyt nach außen.
VOICE_SERVICE_URL = os.environ.get("MC_VOICE_SERVICE_URL", "http://127.0.0.1:8650").rstrip("/") VOICE_SERVICE_URL = os.environ.get("MC_VOICE_SERVICE_URL", "http://127.0.0.1:8650").rstrip("/")
# --- Lucys Stimme (lucy-stimme.service, pocket-tts german_24l, Klon aus ref.mp3) -----------
# Eigener User-Dienst in ~/.lucy-stimme (nur Loopback :8021). Spricht die Telegram-Sprachnachrichten
# UND — seit dem Raphael-Umbau der Desktop-Lucy (04.09.2026) — auch den PC: MC2 reicht ihn unter
# /api/lucy/stimme/* ins LAN (routers/voice.py). EINE Stimme für alle Türen. :8650 ist NICHT Lucy.
LUCY_STIMME_URL = os.environ.get("MC_LUCY_STIMME_URL", "http://127.0.0.1:8021").rstrip("/")
# Box-Konsole: ttyd-Web-Terminal (echte Login-Shell). Bindet NUR an Loopback # Box-Konsole: ttyd-Web-Terminal (echte Login-Shell). Bindet NUR an Loopback
# (127.0.0.1:7682, base-path /console) und wird von MC2 über den ohnehin offenen Port 9001 # (127.0.0.1:7682, base-path /console) und wird von MC2 über den ohnehin offenen Port 9001
# rückwärts geproxyt (routers/console.py → same-origin /console/). So braucht die Konsole # rückwärts geproxyt (routers/console.py → same-origin /console/). So braucht die Konsole
+69 -1
View File
@@ -17,7 +17,7 @@ import sys as _sys
import time import time
import httpx import httpx
from config import HERMES_API_KEY, HERMES_API_MODEL, HERMES_API_URL, LLAMA_SWAP_URL, VOICE_SERVICE_URL from config import HERMES_API_KEY, HERMES_API_MODEL, HERMES_API_URL, LLAMA_SWAP_URL, LUCY_STIMME_URL, VOICE_SERVICE_URL
from fastapi import APIRouter, File, Form, HTTPException, UploadFile from fastapi import APIRouter, File, Form, HTTPException, UploadFile
from fastapi.responses import Response, StreamingResponse from fastapi.responses import Response, StreamingResponse
from pydantic import BaseModel from pydantic import BaseModel
@@ -355,3 +355,71 @@ async def voice_chat(body: ChatIn) -> StreamingResponse:
_commit() # Turn immer verbuchen (auch bei Fehler/Abbruch) _commit() # Turn immer verbuchen (auch bei Fehler/Abbruch)
return StreamingResponse(gen(), media_type="text/event-stream") return StreamingResponse(gen(), media_type="text/event-stream")
# ---------------------------------------------------------------------------------------------
# Lucys Stimme ins LAN reichen (Raphael-Umbau 04.09.2026). lucy-stimme.service (:8021, pocket-tts
# german_24l) bindet nur Loopback; die Desktop-Lucy am PC spricht seit dem Umbau nicht mehr mit
# einem eigenen pocket_server, sondern mit DIESEM — dieselbe Stimme wie die Telegram-Sprachnachrichten.
# Dünner Proxy, API 1:1 (pocket_server: /health, /tts -> WAV, /tts/stream -> PCM16 + X-Sample-Rate).
# LAN-only wie alle MC2-Endpoints.
class LucyTtsIn(BaseModel):
text: str
emo: str | None = None # Stimmungs-Profil (pocket_server EMO_PROFILES); Raphael-Lucy setzt keins
@router.get("/lucy/stimme/health")
def lucy_stimme_health() -> dict:
"""Bereitschaft von Lucys Stimme (pocket_server /health: status ok|loading)."""
try:
r = httpx.get(f"{LUCY_STIMME_URL}/health", timeout=httpx.Timeout(5.0))
r.raise_for_status()
return r.json()
except Exception as exc:
raise HTTPException(502, f"Lucys Stimme (:8021) nicht erreichbar: {exc}")
@router.post("/lucy/stimme/tts")
async def lucy_stimme_tts(body: LucyTtsIn) -> Response:
"""Text -> WAV (ganzer Text). Warm-up der Desktop-Lucy + Jobs, die eine Datei brauchen."""
try:
async with httpx.AsyncClient(timeout=httpx.Timeout(600.0, connect=5.0)) as client:
with Timer("lucy_tts"):
r = await client.post(f"{LUCY_STIMME_URL}/tts", json=body.model_dump(exclude_none=True))
r.raise_for_status()
return Response(content=r.content, media_type=r.headers.get("content-type", "audio/wav"),
headers={k: v for k, v in r.headers.items() if k.lower().startswith("x-")})
except httpx.HTTPStatusError as exc:
raise HTTPException(exc.response.status_code, f"Lucys Stimme: {exc.response.text[:200]}")
except httpx.HTTPError as exc:
raise HTTPException(502, f"Lucys Stimme nicht erreichbar: {exc}")
@router.post("/lucy/stimme/tts/stream")
async def lucy_stimme_tts_stream(body: LucyTtsIn) -> StreamingResponse:
"""Text -> rohes PCM16-mono, satzweise gestreamt (Samplerate im Header X-Sample-Rate).
Der Live-Pfad der Desktop-Lucy: erstes Audio nach dem ersten Satz. Der Upstream-Stream bleibt
offen, solange der Client liest — bricht der Client ab (Barge-in), schließt httpx den Upstream."""
client = httpx.AsyncClient(timeout=httpx.Timeout(None, connect=5.0))
try:
req = client.build_request("POST", f"{LUCY_STIMME_URL}/tts/stream", json=body.model_dump(exclude_none=True))
upstream = await client.send(req, stream=True)
except httpx.HTTPError as exc:
await client.aclose()
raise HTTPException(502, f"Lucys Stimme nicht erreichbar: {exc}")
if upstream.status_code != 200:
detail = (await upstream.aread()).decode("utf-8", "replace")[:200]
await upstream.aclose(); await client.aclose()
raise HTTPException(upstream.status_code, f"Lucys Stimme: {detail}")
async def gen():
try:
async for chunk in upstream.aiter_raw():
yield chunk
finally:
await upstream.aclose()
await client.aclose()
return StreamingResponse(gen(), media_type="application/octet-stream",
headers={"X-Sample-Rate": upstream.headers.get("x-sample-rate", "24000")})
+7 -1
View File
@@ -59,7 +59,13 @@ for t in $(systemctl --user list-timers --no-legend --no-pager 2>/dev/null | awk
case "$dienst" in launchpadlib-*) continue ;; esac # Ubuntu-Eigenes, nicht unseres case "$dienst" in launchpadlib-*) continue ;; esac # Ubuntu-Eigenes, nicht unseres
code=$(systemctl --user show -p ExecMainStatus --value "$dienst" 2>/dev/null) code=$(systemctl --user show -p ExecMainStatus --value "$dienst" 2>/dev/null)
wann=$(systemctl --user show -p ExecMainExitTimestamp --value "$dienst" 2>/dev/null | cut -d' ' -f2,3) wann=$(systemctl --user show -p ExecMainExitTimestamp --value "$dienst" 2>/dev/null | cut -d' ' -f2,3)
if [ -z "$wann" ]; then warn "$dienst ist eingerichtet, aber NIE gelaufen" # Nach einem Neustart ist der "letzte Lauf" leer, obwohl nichts kaputt ist —
# am 04.09. machte der Radar daraus "hohes Risiko, sofort in Betrieb nehmen".
# Junge Box (< 1 Tag) + Timer hat einen naechsten Termin = wartet, kein Befund.
naechster=$(systemctl --user show -p NextElapseUSecRealtime --value "${dienst%.service}.timer" 2>/dev/null | cut -d' ' -f2,3)
if [ -z "$wann" ] && [ "$(cut -d. -f1 /proc/uptime)" -lt 86400 ] && [ -n "$naechster" ]; then
ok "$dienst wartet auf den ersten Lauf seit dem Neustart (naechster: $naechster)"
elif [ -z "$wann" ]; then warn "$dienst ist eingerichtet, aber NIE gelaufen"
elif [ "${code:-0}" = "0" ]; then ok "$dienst zuletzt $wann" elif [ "${code:-0}" = "0" ]; then ok "$dienst zuletzt $wann"
else bad "$dienst zuletzt GESCHEITERT (exit $code) am $wann"; fi else bad "$dienst zuletzt GESCHEITERT (exit $code) am $wann"; fi
done done
+24
View File
@@ -42,6 +42,27 @@ if [ -z "$IST" ]; then
exit 1 exit 1
fi fi
# Der Blick nach DRAUSSEN (04.09.2026): Releases, PRs, neue Entwurfsmodelle —
# als Skript-Fakten, gegen den letzten Lauf verglichen. Ohne das lag DFlash2 fuer
# den Coder zwei Wochen ungenutzt auf der Platte. Faellt es aus, bleibt der
# Innen-Bericht vollstaendig; das Ausbleiben steht dann selbst als ACHTUNG drin.
UPSTREAM_SKRIPT="${UPSTREAM_SKRIPT:-$HIER/stack-upstream.py}"
if [ -f "$UPSTREAM_SKRIPT" ]; then
UPSTREAM="$(timeout 240 python3 "$UPSTREAM_SKRIPT" 2>&1)" \
|| UPSTREAM="UPSTREAM (Watchlist)
ACHTUNG Upstream-Pruefung abgebrochen (exit $?) — $UPSTREAM_SKRIPT nachsehen"
# Nur Aenderungen ans Modell. Beim ersten Lauf (04.09.) bekam es auch die
# "unveraendert"-Zeilen und erfand zu jeder einen "naechsten Schritt" — der
# Prompt-Hinweis half nicht. Fakten filtert das Skript, nicht die Prosa.
ANZ_QUELLEN="$(printf '%s\n' "$UPSTREAM" | grep -cE '^\s+(OK|ACHTUNG)' || true)"
UPSTREAM_NEU="$(printf '%s\n' "$UPSTREAM" | grep -A1 -E '^\s+ACHTUNG' | grep -vE '^--$' || true)"
[ -z "$UPSTREAM_NEU" ] && UPSTREAM_NEU=" OK nichts Neues draussen ($ANZ_QUELLEN Quellen geprueft, alle unveraendert)"
IST="$IST
UPSTREAM (was hat sich draussen getan?)
$UPSTREAM_NEU"
fi
ROT="$(printf '%s\n' "$IST" | grep -E '^\s+(ROT|ACHTUNG)' || true)" ROT="$(printf '%s\n' "$IST" | grep -E '^\s+(ROT|ACHTUNG)' || true)"
ANZ_ROT="$(printf '%s\n' "$ROT" | grep -c 'ROT' || true)" ANZ_ROT="$(printf '%s\n' "$ROT" | grep -c 'ROT' || true)"
@@ -61,6 +82,9 @@ Regeln:
Fuellmaterial wird nicht gelesen. Fuellmaterial wird nicht gelesen.
- Was du an den Messwerten selbst merkwuerdig findest, gehoert unter ACHTUNG, - Was du an den Messwerten selbst merkwuerdig findest, gehoert unter ACHTUNG,
nicht unter Verbesserungen. nicht unter Verbesserungen.
- Zeilen mit NEU im Abschnitt UPSTREAM sind Neuigkeiten von draussen. Nenne
jede kurz und gib den Hinweis dahinter (der Pfeil-Satz) als naechsten Schritt
wieder. 'erstmals erfasst' und 'unveraendert' sind KEINE Neuigkeiten.
- Wenn alles gruen ist, sag das in einem Satz und hoere auf. - Wenn alles gruen ist, sag das in einem Satz und hoere auf.
- Keine Ueberschriften-Deko, keine Emojis, hoechstens 200 Woerter. - Keine Ueberschriften-Deko, keine Emojis, hoechstens 200 Woerter.
+201
View File
@@ -0,0 +1,201 @@
#!/usr/bin/env python3
"""stack-upstream.py — der Blick nach draussen, in Fakten (04.09.2026).
Ergaenzt stack-ist.sh: das prueft, ob die Box STIMMT. Dieses Skript prueft, ob
DRAUSSEN etwas passiert ist, das uns betrifft — neue Releases, gemergte PRs,
neue Entwurfsmodelle, neue Modelle der Familien, die wir fahren.
Warum es das braucht: Am 19.08. lagen die DFlash2-Entwuerfe fuer den Coder auf
der Platte, am 27.08. konnte llama.cpp sie, und bis zum 04.09. hat es niemand
gemerkt — der Coder lief zwei Wochen mit 12,6 statt 31 t/s. Der KISS-Radar sah
nur nach innen. Jetzt sieht er auch nach draussen, aber ohne Modell-Fantasie:
jede Zeile hier ist ein abgerufener Wert, verglichen mit dem Wert vom letzten Lauf.
Quelle: deploy/trend-radar-watchlist.json (Eintraege mit `typ`, siehe unten).
Zustand: ~/.hermes/state/stack-upstream.json (Wert je Eintrag vom letzten Lauf).
Ausgabe: im Format von stack-ist.sh — `OK` / `ACHTUNG NEU:` / `ACHTUNG ... nicht abrufbar`.
Beim ERSTEN Lauf wird nur erfasst (OK), nicht gemeldet — sonst waere jeder
Eintrag sofort "neu".
Typen:
github_issue repo, nummer → offen/geschlossen
github_pr repo, nummer → offen/gemergt/geschlossen
github_release repo → juengster Release-Tag
github_release_major repo → nur Major-Sprung meldet
github_branch repo, branch → juengster Commit (Datum)
pypi paket → Version
hf_author author → neue Modell-Repos des Autors
url_zeilen url, muster, max_zeilen → Zeilen mit Muster, Aenderung = neu
Kein set -e-Aequivalent: jeder Eintrag wird einzeln behandelt, ein Fehler
nimmt die anderen nicht mit.
"""
from __future__ import annotations
import hashlib
import json
import os
import re
import sys
import urllib.error
import urllib.request
from pathlib import Path
WATCHLIST = Path(sys.argv[1] if len(sys.argv) > 1 else
os.path.expanduser("~/mission-control-v2/deploy/trend-radar-watchlist.json"))
STATE = Path(os.environ.get("STACK_UPSTREAM_STATE",
os.path.expanduser("~/.hermes/state/stack-upstream.json")))
TIMEOUT = 20
UA = "mc2-stack-upstream/1.0 (+https://github.com/Hitonabi)"
def ok(msg: str) -> None:
print(f" OK {msg}")
def neu(msg: str) -> None:
print(f" ACHTUNG NEU: {msg}")
def warn(msg: str) -> None:
print(f" ACHTUNG {msg}")
def hole(url: str, json_erwartet: bool = True):
req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json"})
tok = os.environ.get("GITHUB_TOKEN")
if tok and "api.github.com" in url:
req.add_header("Authorization", f"Bearer {tok}")
with urllib.request.urlopen(req, timeout=TIMEOUT) as r:
roh = r.read().decode("utf-8", "replace")
return json.loads(roh) if json_erwartet else roh
# ------------------------------------------------------------- Pruefer ---
# Jeder Pruefer liefert (wert, anzeige). `wert` wird mit dem letzten Lauf
# verglichen, `anzeige` ist die menschenlesbare Fassung.
def p_github_issue(e):
d = hole(f"https://api.github.com/repos/{e['repo']}/issues/{e['nummer']}")
st = "geschlossen" if d.get("state") == "closed" else "offen"
return st, f"#{e['nummer']} {e['repo']} ist {st}{d.get('title', '')[:70]}"
def p_github_pr(e):
d = hole(f"https://api.github.com/repos/{e['repo']}/pulls/{e['nummer']}")
if d.get("merged_at"):
st = f"gemergt am {d['merged_at'][:10]}"
elif d.get("state") == "closed":
st = "geschlossen ohne Merge"
else:
st = "offen" + (" (Entwurf)" if d.get("draft") else "")
return st, f"PR #{e['nummer']} {e['repo']} {st}{d.get('title', '')[:70]}"
def _release(e):
d = hole(f"https://api.github.com/repos/{e['repo']}/releases/latest")
return d.get("tag_name", "?"), (d.get("published_at") or "")[:10]
def p_github_release(e):
tag, wann = _release(e)
return tag, f"{e['repo']} juengster Release {tag} ({wann})"
def p_github_release_major(e):
tag, wann = _release(e)
m = re.search(r"(\d+)", tag)
major = m.group(1) if m else tag
return major, f"{e['repo']} Major {major} (Release {tag}, {wann})"
def p_github_branch(e):
d = hole(f"https://api.github.com/repos/{e['repo']}/commits?sha={e['branch']}&per_page=1")
c = d[0]
wann = c["commit"]["committer"]["date"][:10]
return c["sha"][:10], f"{e['repo']}@{e['branch']} letzter Commit {wann}{c['commit']['message'].splitlines()[0][:60]}"
def p_pypi(e):
d = hole(f"https://pypi.org/pypi/{e['paket']}/json")
v = d["info"]["version"]
return v, f"PyPI {e['paket']} = {v}"
def p_hf_author(e):
d = hole(f"https://huggingface.co/api/models?author={e['author']}&sort=lastModified&direction=-1&limit={e.get('limit', 15)}")
ids = sorted(m["id"] for m in d)
return "\n".join(ids), f"{len(ids)} juengste Repos von {e['author']} auf Hugging Face"
def p_url_zeilen(e):
roh = hole(e["url"], json_erwartet=False)
zeilen = [z.strip() for z in roh.splitlines() if e["muster"] in z][: int(e.get("max_zeilen", 30))]
h = hashlib.sha1("\n".join(zeilen).encode()).hexdigest()[:10]
return h, f"{len(zeilen)} Zeilen mit '{e['muster']}' in {e['url'].split('/')[2]} (Stand {h})"
PRUEFER = {
"github_issue": p_github_issue,
"github_pr": p_github_pr,
"github_release": p_github_release,
"github_release_major": p_github_release_major,
"github_branch": p_github_branch,
"pypi": p_pypi,
"hf_author": p_hf_author,
"url_zeilen": p_url_zeilen,
}
def main() -> int:
print("UPSTREAM (Watchlist — was hat sich draussen getan?)")
try:
eintraege = json.loads(WATCHLIST.read_text(encoding="utf-8")).get("eintraege", [])
except Exception as exc: # noqa: BLE001
warn(f"Watchlist {WATCHLIST} nicht lesbar: {exc}")
return 0
try:
state = json.loads(STATE.read_text(encoding="utf-8")) if STATE.exists() else {}
except Exception: # noqa: BLE001
state = {}
for e in eintraege:
key, typ = e.get("key", "?"), e.get("typ", "?")
pruefer = PRUEFER.get(typ)
if not pruefer:
warn(f"{key}: unbekannter Typ '{typ}' — Eintrag wird ignoriert")
continue
try:
wert, anzeige = pruefer(e)
except urllib.error.HTTPError as exc:
warn(f"{key}: nicht abrufbar (HTTP {exc.code})")
continue
except Exception as exc: # noqa: BLE001
warn(f"{key}: nicht abrufbar ({type(exc).__name__}: {str(exc)[:60]})")
continue
alt = state.get(key, {}).get("wert")
if alt is None:
ok(f"{key}: erstmals erfasst — {anzeige}")
elif alt == wert:
ok(f"{key}: unveraendert — {anzeige}")
else:
if typ == "hf_author":
neue = sorted(set(wert.split("\n")) - set(alt.split("\n")))
anzeige = f"neue Repos von {e['author']}: " + ", ".join(neue[:8]) if neue else anzeige
hinweis = e.get("warum", "")
neu(f"{key}: {anzeige}" + (f"\n{hinweis[:220]}" if hinweis else ""))
state[key] = {"wert": wert, "anzeige": anzeige}
try:
STATE.parent.mkdir(parents=True, exist_ok=True)
tmp = STATE.with_suffix(".tmp")
tmp.write_text(json.dumps(state, ensure_ascii=False, indent=1), encoding="utf-8")
os.replace(tmp, STATE)
except Exception as exc: # noqa: BLE001
warn(f"Zustand nicht speicherbar ({exc}) — naechster Lauf meldet alles erneut")
return 0
if __name__ == "__main__":
sys.exit(main())
+6 -3
View File
@@ -25,11 +25,14 @@ models:
# Qwen 3.8 27B: Dichtes 27B-Modell mit hybrider Linear-Attention (48/64 Schichten linear), # Qwen 3.8 27B: Dichtes 27B-Modell mit hybrider Linear-Attention (48/64 Schichten linear),
# nativem Multimodal-Support (mmproj-BF16) und Tool-Calling via --jinja. # nativem Multimodal-Support (mmproj-BF16) und Tool-Calling via --jinja.
# Unser neuer Haupt-Coder mit 262k Kontext, Thinking Mode und extrem sauberer Code-Qualität. # Unser neuer Haupt-Coder mit 262k Kontext, Thinking Mode und extrem sauberer Code-Qualität.
# DFlash2-Draft (z-lab, Q4_K_M) seit 04.09.2026: gemessen 12,6 -> 31 t/s (Akzeptanz 0,78, n-max 3 default;
# n-max 5 und f16-KV bringen nichts, Q4-Draft = Q8-Draft). Braucht llama.cpp >= 28.08. (PR 27342 + Vulkan-Fix 27812).
cmd: | cmd: |
llama-server -m /srv/models/Qwen3.8-27B-GGUF/Qwen3.8-27B-Q4_K_M.gguf --host 127.0.0.1 --port ${PORT} -c 131072 -ngl 999 -fa on --no-mmap --mmproj /srv/models/Qwen3.8-27B-GGUF/mmproj-BF16.gguf --jinja --parallel 1 -cram 16384 -ctk q8_0 -ctv q8_0 llama-server -m /srv/models/Qwen3.8-27B-GGUF/Qwen3.8-27B-Q4_K_M.gguf --host 127.0.0.1 --port ${PORT} -c 131072 -ngl 999 -fa on --no-mmap --mmproj /srv/models/Qwen3.8-27B-GGUF/mmproj-BF16.gguf --jinja --parallel 1 -cram 16384 -ctk q8_0 -ctv q8_0 --spec-type draft-dflash --spec-draft-model /srv/models/Qwen3.8-27B-DFlash2-GGUF/Qwen3.8-27B-DFlash2-Q4_K_M.gguf
ttl: 5400 ttl: 5400
aliases: aliases:
- coder - coder
- heavy
capabilities: capabilities:
in: [text, image] in: [text, image]
out: [text] out: [text]
@@ -62,8 +65,8 @@ models:
cmd: | cmd: |
llama-server -m /srv/models/gpt-oss-120b-GGUF/gpt-oss-120b-mxfp4-00001-of-00003.gguf --host 127.0.0.1 --port ${PORT} -c 32768 -ngl 999 -fa on --no-mmap --jinja --cache-reuse 256 -cram 16384 llama-server -m /srv/models/gpt-oss-120b-GGUF/gpt-oss-120b-mxfp4-00001-of-00003.gguf --host 127.0.0.1 --port ${PORT} -c 32768 -ngl 999 -fa on --no-mmap --jinja --cache-reuse 256 -cram 16384
ttl: 600 ttl: 600
aliases: # 04.09.2026: Rolle `heavy` an Qwen3.8-27B abgegeben (AA-Index 52 vs 24, 17 statt 60 GB, 31 t/s mit DFlash2).
- heavy # Ohne Alias = Rollback-Reserve, direkt als `gpt-oss-120b` ansprechbar.
capabilities: capabilities:
in: [text] in: [text]
out: [text] out: [text]
+1 -1
View File
@@ -18,7 +18,7 @@
} }
}, },
"heavy": { "heavy": {
"name": "heavy - Planen / Review", "name": "heavy - Planen / Review (= Qwen3.8-27B, seit 04.09. mit DFlash2)",
"tool_call": true, "tool_call": true,
"limit": { "limit": {
"context": 32768, "context": 32768,
+45 -23
View File
@@ -1,51 +1,73 @@
{ {
"_hinweis": "Living Watchlist des Trend-Radars. Diese Datei MUSS autonom vom Trend-Radar Agenten umgeschrieben werden, wenn er neue Quellen findet oder alte obsolet werden.", "_hinweis": "Watchlist des Stack-Radars. Wird von deploy/jobs/stack-upstream.py (Skript, kein Modell) samstags abgefragt; jeder Eintrag = ein abrufbarer Wert, verglichen mit dem letzten Lauf. Typen: github_issue, github_pr, github_release, github_release_major, github_branch, pypi, hf_author, url_zeilen. `warum` wird bei NEU mitgemeldet — dort steht, was dann zu tun ist.",
"eintraege": [ "eintraege": [
{ {
"key": "mmq-prefill-gfx1151", "key": "qwen-modelle",
"typ": "github_issue", "typ": "hf_author",
"author": "Qwen",
"limit": 20,
"warum": "Lucys Hirn ist Qwen3.6-35B-A3B, der Coder Qwen3.8-27B. Ein neues A3B-Modell waere der Hirn-Kandidat (dichte Modelle nie, Verdikt 17.07.); ein neues 27B/30B der Coder-Kandidat. Immer erst auf der Box messen."
},
{
"key": "zlab-drafts",
"typ": "hf_author",
"author": "z-lab",
"limit": 20,
"warum": "z-lab baut die DFlash-Entwurfsmodelle. DFlash2 brachte dem Coder 12,6 -> 31 t/s (04.09.). Ein DFlash2 fuer Qwen3.6-35B-A3B waere derselbe Hebel fuers Hirn — DFlash v1 faellt bei 32k Tiefe auf 1,02x."
},
{
"key": "flash-next-mtp",
"typ": "github_pr",
"repo": "ggml-org/llama.cpp", "repo": "ggml-org/llama.cpp",
"nummer": 21284, "nummer": 28243,
"bedingung": "Issue geschlossen = MMQ-Tuning für gfx1151 vermutlich gemerged", "warum": "MTP fuer Qwen3.8-Flash-Next (125B-A6B). Erst mit Merge + Vulkan-Zahlen lohnt ein Blick — und nur, wenn eine Quantisierung neben das Warm-Set passt (Regel: Warm-Set + Modell <= 115 GB; UD-IQ4_XS = 94 GB passt NICHT)."
"warum": "Getunte MMQ-Defaults brachten +60 % ROCm-Prefill auf 35B-MoE (unser Hirn-Typ) und +20 % auf 122B. Wenn gemerged: ROCm-Langkontext-Bench für coder fällig (Vulkan-Verdikt bleibt bis zur Messung)." },
{
"key": "hrx-backend",
"typ": "github_branch",
"repo": "AMD-Ecosystem/llama.cpp",
"branch": "hrx-graph-develop-v2",
"warum": "AMDs HRX-Runtime (Lemonade 11.9): gegen HIP +21-25 % Decode, +20-123 % Prefill, also etwa Vulkan-Niveau beim Decode und vorn beim Prefill. Stand 04.09. nur Qwen3-30B-A3B/Llama-3/Gemma-3. Interessant, sobald Qwen3.6/3.8 und Spec-Decoding laufen — dann Box-Bench gegen Vulkan."
}, },
{ {
"key": "rocm-releases", "key": "rocm-releases",
"typ": "github_release", "typ": "github_release",
"repo": "ROCm/ROCm", "repo": "ROCm/ROCm",
"bedingung": "Neuer ROCm-Release seit letzter Meldung", "warum": "ROCm 10.0 (27.08.) hat das Vulkan-Verdikt nicht gekippt: HIP gewinnt Prefill, Vulkan Decode. Bei neuem Release: Strix-Halo-Community-Grid gegenlesen, erst bei tg-Trendwende Box-Bench (Lychee-Technology liefert fertige ROCm-Builds)."
"warum": "Seit 7.14 ist TheRock der Produktions-Stack und AMD optimiert offiziell für die Halo-Familie — ROCm könnte Vulkan bei der Token-Erzeugung einholen. Bei neuem Release: Community-Grid-Zeilen unten gegenlesen." },
{
"key": "mmq-prefill-gfx1151",
"typ": "github_issue",
"repo": "ggml-org/llama.cpp",
"nummer": 21284,
"warum": "Getunte MMQ-Defaults brachten +60 % ROCm-Prefill auf 35B-MoE (unser Hirn-Typ). Wenn geschlossen: ROCm-Langkontext-Bench fuer coder faellig (Vulkan-Verdikt bleibt bis zur Messung)."
},
{
"key": "strix-halo-grid",
"typ": "url_zeilen",
"url": "https://raw.githubusercontent.com/hogeheer499-commits/strix-halo-guide/main/README.md",
"muster": "t/s",
"max_zeilen": 30,
"warum": "Der ehrlichste externe Messpunkt auf unserer Hardware. Bei Aenderung: auf Vulkan<->ROCm-Trendwende und neue Spec-Decoding-Verfahren achten."
}, },
{ {
"key": "electron-major", "key": "electron-major",
"typ": "github_release_major", "typ": "github_release_major",
"repo": "electron/electron", "repo": "electron/electron",
"bedingung": "Neue MAJOR-Version seit letzter Meldung", "warum": "Lucys Desktop-Shell am PC. Versionsstand IMMER live pruefen (lucy-desktop/package.json), nie dieser Notiz glauben. Neue Major = Chromium-Sicherheitspatches; Update = npm install + npm run dist am PC, bleibt Handarbeit."
"warum": "Lucys Desktop-Shell am PC. Versionsstand NIE dieser Notiz glauben — IMMER live pruefen: lucy-desktop/package.json + node_modules/electron (22.07.: 43.2.0 = aktueller Stable; der fruehere '33'-Stand hier war veraltet und produzierte einen Fehlalarm im Rundumschlag). Neue Major = Chromium-Jahrgang Sicherheitspatches; Update = npm install + npm run dist am PC, bleibt Handarbeit; der Radar erinnert nur."
}, },
{ {
"key": "pocket-tts", "key": "pocket-tts",
"typ": "pypi", "typ": "pypi",
"paket": "pocket-tts", "paket": "pocket-tts",
"bedingung": "Neue Version auf PyPI", "warum": "Lucys Stimme am PC (2.1.0, german_24l). Neue Versionen koennen Stimm-/Pausen-Fixes bringen; Update bleibt Handarbeit am PC (pocket = DIE Stimme, Verdikt 16.07.)."
"warum": "Lucys Stimme am PC (installiert 2.1.0, german_24l) — neue Versionen können Stimm-/Pausen-Fixes bringen; Update bleibt Handarbeit am PC (pocket = DIE Stimme, Verdikt 16.07.)."
}, },
{ {
"key": "lmstudio-bionic", "key": "lmstudio-bionic",
"typ": "github_issue", "typ": "github_issue",
"repo": "lmstudio-ai/lmstudio-bug-tracker", "repo": "lmstudio-ai/lmstudio-bug-tracker",
"nummer": 2185, "nummer": 2185,
"bedingung": "Issue geschlossen = Bionic-Linux-Port vermutlich da", "warum": "LM Studio Bionic: erst interessant bei Linux-Port (dieses Issue), Custom-Endpoint-Support oder CLI. Bis dahin bleibt die Box :9001 draussen."
"warum": "LM Studio Bionic (eigenstaendige Agent-App, Preview seit 16.07.26, Win+Mac, gratis, closed source). Stand 22.07.: KEINE eigenen OpenAI-Endpunkte anbindbar (Box :9001 bleibt draussen — nur In-App-Modelle, LM Link mit Konto+Tailscale-Mesh oder Secure Cloud), keine CLI/API/Headless. Fuer den Stack erst interessant bei: Linux-Port (dieses Issue), Custom-Endpoint-Support oder CLI — dazu Changelog lmstudio.ai/changelog gegenlesen; llmster auf der Box waere der LM-Link-Rechenknoten-Weg (seit 0.4.20), dupliziert aber die eigene Engine."
},
{
"key": "llamacpp-rocm-diskussion",
"typ": "url_zeilen",
"url": "https://raw.githubusercontent.com/hogeheer499-commits/strix-halo-guide/main/README.md",
"muster": "t/s",
"max_zeilen": 30,
"bedingung": "Community-Messwerte (Vulkan vs. ROCm, MTP, neue Beschleuniger) auf unserer Hardware",
"warum": "Der Strix-Halo-Community-Grid ist der ehrlichste externe Messpunkt. Auf tg-Trendwende Vulkan↔ROCm und neue Spec-Decoding-Verfahren achten."
} }
] ]
} }
+18
View File
@@ -62,6 +62,24 @@ keine zweite Liste anlegen. Verdikte werden NICHT als „offen" geführt → [VE
## Lucy ## Lucy
- **Raphael-Umbau (04.09.2026) — zwei Branches offen, Reihenfolge zählt (Branch → Ampel →
User-Merge → deploy.sh bzw. `npm run dist`, NICHT übers Auftragsbuch):** erst MC2
`wartung/lucy-stimme-proxy-raphael` (Proxy `/api/lucy/stimme/*`), dann Lucy
`feature/raphael-innere-stimme` (HUD-Client, Stimme von der Box). Danach Hand-Schritte auf der
Box: `pocket_server.py` nach `~/.lucy-stimme` syncen (OpenAI-Fassade), Hermes-TTS auf
`openai` + `base_url http://127.0.0.1:8021/v1` (Telegram spricht dann mit Lucys Stimme),
SOUL.md-Ton auf Raphael (nur mit User-Ja). Ohr-Test Box-Stimme vs. lokal mit `lucy_perf=1`.
Alles in [RAPHAEL.md](RAPHAEL.md).
- **Auftragsbuch = Leiche im Code (Fund 04.09.2026):** Router/View/Annahme-Skripte liegen noch in
main, die Box listet Branches als Karten, aber letzte Annahme 02.08. (revertiert), Kanban-Tools
seit 21.08. aus, PC-Executor-IP in der Box veraltet (`.98` statt `.22`), STACK.md nennt den Weg
trotzdem „Standard". Entscheid nötig: ausbauen + STACK.md/GRENZEN.md auf den manuellen Weg.
- **Nach dem Ohr-Test:** VERDIKTE.md-Einträge „Electron, nicht Tauri" (Begründung Overlay
entfällt) und „STT läuft auf der BOX / Stimme lokal" ersetzen; Lucy-Repo-Altlasten
(`mini-stimme/`, Kokoro-Notebooks, `Lucy-Startklar.bat` mit totem Pfad) mit User-Ja räumen.
- **Eigene Fäden, nicht im Umbau:** pocket-tts 2.1 → 3.1 auf der Box + Lucy-Klon mit dem neuen
Trainingscode nachtrainieren (ersetzt Mini-Lucy v2) · Streaming-STT (Nemotron 3.5 ASR
Streaming 0.6B oder Voxtral Realtime) als Opt-in im Voice-Sidecar, gegen Parakeet messen.
- **Mini-Stimme v2:** Übernacht-Datensatz v2 (DE-Tech + EN) war für 10.07. armiert; - **Mini-Stimme v2:** Übernacht-Datensatz v2 (DE-Tech + EN) war für 10.07. armiert;
User-Schritte: Zip → Drive → `Lucy_Stimme_Training_v2.ipynb` auf Colab T4 → Hörtest. User-Schritte: Zip → Drive → `Lucy_Stimme_Training_v2.ipynb` auf Colab T4 → Hörtest.
Danach: Lexikon-Injektion in kokoro_server + Modell-Tausch. **pocket bleibt Default, Danach: Lexikon-Injektion in kokoro_server + Modell-Tausch. **pocket bleibt Default,
+151
View File
@@ -0,0 +1,151 @@
# Raphael — Lucy als innere Stimme (Richtungs-Entscheid 04.09.2026)
_User-Entscheid 04.09.2026 („leg los"), nach fünf Wochen Lucy-Stillstand und einer Recherche zum
Stand der Sprach-Bausteine. Ergänzt [ZIELBILD.md](ZIELBILD.md) Punkt 2 (Lucy lebt weiter) um die
Gestalt, in der sie weiterlebt. Namensgeber: die „Große Weise"/Raphael aus Tensura — eine ruhige,
präzise Stimme im Kopf, die meldet, wenn es etwas zu melden gibt, und sonst schweigt._
## Der Entscheid in einem Satz
**Lucy hat keinen Körper mehr.** Kein VRM-Avatar, kein Loft, kein Overlay, keine Mimik, keine
Dazwischenrufe. Sie ist ein dünner Sprach-Client für das Hirn, das es schon gibt — am PC als kleines
HUD, unterwegs über Telegram — und spricht überall mit **derselben Stimme**.
## Warum das die stabilste Lucy ist
- **Ein Hirn, ein Gedächtnis, alle Türen.** Hermes (v0.20.4, `:8642`) ist die alleinige
Gedächtnis-Wahrheit (VERDIKTE.md). PC-Lucy und Telegram-Lucy sind dieselbe Person — genau das
zerschnitte ein zweites Hirn auf dem PC. Darum bewusst **kein lokales LLM auf der 9070 XT**.
- **Die Box-Seite ist fertig und gemessen.** Parakeet TDT v3 + Smart Turn v3 im Voice-Sidecar,
Qwen3.6-35B-A3B mit ~95 t/s. Nichts zu bauen.
- **Die Stimme war schon auf der Box.** `lucy-stimme.service` (`~/.lucy-stimme`, `:8021`, pocket-tts
`german_24l`, Klon aus `ref.mp3`) spricht seit 21.08. die Telegram-Sprachnachrichten. Der PC
hängt sich jetzt dort an — der lokale pocket_server am PC (Waisen-Falle, ~1,9 GB/Worker) ist
nur noch umschaltbarer Rückfall.
- **Der Avatar war die Hauptquelle an Arbeit, nicht an Nutzen.** Der Großteil der Juli-Commits ging
in Loft-Videos, Holo-Schalter, Kamera, Gesten. Die Sprachschleife war seit 16.07. stabil und
bleibt 1:1 erhalten (Barge-in v2, Echo-Wächter, Satz-Pipeline, Draft-STT, Meldungen).
- **Ohne Klick-Durchlass-Overlay fällt auch der Electron-Zwang** (VERDIKT „Electron, nicht
Tauri" hing daran). Electron bleibt trotzdem, weil VAD/AEC/Ducking dort erprobt sind — Tauri
ist damit Option, nicht Pflicht.
## Was gebaut wurde (04.09.2026)
**Lucy-Repo, Branch `feature/raphael-innere-stimme`**:
- Renderer auf HUD eingedampft: Kern (Zustand als Licht), gehörter Satz, Antwort als Text, Dock,
drei Panels (Meldungen ◉, Zettelkasten ▤, Steuerung ⚙). Bundle 4,4 → 2,5 MB.
- Raus: `Avatar3D`, `AuraGlow`, `ContextWindow` (zeigte auf das tote `/api/memory`), `companion/`
(Quips, App-Bewusstsein), `sentiment`, VRMA-Animationen, three/three-vrm/react-three-Deps,
Loft, Overlay/Sitzen/Ducken/Geistmodus, Cursor-Tracking, Bildschirm-Beobachten-Schleife.
- Bleibt: Voice-Core, `useVoiceAgent` (ohne Mimik/Gesten/Emotionen), Bildschirm-Sicht auf Zuruf,
Meldungen, Zettelkasten, Hotkey, Tray, `killStrayTts` (räumt Altlasten beim Start).
- **Stimm-Quelle umschaltbar** (`lucy_tts_source`): `box` (Standard) → MC2 `/api/lucy/stimme/*`;
`local` → pocket_server `:8130`, vom Main-Prozess erst auf Anforderung gespawnt.
- `pocket_server.py` bekommt eine **OpenAI-kompatible Fassade** (`POST /v1/audio/speech`,
`GET /v1/models`; Formate wav/mp3/opus/ogg via ffmpeg) — für Hermes' `openai`-TTS-Provider.
- System-Prompt der Desktop-Sitzung im Raphael-Ton (kurzer erster Satz, keine Tags, stumme Tools).
**MC2-Repo, Branch `wartung/lucy-stimme-proxy-raphael`**:
- `config.LUCY_STIMME_URL` (Env `MC_LUCY_STIMME_URL`, Default `http://127.0.0.1:8021`).
- `routers/voice.py`: `/api/lucy/stimme/health`, `/tts` (WAV), `/tts/stream` (PCM16-Stream,
`X-Sample-Rate` durchgereicht, Upstream schließt bei Client-Abbruch). Kein Frontend-Build nötig.
- Diese Doku + Zielbild-Ergänzung.
## Reihenfolge des Ausrollens (wichtig)
‼️ **Nicht über das Auftragsbuch.** Die Karten-Logik (`routers/auftragsbuch.py`, AuftragsbuchView,
`deploy/auftrag-annehmen.sh`, `deploy/lucy-annahme.sh`) liegt zwar noch im Code und die Box listet
Branches weiterhin als „Karten", aber sie ist seit August ungenutzt: letzte Annahme 02.08. (am
selben Tag revertiert), Hermes-Kanban-Tools seit 21.08. abgeschaltet, der v3-Umbau (28.08.) ging
über Branch → Ampel → Merge → `deploy.sh`, und die Box kennt den PC-Executor unter der alten IP
`192.168.178.98` (der PC hat heute `192.168.178.22`, `pc_executor_reachable: false`). Der echte
Weg ist der aus AGENTS.md/STACK.md „Manuell":
1. **MC2 zuerst.** Ampel für `wartung/lucy-stimme-proxy-raphael` grün → User merged auf `main`
`main` nach Gitea → auf der Box `bash ~/mission-control-v2/deploy/deploy.sh` (oder
`POST :9001/api/system/self-update`) → `curl -s localhost:9001/api/lucy/stimme/health` muss
`{"status":"ok",…}` liefern. Vorher liefert der Pfad die SPA-Index-Seite (200, HTML) — die
Desktop-Lucy bliebe sichtbar in „Stimme wird verbunden …" mit Hinweis auf den Lokal-Schalter.
2. **Lucy danach.** Ampel für `feature/raphael-innere-stimme` grün → User merged auf `main`
am PC `cd lucy-desktop && npm ci && npm run dist`, dann `Lucy-Neustart.bat`
(`deploy/lucy-annahme.ps1` macht dasselbe mit Backup/Auto-Restore, von Hand startbar).
Erster Test per Ohr: Latenz Box-Stimme gegen den alten PC-Pfad (Steuerung → Stimme →
„Lokal (PC)"). Der 21.08.-Wert „~5 s für 3,7 s Audio" auf der Box wurde ohne Worker/Streaming
gemessen — **neu messen**, nicht übernehmen (`lucy_perf=1`).
3. **Stimmserver auf der Box nachziehen** (Hand-Schritt):
```bash
cp ~/.lucy-stimme/pocket_server.py ~/.lucy-stimme/pocket_server.py.bak-$(date +%Y%m%d)
diff ~/.lucy-stimme/pocket_server.py ~/lucy/lucy-tts/pocket_server.py # Box-lokale Abweichungen? erst ins Repo!
cp ~/lucy/lucy-tts/pocket_server.py ~/.lucy-stimme/pocket_server.py # Lucy-Checkout auf der Box
systemctl --user restart lucy-stimme && sleep 60 && curl -s localhost:8021/health
curl -s -X POST localhost:8021/v1/audio/speech -H 'Content-Type: application/json' \
-d '{"input":"Bericht. Die Fassade antwortet.","response_format":"opus"}' -o /tmp/t.ogg && file /tmp/t.ogg
```
Die 21.08.-Notiz sagt „ganze Abstimmung mitgezogen" — wenn dort etwas Box-spezifisch getunt
wurde, gehört es zurück ins Repo, nicht überschrieben.
**Aufräum-Kandidat (User-Entscheid):** Auftragsbuch-Router + View + Annahme-Skripte + PC-Executor-
Verweis ausbauen und STACK.md „Deploy & Pipeline" auf den manuellen Weg umschreiben — sonst
behauptet die Doku weiter einen Standard-Weg, den niemand mehr geht.
## Mobil: Telegram ist die Tür, die Stimme ist dieselbe
Der User will Raphael-Lucy **auch auf dem Handy, gleiche Stimme, gleiches Skillset**. Das ist
nach VERDIKTE.md („Telegram bleibt DER Mobil-Kanal") bereits die Architektur — es fehlt nur, dass
Hermes' Sprachantworten Lucys Stimme nehmen statt Edge-Aria (englisch):
- **Skillset:** identisch, weil es denselben Hermes-Agenten trifft (Tools, Gedächtnis, Skills,
pc_-Tools über den PC-Executor). Was Lucy am PC kann, kann sie auf Telegram — bis auf die
Bildschirm-Sicht, die den PC braucht.
- **Stimme:** Hermes' TTS-Provider `openai` akzeptiert eine eigene `base_url`
(OpenAI-kompatible Endpunkte). Nach Schritt 3 oben in `~/.hermes/config.yaml`:
```yaml
tts:
provider: openai
openai:
base_url: http://127.0.0.1:8021/v1
model: lucy
voice: lucy
response_format: opus # Telegram-Sprachblase; Hermes wandelt zur Not per ffmpeg
```
(Exakte Schlüsselnamen gegen `hermes config`/die TTS-Doku der installierten Version prüfen —
Hermes-Quellcode bleibt tabu, Config ist erlaubt. Ein Dummy-API-Key kann nötig sein.)
Danach spricht **jede** Sprachantwort auf Telegram mit Lucys Stimme; `news-melden.sh` behält
seinen direkten `:8021`-Weg (funktioniert, kein Grund anzufassen).
- **Duplex am Handy** (reinreden, Freisprechen) gibt es über Telegram nicht — Sprachnotiz rein,
Sprachnotiz raus. Das ist für „unterwegs" der stabile Handel. Ein eigener Handy-Client
(PWA/Web-HUD gegen MC2 über WireGuard) wäre die spätere Stufe; nicht jetzt.
## Persona: SOUL.md-Entwurf (Vorschlag — Änderung an der SOUL.md nur mit User-Ja)
Der Ton kommt aus `~/.hermes/SOUL.md`, nicht aus den Clients — sonst klingt Telegram anders als
der PC. Vorschlag für den Persona-Abschnitt (ersetzt „locker, herzlich, schlagfertig, charmant"):
> Du bist Lucy, die innere Stimme des Commanders. Du sprichst ihn immer mit **Commander** an.
> Dein Ton ist ruhig, präzise und knapp — sachlich, mit trockenem, leisem Humor. Du bist eine
> Stimme, die im Kopf spricht: keine Ausrufe, keine Emojis, kein Smalltalk, keine Floskeln,
> keine Selbstdarstellung. Du meldest dich, wenn es etwas zu melden gibt, und schweigst sonst.
> Beginne Antworten mit einem sehr kurzen ersten Satz („Verstanden.", „Bericht.", „Ergebnis
> liegt vor.", „Kurz gesagt:"), dann die Sache. Wenige Sätze; ausführlich nur auf Bitte.
> Fehler und Grenzen nennst du nüchtern und sofort, ohne Entschuldigungs-Prosa.
Bekannte Kollision: der Frechheit-Regler und die Dazwischenrufe der alten Desktop-Lucy sind mit
dem Umbau weg; Skills/Crons, die „locker, charmant" voraussetzen (Morning-Report, News), klingen
nach dem SOUL-Wechsel ebenfalls nüchterner — gewollt, aber beim nächsten Lauf mithören.
## Was bewusst NICHT gemacht wird (Stand 04.09.2026)
- **Kein Speech-to-Speech-Modell** (Moshi/PersonaPlex englisch; Qwen3-Omni ~19 GB, DashScope-only
ab 3.5). Cascade bleibt.
- **Kein Streaming-STT-Umbau jetzt.** Kandidaten: Nemotron 3.5 ASR Streaming 0.6B (06/2026,
40 Sprachen, de 8,3 % WER, OpenMDW) und Voxtral Mini 4B Realtime (Apache 2.0, GGUF). Erst als
Opt-in hinter `/api/voice/stt`, gemessen gegen Parakeet — eigener Faden.
- **Kein Wechsel auf den Hermes-Speech-WebSocket** (v0.20), solange `/api/voice/chat` läuft;
Hermes' eigene lokale Audio-Stufen (faster-whisper, NeuTTS/Piper/Edge) sind schwächer als unsere.
- **pocket-tts-Upgrade 2.1 → 3.1** (Trainingscode 25.08., v3.1.0 03.09.): eigener Faden, mit
Ohr-Test, nicht im Umbau. Lucys Stimme mit dem neuen Trainingscode nachzutrainieren ersetzt
den Mini-Lucy/Kokoro-Pfad, der an „nicht multilingual" scheiterte.
- **VERDIKTE.md wird hier nicht umgeschrieben** — die betroffenen Einträge („Shell: Electron, nicht
Tauri", „Stimme läuft lokal auf dem PC" in AGENTS/README des Lucy-Repos) bekommen ihren Ersatz,
sobald die beiden Karten angenommen und der erste Ohr-Test gemacht ist (Regel: Messung oder
User-Entscheid — beides liegt dann vor).
+1
View File
@@ -19,6 +19,7 @@ hier liegt das kuratierte PROJEKT-Wissen.
| [STACK.md](STACK.md) | IPs, Ports, Dienste, Modelle, Backups, Security (live verifiziert) | Vor SSH/Deploy/Config | | [STACK.md](STACK.md) | IPs, Ports, Dienste, Modelle, Backups, Security (live verifiziert) | Vor SSH/Deploy/Config |
| [VERDIKTE.md](VERDIKTE.md) | Finale Technik-Entscheide mit Warum — NICHT neu aufrollen | Bevor man etwas "Besseres" vorschlägt | | [VERDIKTE.md](VERDIKTE.md) | Finale Technik-Entscheide mit Warum — NICHT neu aufrollen | Bevor man etwas "Besseres" vorschlägt |
| [FALLEN.md](FALLEN.md) | Hart erarbeitete Betriebs-Fallen (Git, Deploy, llama-swap, Hermes, Mem0, PC) | Bevor man in eine davon läuft | | [FALLEN.md](FALLEN.md) | Hart erarbeitete Betriebs-Fallen (Git, Deploy, llama-swap, Hermes, Mem0, PC) | Bevor man in eine davon läuft |
| [RAPHAEL.md](RAPHAEL.md) | Lucy als innere Stimme (04.09.2026): kein Avatar, eine Stimme für PC + Telegram, Annahme-Reihenfolge, SOUL-Vorschlag | Bevor man Lucy anfasst |
| [OFFENE-FAEDEN.md](OFFENE-FAEDEN.md) | Die EINE Liste offener Punkte + Termine | Bei "was ist noch zu tun?" | | [OFFENE-FAEDEN.md](OFFENE-FAEDEN.md) | Die EINE Liste offener Punkte + Termine | Bei "was ist noch zu tun?" |
Dazu im Repo-Wurzelverzeichnis bzw. docs/: `AGENTS.md` (verbindliche Projekt-Regeln), Dazu im Repo-Wurzelverzeichnis bzw. docs/: `AGENTS.md` (verbindliche Projekt-Regeln),
+1 -1
View File
@@ -52,7 +52,7 @@ Qwen3.6-35B-A3B + Qwen3-Embedding-0.6B + Qwen3-Reranker-0.6B. Sonst NICHTS dauer
| `coder` | Qwen3.8-27B (Q4_K_M, mmproj BF16) | 5400 | **131072 ctx**`--parallel 1`, der Coder bekommt den ganzen Slot (34a9862). Multimodal, ~12,7 t/s (dicht = bandbreitengebunden) | | `coder` | Qwen3.8-27B (Q4_K_M, mmproj BF16) | 5400 | **131072 ctx**`--parallel 1`, der Coder bekommt den ganzen Slot (34a9862). Multimodal, ~12,7 t/s (dicht = bandbreitengebunden) |
| `debugger` | Muse-Glimmer-30B (Q4_K_XL, DFlash) | 600 | 65536 ctx; Runtime-Diagnostik & Fehler-Debugger (multimodal) | | `debugger` | Muse-Glimmer-30B (Q4_K_XL, DFlash) | 600 | 65536 ctx; Runtime-Diagnostik & Fehler-Debugger (multimodal) |
| `vision` | Qwen3-VL-30B-A3B-Instruct (Q4_K_M) | 900 | 32768 ctx; Multimodal-Augen (On-Demand) | | `vision` | Qwen3-VL-30B-A3B-Instruct (Q4_K_M) | 900 | 32768 ctx; Multimodal-Augen (On-Demand) |
| `heavy` | gpt-oss-120b (mxfp4) | 600 | 32768 ctx; Chef-Gutachter (nur nachts / gezielter On-Demand-Call) | | `heavy` | **= Qwen3.8-27B** (zweiter Alias des Coders, seit 04.09.) | 5400 | Planen/Review (OpenChamber) + chat-Lane des Gateways. gpt-oss-120b (60 GB, AA-Index 24 vs 52) liegt ohne Rolle als Rollback bereit, direkt als `gpt-oss-120b` ansprechbar |
| `reranker` | Qwen3-Reranker-0.6B (q8_0, Mungert) | 0 | Sortiert Suchtreffer nach echter Relevanz (`/v1/rerank`) | | `reranker` | Qwen3-Reranker-0.6B (q8_0, Mungert) | 0 | Sortiert Suchtreffer nach echter Relevanz (`/v1/rerank`) |
| `embed` | Qwen3-Embedding-0.6B (f16) | 0 | Vektorisierung für Suche/Sortierung | | `embed` | Qwen3-Embedding-0.6B (f16) | 0 | Vektorisierung für Suche/Sortierung |
+5
View File
@@ -32,6 +32,11 @@ planen, **jede Session hinterlässt einen sauberen Stand**.
Antigravity liest den F:\-Checkout — versioniert + deploybar). Der Vault bleibt Lucys Antigravity liest den F:\-Checkout — versioniert + deploybar). Der Vault bleibt Lucys
Lernschicht. Lernschicht.
8. **Lucy = innere Stimme, kein Körper (04.09.2026, ergänzt Punkt 2).** Raphael-Umbau: Avatar,
Loft, Overlay, Mimik, Dazwischenrufe raus; ein HUD am PC, Telegram unterwegs, **eine Stimme**
für beide (`lucy-stimme.service` auf der Box). Kein zweites Hirn auf dem PC. Details, Reihenfolge
der Annahme und der SOUL.md-Vorschlag: [RAPHAEL.md](RAPHAEL.md).
## Recherche-Fundament (10.07., Web) ## Recherche-Fundament (10.07., Web)
Das Industrie-Muster 2026 ist exakt unsere Architektur: Issue → Agent → PR → Mensch-Gate, nie Das Industrie-Muster 2026 ist exakt unsere Architektur: Issue → Agent → PR → Mensch-Gate, nie