20 KiB
Hugin lokal testen
Schritt für Schritt: Demo-Server starten, Pakete in ein Test-Repo holen, als Autor ein Paket ausprobieren, die automatischen Tests laufen lassen und die Funktionen der Weboberfläche und des CLI durchgehen (Checkliste in Abschnitt 5).
Voraussetzungen: uv, Go ≥ 1.26, zip, curl; für Schritt 2, 3 und 5 außerdem
OpenCode (vorrangig) und/oder Claude Code; für die Browser-Prüfungen Google Chrome. Alle Pfade gehen vom Hugin-Repo aus (hier ~/repos/dev/hugin).
1. Demo-Server mit Beispieldaten
cd ~/repos/dev/hugin
scripts/demo.sh # http://127.0.0.1:8080, Keys stehen in .demo/keys.txt
scripts/demo.sh --neu # Beispieldaten verwerfen und neu anlegen
Im Browser mit einem Key aus .demo/keys.txt anmelden:
| Key | Rolle | Was ausprobieren |
|---|---|---|
| Bert Prüfer | Prüfer | unter „Prüfungen“ wartet pub-munin-nutzen 1.5.0 |
| Anna Autorin | Autorin | Pakete anlegen und hochladen |
| Shop-Admin | Tenant-Admin | Projekte, Personen und Keys anlegen |
demo-admin |
Plattform-Admin | Systemseite, Audit, alle Tenants |
Online-Hilfe: http://127.0.0.1:8080/help · API-Doku: http://127.0.0.1:8080/api/docs
2. Pakete in ein Test-Repo holen
In einem zweiten Terminal, während der Server läuft:
cd ~/repos/dev/hugin/cli && go build -o dist/hugin ./cmd/hugin
export PATH=~/repos/dev/hugin/cli/dist:$PATH # kein alias: OpenCode und Claude Code sehen nur den PATH
mkdir -p /tmp/test-repo && cd /tmp/test-repo && git init -q
export HUGIN_KEY=<Key „Shop CI“ aus .demo/keys.txt>
hugin init --server http://127.0.0.1:8080 --project api
In .hugin.yaml Werkzeuge und Pakete eintragen:
tools: [claude, opencode] # fest eintragen: „auto“ erkennt im leeren Repo nichts Passendes
packages:
- pub-munin-nutzen # Skill
- pub-hausregeln # Regeln
- pub-release-notiz # Befehl mit Argumenten
- pub-code-review # Subagent
pub-munin-anbindung (MCP) kommt als Pflichtpaket von selbst mit.
hugin sync # schreibt die Dateien, legt hugin.lock an
hugin status # Abos, Versionen, erkannte Werkzeuge
hugin check # ändert nichts; Rückgabewert 1, wenn etwas zu tun ist
Dann im Werkzeug ausprobieren, z. B.:
opencode # oder: claude
> /pub-release-notiz 2.0 Kunden
Was sich zu testen lohnt:
- Eine verwaltete Datei von Hand ändern, dann
hugin sync→ Befund „Handänderung“;hugin sync --overwritesetzt sie zurück. - Als Bert
pub-munin-nutzen 1.5.0freigeben, dannhugin check(meldet die neue Version) undhugin sync. - Ein Paket aus
packagesentfernen undhugin sync→ seine Dateien verschwinden. - Claude Code fragt beim ersten Start, ob es den MCP-Server aus
.mcp.jsonnutzen darf.
3. Als Autor ein Paket ausprobieren
cd /tmp
export HUGIN_KEY=<Key von Anna Autorin> HUGIN_SERVER=http://127.0.0.1:8080
hugin new skill pub-mein-test
In pub-mein-test/hugin.yaml mindestens owner: kern und eine echte description
eintragen, in SKILL.md den Inhalt. Format und Beispiele: Hilfe → Quellformat.
hugin validate pub-mein-test # Linter und Vorschau je Werkzeug, speichert nichts
cd /tmp/test-repo
hugin try ../pub-mein-test # ins Repo installieren, ohne hugin.lock zu ändern
opencode # ausprobieren (oder claude)
hugin try --remove # wieder aufräumen
cd /tmp && hugin upload --submit pub-mein-test # hochladen und zur Prüfung einreichen
Danach als Bert im Browser unter „Prüfungen“ freigeben.
Linter ausprobieren:
| Änderung | Meldung |
|---|---|
description aus der Vorlage stehen lassen |
H003 (Fehler): noch der Platzhalter |
unter extra.opencode z. B. temperature: 0.1 bei einem Skill |
H020 (Fehler): Feld unbekannt |
extra.claude.disable-model-invocation: true |
H023 (Hinweis): wirkt in OpenCode 1 nicht |
| „nutze Read“ im Text | H021 (Hinweis): neutral formulieren |
4. Automatische Tests
| Befehl | Prüft | Kosten |
|---|---|---|
cd server && uv run pytest |
Server: Linter, Übersetzer, API, Web, MCP, Tenants | frei |
scripts/postgres-test.sh |
dieselbe Suite gegen PostgreSQL (Docker) | frei |
cd cli && go test ./... |
CLI, gegen die goldenen Bundles des Servers | frei |
scripts/smoke-test-local.sh |
ganzer Ablauf Server → CLI, ohne echte Werkzeuge | frei |
scripts/stage0.sh |
wie OpenCode die Dateien liest, ohne Modellaufruf | frei |
uv run --no-project --with websockets --with httpx python scripts/csp/web_browser.py /tmp/shots |
Weboberfläche in Chrome: CSP-Verstöße je Seite, Bildschirmfotos | frei |
uv run --no-project --with websockets --with httpx python scripts/csp/web_actions.py |
Weboberfläche in Chrome bedienen: Topbar, Live-Suche, Kopieren, Rückfragen, Formulare, Editor, Tabs | frei |
OPENCODE_MODEL=openai/gpt-6-luna scripts/tool-smoke-test.sh |
echtes Claude Code und OpenCode, schreibt COMPATIBILITY.md |
ca. 30 Modellaufrufe |
Reihenfolge: erst die Server-Tests, dann die CLI-Tests (die CLI testet gegen die Bundles, die der Server erzeugt).
Optionen für tool-smoke-test.sh:
| Variable | Wirkung |
|---|---|
TOOLS=opencode |
nur ein Werkzeug prüfen |
CLAUDE_MODEL=sonnet |
anderes Modell für Claude Code (Standard haiku) |
OPENCODE_MODEL=anbieter/modell |
Modell für OpenCode; ohne Angabe sein Standard |
KEEP=1 |
Arbeitsordner und Logs bleiben zum Nachsehen |
OUT=/pfad/datei.md |
Ergebnis woandershin statt nach COMPATIBILITY.md |
OpenCode braucht dafür einen Anbieter-Zugang (opencode providers login); die
kostenlosen Modelle lehnen opencode run ab.
5. Checkliste: Funktionen von Hand durchgehen
Server aus Abschnitt 1 und Test-Repo aus Abschnitt 2. Jede Zeile: was tun, was erwartet
wird. Was die Browser-Prüfung (web_actions.py) schon abdeckt, ist mit ⚙ markiert; von
Hand lohnt es trotzdem einmal, um das Verhalten zu kennen.
5.1 Weboberfläche: überall
| Schritt | Erwartung |
|---|---|
| Fenster schmal ziehen oder Handyansicht (Chrome: F12 → Gerätesymbol) | Topbar oben mit ☰, „Hilfe“, Hell/Dunkel, „Abmelden“; nichts abgeschnitten; „Programm hugin“ steht dann im Menü ⚙ |
Lange Seite (als demo-admin „Tenants, Projekte, Keys“) ganz nach unten scrollen |
Topbar mit „Abmelden“ bleibt sichtbar, die Sidebar bleibt stehen ⚙ |
| Mond/Sonne in der Topbar | Hell/Dunkel wechselt |
| Hilfe → „Arten von Paketen“ | jede Art erklärt (Skill, Regeln, Befehl, Subagent, MCP, Hook) mit „Welche Art passt?“ |
| Auf einer Paketseite das Abzeichen der Art (z. B. „Skill“) anklicken | führt zu „Arten von Paketen“ |
5.2 Als Shop CI (Team)
| Schritt | Erwartung |
|---|---|
| Katalog: ins Suchfeld „haus“ tippen | Liste filtert ohne Enter, Suche steht in der URL ⚙ |
| Katalog: Spalte „Paket“ anklicken | sortiert (nur, solange alles auf eine Seite passt) |
Paket pub-munin-nutzen → „Im Repo nutzen“ → „Kopieren“ |
Meldung „Kopiert“; in der Zwischenablage packages: mit dem Paket ⚙ |
Version 1.4.0 öffnen, Tab „Inhalt“ anklicken, dann ← → Pos1 Ende |
Tabs wechseln per Tastatur ⚙ |
| „Mein Projekt“ | Repos gruppiert; Filter „Alle“ / „Mit neuerer Version“; „Gemeldet“ als relative Zeit („vor 2 Tagen“), genaue Zeit im Tooltip |
5.3 Als Bert (Prüfer) und Carla (Prüferin + Tenant-Admin)
| Schritt | Erwartung |
|---|---|
| „Prüfungen“ | pub-munin-nutzen 1.5.0 mit „eingereicht vor …“ |
| Version öffnen → „Prüfen“ → ohne Kommentar „Zurückgeben“ | Browser verlangt einen Kommentar, nichts wird abgeschickt ⚙ |
| Mit Kanal „stabil“ freigeben | zurück in „Prüfungen“; danach meldet im Test-Repo hugin check die neue Version |
| Danach als Shop-Admin „Überblick“ → Karte „Veraltete Installationen“ | springt zur Tabelle der Repos mit alter Version |
Rechte-Paket: als Anna eine Skill-Version mit extra: {claude: {allowed-tools: [Bash]}} hochladen und einreichen, Bert gibt frei |
Bert sieht im Dialog kein Kanal-Feld, sondern „Den Kanal wählt die letzte nötige Freigabe“; danach sieht Carla in „Prüfungen“ „Freigaben 1 von 2“ und „Tenant-Admin nötig“ |
| Carla gibt frei | Kanal-Feld mit Hinweis zum Risiko; danach freigegeben |
5.4 Als Anna (Autorin)
| Schritt | Erwartung |
|---|---|
| „Hochladen“ → „direkt im Browser anlegen“ | ID ist mit pub- vorausgefüllt |
Version pub-munin-nutzen 1.4.0 → „Neue Version auf dieser Basis“ |
Editor öffnet mit 1.4.1 |
| Im Editor Tab drücken; Esc und dann Tab | Tab rückt zwei Leerzeichen ein; Esc+Tab springt zum nächsten Feld ⚙ |
| Etwas ändern und die Seite verlassen | Browser warnt vor ungespeicherten Änderungen ⚙ |
In SKILL.md $1 schreiben und speichern |
Linter lehnt ab (H010), der Dateiname im Befund springt zur Datei |
Alle Dateien unverändert speichern (nur changes ausfüllen) |
Entwurf 1.4.1 mit denselben Dateien; nichts geht verloren |
ZIP mit hugin.yaml (kind: hook) hochladen |
klare Ablehnung H008 „Hooks kommen mit Stufe 5“, kein Serverfehler |
| „Zur Prüfung einreichen“ | Rückfrage „Danach lässt sich die Version nicht mehr ändern“ |
5.5 Als Shop-Admin (Verwaltung)
| Schritt | Erwartung |
|---|---|
| „Neuer Key“ → Art umschalten | Projekt-Key: nur Feld „Projekt“ (Pflicht); Integrations-Key: nur „Nur für diese Projekte“ ⚙ |
| Rollen ansehen | lesbare Namen („Autor“, „Prüfer (öffentlich)“, „Tenant-Admin“) mit Tooltip |
| Key anlegen → „Kopieren“ | Key in der Zwischenablage; er wird nur dieses eine Mal angezeigt |
| „Widerrufen“ bei einem Key | Rückfrage; „Abbrechen“ ändert nichts ⚙ |
Als demo-admin: Tenant „plattform“ → Person „Sperren“; Pflichtpaket „Keine Pflicht mehr“ |
jeweils Rückfrage (das Pflichtpaket gilt für alle Tenants, nur der Plattform-Admin kann es lösen) |
| Tabelle „Keys“ | „Zuletzt genutzt“ als „vor …“ |
Als demo-admin „Audit“ → Aktion „Keys“ wählen |
Liste filtert sofort; ab 50 Einträgen bleibt der Filter beim Blättern („Ältere“) erhalten ⚙ |
5.6 CLI im Test-Repo (OpenCode zuerst)
| Schritt | Erwartung |
|---|---|
Frisches Repo, hugin sync |
opencode.json beginnt mit "$schema": "https://opencode.ai/config.json"; opencode debug config läuft ohne Fehler |
In .hugin.yaml tools: [opencode], dann hugin sync |
Skills unter .opencode/skills/; kein .claude/, keine .mcp.json, kein Block in CLAUDE.md; opencode debug skill findet den Skill |
Zurück auf tools: [claude, opencode], hugin sync |
Skills wandern nach .claude/skills/, .opencode/skills/ ist leer |
unset MUNIN_KEY; hugin sync |
Warnung: pub-munin-anbindung braucht die Umgebungsvariable MUNIN_KEY; sie ist nicht gesetzt … |
export MUNIN_KEY=x; hugin sync |
keine Warnung mehr |
unset MUNIN_KEY; hugin check; echo $? |
Warnung, aber Rückgabewert 0 (CI ohne Keys bleibt grün) |
In opencode.json unter mcp von Hand "jira": { "url": "https://jira.intern/mcp" } eintragen, dann hugin check; echo $? |
„OpenCode lehnt die Konfiguration ab“ mit mcp.jira, Rückgabewert 1, Text „das kann hugin sync nicht“ |
Eintrag reparieren ("type": "remote", "enabled": true), hugin check |
„Alles aktuell.“ |
opencode im Repo starten, /pub-release-notiz 2.0 Kunden |
Befehl läuft; Regeln aus pub-hausregeln werden beachtet |
In opencode.json einen Tippfehler wie "modell": "x" |
wird nicht gemeldet: OpenCode 1.19.3 nimmt unbekannte Felder hin |
5.7 Agent installiert über Hugins MCP-Endpunkt (OpenCode)
Frisches Test-Repo, damit nichts vom Abschnitt 2 stört:
mkdir -p /tmp/mcp-repo && cd /tmp/mcp-repo && git init -q
export HUGIN_KEY=<Key „Shop CI“ aus .demo/keys.txt>
export MUNIN_KEY=x # nur gegen die Warnung; Munin selbst gibt es in der Demo nicht
hugin init --server http://127.0.0.1:8080 --project api
sed -i '' 's/^tools: auto/tools: [opencode]/' .hugin.yaml
hugin sync # nur das Pflichtpaket pub-munin-anbindung
In opencode.json unter "mcp" Hugin selbst als MCP-Server eintragen (von Hand; Hugin
lässt diesen Eintrag in Ruhe):
"hugin": {
"type": "remote",
"url": "http://127.0.0.1:8080/mcp",
"enabled": true,
"headers": { "Authorization": "Bearer {env:HUGIN_KEY}" }
}
| Schritt | Erwartung |
|---|---|
opencode mcp list |
hugin steht auf „connected“ (munin verbindet in der Demo nicht, das ist erwartet) |
hugin check |
„Alles aktuell.“ (OpenCode akzeptiert den Eintrag) |
which hugin in derselben Shell, aus der du opencode startest |
zeigt …/cli/dist/hugin; sonst findet der Agent hugin sync nicht (Abschnitt 2: PATH, kein alias) |
opencode starten: „Gibt es in Hugin einen Befehl für Release-Notizen?“ |
ruft search_packages auf, nennt pub-release-notiz |
| „Zeig mir, was pub-release-notiz macht, ohne es zu installieren.“ | ruft get_package auf, erklärt den Inhalt; im Repo ändert sich nichts (git status) |
| „Richte pub-release-notiz dauerhaft in diesem Repo ein.“ | trägt pub-release-notiz in .hugin.yaml ein und führt hugin sync aus (OpenCode fragt vorher nach Erlaubnis für den Befehl); schreibt nicht selbst nach .opencode/commands/ |
Danach hugin status und cat hugin.lock |
pub-release-notiz steht in beiden; die Datei .opencode/commands/pub-release-notiz.md hat Hugin geschrieben |
OpenCode neu starten, /pub-release-notiz 2.0 Kunden |
der Befehl läuft |
Als Anna eine neue Version von pub-release-notiz hochladen, Bert gibt frei; dann hugin check |
meldet die neue Version (das geht nur, weil hugin sync installiert hat) |
Gegenprobe ohne hugin im PATH (z. B. env PATH=/usr/bin:/bin opencode): Der Agent
soll melden, dass hugin fehlt, und nichts selbst schreiben. Schreibt er die Datei
doch selbst, fehlt pub-release-notiz in hugin.lock, und das nächste hugin sync
meldet „Datei gibt es schon, sie stammt nicht von Hugin (Konflikt)“. Dann bitte Modell
und Wortlaut notieren, das wäre ein Befund. Aufräumen: hugin sync --overwrite.
Der automatische Test dazu: scripts/tool-smoke-test.sh, Prüfungen „Installieren auf Bitte“ und „Ohne hugin nichts schreiben“.
5.8 Demo und Betrieb
| Schritt | Erwartung |
|---|---|
scripts/demo.sh mit einer Datenbank aus einem alten Stand |
statt Traceback: „Migration gescheitert …“ mit dem Hinweis auf --neu |
cd server && uv run pytest tests/test_migration.py nach einer Änderung an 0001_initial_tables.py |
Fehler „ausgelieferte Migrationen nie ändern, sondern eine neue anlegen“ |
5.9 Lokaler MCP-Server (Python)
Das Beispiel pub-zeit-lokal braucht nur die Standardbibliothek. Als Anna im Test-Repo
aus Abschnitt 3 (mit tools: [opencode] oder [claude, opencode]):
export HUGIN_MCP_HOME=/tmp/hugin-mcp ZEIT_ZONE_HINWEIS=test # Ablage zum Wegwerfen
hugin try ~/repos/dev/hugin/contract/examples/packages/pub-zeit-lokal/1.0.0
| Schritt | Erwartung |
|---|---|
Ausgabe von hugin try |
„installiere pub-zeit-lokal 1.0.0 (lokaler Server) nach /tmp/hugin-mcp/…“ |
ls -a /tmp/hugin-mcp/pub-zeit-lokal/1.0.0 |
zeit_server.py, .venv, .hugin-install.json |
grep -A6 zeit opencode.json |
"command": ["hugin", "mcp", "run", "pub-zeit-lokal"], kein Pfad |
opencode mcp list |
zeit connected |
| in OpenCode: „Rufe das Werkzeug zeit auf“ | Uhrzeit mit UHR-4711 (test) |
rm -rf /tmp/hugin-mcp, dann opencode mcp list |
zeit failed; hugin mcp run pub-zeit-lokal sagt „nicht installiert; im Repo hugin sync ausführen“ |
hugin try erneut |
installiert wieder |
hugin try --remove, dann hugin mcp prune --dry-run |
„würde löschen pub-zeit-lokal 1.0.0“ |
mkdir -p /tmp/hugin-mcp/eigener && hugin mcp prune |
löscht nur das Hugin-Paket; eigener bleibt |
Freigabe und Verteilung: als Anna hugin upload --submit (persönlicher Key nötig, H043
beim Projekt-Key), Risiko „Skripte“, also zwei Freigaben (Bert und Carla). Die
Versionsseite zeigt „Lokaler Server“ mit Ablage. Danach im Repo pub-zeit-lokal unter
packages eintragen und hugin sync; hugin check meldet, wenn der Server auf dem
Rechner fehlt.
Mit Abhängigkeiten: requirements.txt mit Hashes erzeugen (Hilfe → Quellformat,
uv pip compile --universal --generate-hashes). pip nimmt den Index aus der
pip.conf; zum Test einen anderen Index: PIP_CONFIG_FILE=/tmp/pip.conf. Ohne Hash
lehnt der Linter mit H037 ab.
5.10 OpenCode-Plugin
Das Beispiel pub-specht-plugin gibt OpenCode das Werkzeug specht_marke. Als Anna im
Test-Repo (tools: [opencode] oder [claude, opencode]):
hugin validate ~/repos/dev/hugin/contract/examples/packages/pub-specht-plugin/1.0.0
hugin try ~/repos/dev/hugin/contract/examples/packages/pub-specht-plugin/1.0.0
| Schritt | Erwartung |
|---|---|
Ausgabe von hugin validate |
Risiko: permissions, Kompatibilität: opencode-only, keine Fehler |
find .opencode/plugins |
pub-specht-plugin.ts und pub-specht-plugin/index.ts, …/lib/marke.ts; nichts unter .claude/ |
opencode debug config | grep -A2 '"plugin"' |
…/.opencode/plugins/pub-specht-plugin.ts |
| in OpenCode: „Rufe das Werkzeug specht_marke auf“ | SPECHT-5127 |
dasselbe mit opencode --pure |
Werkzeug unbekannt (so gewollt) |
git status |
.opencode/plugins/… neu; node_modules, package.json unter .opencode/ nicht (eigene .gitignore von OpenCode) |
in index.ts import _ from "lodash" ergänzen, hugin validate |
H039 |
targets auf [claude, opencode], hugin validate |
H038 |
hugin try --remove |
Ordner und Startdatei weg |
Freigabe: hugin upload --submit, dann Bert und Carla (Tenant-Admin); mit Bert und
Dora allein bleibt es bei „Tenant-Admin nötig“. Danach abonnieren und hugin sync.
5.11 Windows (von Hand)
Auf einem Windows-Rechner mit Python (Starter py), OpenCode und Zugang zu Hugin.
Programm bauen auf dem Mac: cd cli && GOOS=windows GOARCH=amd64 go build -o dist/hugin.exe ./cmd/hugin,
hugin.exe in einen Ordner im PATH legen. In PowerShell:
| Schritt | Erwartung |
|---|---|
hugin init …, .hugin.yaml wie in Abschnitt 2 mit tools: [opencode], hugin sync |
Dateien unter .opencode\…, keine unter .claude |
opencode debug skill > s.txt; opencode agent list; opencode mcp list |
Skill, Subagent, MCP wie unter macOS |
hugin try …\pub-zeit-lokal\1.0.0 (mit $env:ZEIT_ZONE_HINWEIS="test") |
installiert nach %USERPROFILE%\.local\share\mcp\pub-zeit-lokal\1.0.0, venv unter .venv\Scripts |
opencode mcp list |
zeit connected |
| in OpenCode das Werkzeug zeit aufrufen | Antwort mit UHR-4711, Umlaute korrekt |
| aus einem Unterordner des Repos starten | lokaler Server verbindet trotzdem |
ohne py, nur python aus python.org im PATH |
wird gefunden; nur der Store-Platzhalter python.exe: Meldung „kein Python gefunden“ |
$env:HUGIN_PYTHON="C:\Pfad\python.exe" |
wird genommen |
Paket mit requirements.txt, pip.ini unter %APPDATA%\pip\ mit Artifactory |
pip installiert aus dem Artifactory |
hugin mcp prune |
wie unter macOS |
Repo unter einem langen Pfad (> 200 Zeichen), dann hugin sync |
Befund notieren, falls Windows-Pfadgrenze greift |
hugin try …\pub-specht-plugin\1.0.0, OpenCode neu starten, Werkzeug specht_marke aufrufen |
SPECHT-5127 |
hugin-install.ps1 mit einem Paket mit lokalem Server |
Warnung „ist ein lokaler MCP-Server; installieren mit dem Programm hugin“, sonst läuft alles durch |
Befunde bitte mit Ausgabe und Windows-Version notieren.
Noch nicht testbar
- Hooks, Paare, Signaturen, fertige Programme als lokale Server, npm-Abhängigkeiten für Plugins: noch nicht gebaut (Stufe 5c–5e); ein Hook-Paket lehnt der Linter mit H008 ab.
- OpenCode 2: ungeprüft (STUFE0.md, Frage 10);
OPENCODE=<opencode-2> scripts/stage0.sh. hugin-install.ps1unter Windows PowerShell 5.1: braucht einen Windows-Rechner, siehe README „Integration unter Windows PowerShell 5.1 testen“.