VersaGUI-py/AGENTS.md
cjjohn 553ecc54d8 Restructure AGENTS.md to the projekt-doku standard, audit README status
AGENTS.md now follows the mandated section structure (Project Goal,
Aktuell unterstützte Architektur, Kritische Domänenregeln,
Existing-Codebase-Regel, Implementierungsdisziplin, Naming, Deferred
Work, Dokumentation und Verifikation) instead of an organically grown
set of headings. Folds in all prior technical notes (protocol
validation, network-drive build/runtime gotchas, threading rules)
under the appropriate section, and fixes a stale "no tray icon yet"
line that no longer matched the code. README gets an explicit honest
status paragraph (what's tested, what's not: no automated tests, no
prebuilt exe download, hardcoded paths).

No docs/ tree: project has no database or persistent multi-user
service, so the full doc structure isn't warranted per the standard.
2026-08-06 16:05:36 +02:00

191 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AGENTS.md
## Project Goal
Eigenständiges Begleit-Tool für das VersaPad-Makropad (Grovy311-Kontext,
nicht Teil der fremden jappel-Repos VersaGUI/VersaMCU). Zeigt die
Steuermatrix (4×5-Button-Grid + 4 Encoder) an, synchronisiert sie live mit
dem Board und kann sie komplett neu programmieren — inzwischen ein
schlankes Python-Pendant zur offiziellen VersaGUI (C#/.NET), plus ein
MCP-Server, der dieselbe Programmierung per KI-Tool-Aufruf ermöglicht.
Nutzerorientierte Einführung: [`README.md`](README.md).
## Aktuell unterstützte Architektur
**Read-only-Schicht (JSON, beide Frontends):**
- `versapad_data.py` — Decoding für Anzeige: JSON laden, HID-Keycode/
Consumer-Usage/Modifier → lesbarer Text, Grid-Geometrie
(`index = spalte*5+reihe`), `hid_key_choices()`/`consumer_choices()`.
- `server.py` — stdlib `http.server`, generiert HTML pro Request neu,
Profil-Wechsel über `?profile=0|1|2`, Auto-Reload alle 4s. Rein lesend,
kein Programmiermodus (bewusst einfach gehalten).
**Binär-/Serial-Schicht (Programmiermodus + MCP):**
- `versapad_protocol.py` — pack/unpack für `SDeviceConfig` (740B, alle 3
Profile) und `SMacroTable` (512B, 32 Slots) + CRC16 (Poly 0x1021, Init
0xFFFF), 1:1 aus den Firmware-Structs. **Gegen echtes Board validiert:**
read → unpack → pack ist byte-identisch zum Original, inkl. CRC.
- `versapad_serial.py``VersaPadLink`: liest/schreibt komplette Config +
Makros per 8-Byte-Paket-Protokoll, Board-Identifikation per VID/PID
`239A:0042`. Schreiben ist sicher im Sinne von "kann NVM nicht zerlegen"
— Firmware prüft Magic/CRC/Keycode-Bereich vor jedem Save, antwortet
sonst nur mit NACK.
- `versapad_combined.py` — Ein-Datei-Format (alle 3 Profile + Makros +
**nur lokal gespeicherte** Profilnamen), Default-Pfad
`~\OneDrive\Desktop\versapad_config_all.json`. Passt zum Wire-Protokoll:
`CONFIG_BEGIN/COMMIT` überträgt ohnehin immer den kompletten 740B-Block.
**UI:**
- `desktop_viewer.py` — Tkinter, flaches Design, drei unabhängige Modi
(Nur lesen / Live-Sync / Programmiermodus, siehe Kritische Domänenregeln),
Tray-Icon statt Taskleisten-Minimierung, Info-Button mit MCP-Doku.
- `action_dialog.py` — Bearbeiten-Dialoge (`ActionEditDialog`,
`MacroStepsDialog`) für den Programmiermodus.
**MCP-Server:**
- `versapad_mcp_server.py` — registriert als User-Scope-MCP-Server
"versapad" (`claude mcp add -s user versapad -- <python> versapad_mcp_server.py`).
Nutzt MCP-SDK v2 (Paket `mcp`, Klasse `mcp.server.mcpserver.MCPServer`
**nicht** `FastMCP` aus `mcp.server.fastmcp`, das existiert in dieser
SDK-Version nicht mehr, wurde umbenannt). `@mcp.tool()`-dekorierte
Funktionen bleiben direkt aufrufbar (kein `.fn`-Unterschied wie bei
älteren FastMCP-Versionen). Tool-Liste: siehe README oder
`MCP_INFO_TEXT` in `desktop_viewer.py`.
Vollständige Modulübersicht mit Zeilenreferenzen bei Bedarf direkt im Code
nachschlagen — die Dateien sind klein genug, dass eine separate
`docs/current-architecture.md` hier keinen Mehrwert hätte (siehe
Dokumentation und Verifikation unten für die Größeneinschätzung).
## Kritische Domänenregeln
- Geometrie: `index = spalte*5 + reihe`, Reihe 0 = oben, Reihe 4 = unten
(Firmware-Reihenfolge). Nicht raten, nicht neu herleiten.
- Encoder 0 `sw` ist auf allen 3 Profilen der Profilwechsel — nicht ohne
Rücksprache mit dem User ändern.
- Makros sind eine EINE globale 32-Slot-Tabelle, nicht pro Profil. Slot 0-19
= MX-Button-Index, Slot 20-31 = `20 + enc*3 + act_idx`. Zwei Profile, die
denselben Slot referenzieren, spielen dieselben Schritte ab.
- Ein Makro-Schritt mit `keycode=0` beendet die Sequenz (Firmware-Konvention)
— keine Lücken vor dem letzten belegten Schritt lassen.
- Makro-Schritte erlauben nur Strg/Shift/Alt als Modifier, kein Win (passend
zum Original-`ActionDialog.cs`-Verhalten).
- Profilnamen leben NUR lokal in `versapad_config_all.json`
(`profile_names`) — die Firmware-Structs haben keinen Platz für einen
String (Header exakt 32B, jedes Profil exakt 236B, alles verplant). Sie
landen nie aufs Board, egal welcher Schreibpfad benutzt wird.
- Der COM-Port ist exklusiv. Live-Sync und Programmiermodus schalten sich
gegenseitig aus (ein `VersaPadLink` kann nicht von zwei Konsumenten
gleichzeitig genutzt werden); VersaGUI läuft als Tray-App dauerhaft im
Hintergrund weiter, auch wenn nur ihr Konfigurationsfenster geschlossen
wird — für Parallelbetrieb mit diesem Tool muss sie über ihr eigenes
Tray-Menü ("Beenden") wirklich beendet werden.
- Programmiermodus-Änderungen werden bei jeder Bearbeitung automatisch in
`versapad_config_all.json` gespeichert (nicht erst bei explizitem
"Datei speichern"). Der Nur-Lese-Modus bevorzugt dieselbe Datei, falls
vorhanden, und fällt sonst auf die klassischen `versapad_config{1,2,3}.json`
zurück — beide Ansichten müssen dieselbe Quelle zeigen, sonst wirkt eine
Bearbeitung "verschwunden".
- HID-Tasten-Auswahl im Programmiermodus ist ein Dropdown, kein
Tastendruck-Capture (bewusst — kein WinAPI-Hook, um keinen AV-Fehlalarm
wie bei den Fensterverstecktricks in anderen Projekten zu riskieren).
- Zeichentasten-Labels zeigen eine US-Layout-Näherung, nicht das tatsächlich
aktive Windows-Tastaturlayout (die echte VersaGUI löst das über
`GetKeyNameText()`, das bilden wir ohne WinAPI-Call nicht nach).
- Tk-Aufrufe (`self.after()`, Widget-Konfiguration) NIE direkt aus einem
Fremdthread (Serial-Thread, pystray-Thread) — hat in einer früheren
Version einen stillen Absturz verursacht. Threads legen Ergebnisse nur in
eine `queue.Queue`, der Main-Thread holt sie per `after()`-Polling ab.
- `.exe` (PyInstaller) läuft NICHT vom Netzlaufwerk aus (`Z:\Git\...`,
SMB-Share) — Windows blockiert das Nachladen der `_internal`-DLLs von
einem Netzwerkpfad ohne jede Fehlermeldung. Bauen scheitert dort zusätzlich
an Tcl/Tk-`tzdata`-Pfadlängen. `build_and_deploy.ps1` kopiert den
Quellcode deshalb zuerst nach `%TEMP%`, baut nur dort, deployt nach
`%LOCALAPPDATA%`.
- `--onedir`, nicht `--onefile` beim PyInstaller-Build — Single-File-Bundles
lösen öfter AV-Fehlalarme aus (sehen strukturell wie ein Packer aus).
## Existing-Codebase-Regel
Es gibt bereits eine Codebasis mit validierter, gegen die echte Firmware
getesteter Logik (Binärformat, CRC, Protokoll). Nicht blind neu raten oder
umschreiben. Vor größeren Änderungen am Binärformat/Protokoll immer gegen
die Firmware- und GUI-Quellen abgleichen, nicht aus dem Gedächtnis
rekonstruieren:
- `VersaGUI/src/ActionDialog.cs` (HidKeyName, s_consumer, Modifier-Bits)
- `VersaGUI/src/Protocol.cs` (Paket-IDs, Chunk-Größen)
- `VersaMCU/src/config/nvm_config.h` + `.cpp` (SDeviceConfig-Layout, CRC)
- `VersaMCU/src/config/action.h` (SAction, ActionType-Enum-Werte)
- `VersaMCU/src/config/macro_config.h` + `.cpp` (SMacroTable-Layout)
- `VersaMCU/src/CButton.h` (LEDAnim-Enum-Werte)
- `VersaMCU/src/CMainController.cpp` (welche Commands die Firmware
*tatsächlich* behandelt — `Protocol.cs` definiert mehr Konstanten als
zwingend implementiert sind, immer hier gegenchecken)
Frühere falsche Annahme, die hier stand: Makros seien nur per SWD/JTAG
schreibbar. Falsch — `USB_CMD_MACRO_BEGIN/DATA/COMMIT` in
`CMainController.cpp` sind normal über USB implementiert. Korrigiert, auch
im `versapad`-Skill (`~/.claude/skills/versapad/SKILL.md`).
## Implementierungsdisziplin
In Phasen arbeiten, nicht mehrere unabhängige Features in einem Rutsch ohne
Zwischenverifikation bauen. Vor jeder Änderung am Binärformat/Protokoll:
gegen ein echtes Board testen (read → unpack → pack → Vergleich auf
Byte-Identität), nicht nur gegen Beispieldaten. Vor jedem Schreibvorgang
aufs Board: erst mit unveränderten Daten testen (Identity-Write), bevor
echte Änderungen geschrieben werden.
## Naming
Code-Identifier englisch (Python-Konvention: `pack_config`, `read_macros`,
`ActionEditDialog`). UI-Text, Kommentare und Docstrings deutsch (Projekt-
und User-Konvention). Domänenbegriffe aus der Firmware direkt übernehmen,
nicht neu erfinden: `profile`, `action`, `led`, `slot`, `macro`, `encoder`,
`chunk`. Keine generischen Namen wie `data`/`item`/`entry`, wo eine
Bedeutung existiert — Ausnahme: `data` als Feldname ist durch die Firmware
selbst vorgegeben (`SAction.data`), dort beibehalten statt umzubenennen.
## Deferred Work
- Volle `docs/`-Baumstruktur (siehe Dokumentation und Verifikation unten —
Projektgröße rechtfertigt das aktuell nicht, kein DB-/API-Dienst)
- Board-seitiges Umschalten des aktiven Profils per Button in der GUI —
explizit vom User abgelehnt ("lass uns weg"), Live-Sync bleibt read-only
- Profilnamen aufs Board schreiben — technisch unmöglich (kein Platz im
Firmware-Struct), bleibt lokal
- Tastendruck-Capture statt Dropdown im Programmiermodus — bewusst
vermieden (WinAPI-Hook-Risiko)
- Hintergrund-Thread für "Vom Board laden"/"Zum Board übertragen" — laufen
aktuell synchron im UI-Thread (kurzzeitiges Einfrieren möglich)
- Vorgefertigte `.exe` im Repo/als Release-Asset — bewusst nicht committet
(Build-Artefakt), Anleitung zum Selbstbauen steht in `README.md`
Nicht an diesen Punkten arbeiten, ohne dass der User es explizit anfragt.
## Dokumentation und Verifikation
- `README.md` ist der Einstiegspunkt (Installation, Nutzung, Architektur-
Überblick).
- `AGENTS.md` (diese Datei) ist die agentenseitige Quelle der Wahrheit für
Domänenregeln und Architekturgrenzen — jede Session aktualisieren, die
daran etwas ändert oder etwas Wichtiges lernt.
- Größeneinschätzung nach Projekt-Dokumentationsstandard: kleines/mittleres
Tool ohne eigene Datenbank und ohne persistenten API-Dienst (der
Browser-Server ist ein einfacher lokaler Lese-Viewer, kein
Mehrbenutzer-Backend) → `README.md` + `AGENTS.md` sind Pflicht und
vorhanden, ein voller `docs/`-Baum ist nicht angemessen.
Prüfungen vor einem Commit an Binärformat/Protokoll:
```bash
python -m py_compile *.py
```
Danach ein Live-Testskript gegen ein angeschlossenes Board laufen lassen
(read → unpack → pack → Bytevergleich, siehe Existing-Codebase-Regel) —
es gibt keine automatisierten Unit-Tests dafür, die Verifikation läuft
manuell/interaktiv pro Session.
Committen: prägnante Commit-Message je abgeschlossenem, verifiziertem
Arbeitspaket. Nach jedem Push: alle bekannten Remotes prüfen (`origin` auf
GitHub, `jappel` auf git.jappel.io) — beide müssen synchron bleiben, siehe
Speicher-Notiz "Multi-Remote-Repos synchron halten".