Compare commits
39 changed files with 2 additions and 4448 deletions
14
.gitignore
vendored
14
.gitignore
vendored
|
|
@ -1,14 +0,0 @@
|
||||||
*.bak
|
|
||||||
node_modules/
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# pi-coder Laufzeitartefakte
|
|
||||||
TASK.md
|
|
||||||
examples/**/TASK.md
|
|
||||||
|
|
||||||
# Build-Artefakte (Examples)
|
|
||||||
examples/rust-wordcount/target/
|
|
||||||
examples/**/__pycache__/
|
|
||||||
examples/**/.pytest_cache/
|
|
||||||
examples/**/Cargo.lock
|
|
||||||
examples/**/ll_demo
|
|
||||||
|
|
@ -1,896 +0,0 @@
|
||||||
# Bedienungsanleitung: pi_coder
|
|
||||||
|
|
||||||
pi_coder ist ein Werkzeug, das zwei lokale KI-Modelle als **Coder** und **Judge** einsetzt,
|
|
||||||
um Software automatisch zu schreiben, zu prüfen und zu verbessern — alles gesteuert über
|
|
||||||
einfache Slash-Kommandos in der pi-Agent-Oberfläche.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Inhaltsverzeichnis
|
|
||||||
|
|
||||||
1. [Konzept: Coder und Judge](#1-konzept-coder-und-judge)
|
|
||||||
2. [Vorbereitung](#2-vorbereitung)
|
|
||||||
3. [Server starten und stoppen](#3-server-starten-und-stoppen)
|
|
||||||
4. [Neues Projekt anlegen](#4-neues-projekt-anlegen)
|
|
||||||
5. [Manueller Workflow: /coder → /judge → /fix → /shipit](#5-manueller-workflow)
|
|
||||||
6. [Automatischer Workflow: /optimize](#6-automatischer-workflow-optimize) (inkl. [Interactive-Modus](#interactive-modus))
|
|
||||||
7. [Kleine Änderungen: /patch und /quick_check](#7-kleine-änderungen-patch-und-quick_check)
|
|
||||||
8. [Dokumentation generieren: /update_doku](#8-dokumentation-generieren-update_doku)
|
|
||||||
9. [Versionsverwaltung: /version](#9-versionsverwaltung-version)
|
|
||||||
10. [TASK.md verstehen und nutzen](#10-taskmd-verstehen-und-nutzen)
|
|
||||||
11. [Typische Anwendungsfälle](#11-typische-anwendungsfälle)
|
|
||||||
12. [Fehlermeldungen und Lösungen](#12-fehlermeldungen-und-lösungen)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Konzept: Coder und Judge
|
|
||||||
|
|
||||||
pi_coder verwendet zwei Rollen:
|
|
||||||
|
|
||||||
**Coder** (Port 8001): Schreibt und repariert Code. Liest die Aufgabe aus `TASK.md`,
|
|
||||||
implementiert sie, führt Tests aus und erstellt Git-Commits.
|
|
||||||
|
|
||||||
**Judge** (Port 8002): Überprüft den Code mit dem Blick eines skeptischen Senior-Entwicklers.
|
|
||||||
Prüft Korrektheit, Robustheit, Randfälle, Sicherheit und Produktionsreife. Gibt ein Urteil:
|
|
||||||
- `PASS` — Code ist in Ordnung
|
|
||||||
- `PASS WITH CONCERNS` — grundsätzlich akzeptabel, aber mit Anmerkungen
|
|
||||||
- `FAIL` — enthält Blocker, die behoben werden müssen
|
|
||||||
|
|
||||||
Der Grundgedanke: Coder und Judge haben keine „Höflichkeitsschranke" zueinander —
|
|
||||||
der Judge kritisiert direkt und konkret, der Coder repariert ohne Widerspruch.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Vorbereitung
|
|
||||||
|
|
||||||
### Server starten
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/pi_coder
|
|
||||||
./start-servers.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Ausgabe bei Erfolg:
|
|
||||||
```
|
|
||||||
[*] Starte beide Server parallel ...
|
|
||||||
[✓] Coder (:8001) bereit
|
|
||||||
[✓] Judge (:8002) bereit
|
|
||||||
```
|
|
||||||
|
|
||||||
Dauer: 1–3 Minuten (Modell wird in GPU-VRAM geladen).
|
|
||||||
|
|
||||||
### Status prüfen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./status.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
=== LLaMA-Server Status ===
|
|
||||||
qwen36-27b-coder (Port 8001): Container=RUNNING HTTP=OK
|
|
||||||
qwen36-27b-judge (Port 8002): Container=RUNNING HTTP=OK
|
|
||||||
```
|
|
||||||
|
|
||||||
### pi agent öffnen
|
|
||||||
|
|
||||||
pi agent im Projektverzeichnis starten — das ist das Verzeichnis, in dem dein Code liegt,
|
|
||||||
**nicht** `~/pi_coder`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/MeinProjekt
|
|
||||||
pi
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Server starten und stoppen
|
|
||||||
|
|
||||||
### Beide starten (empfohlen)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./start-servers.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Einzelnen Server neu starten
|
|
||||||
|
|
||||||
Z.B. wenn nur der Coder-Server abgestürzt ist:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./start-coder.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Beide stoppen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./stop-servers.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Alternativer Modellpfad
|
|
||||||
|
|
||||||
Falls die GGUF-Datei an einem anderen Ort liegt:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
HF_HOME=/mnt/daten/huggingface ./start-servers.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Neues Projekt anlegen
|
|
||||||
|
|
||||||
### Kommando
|
|
||||||
|
|
||||||
```
|
|
||||||
/new_project <pfad>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Beispiel
|
|
||||||
|
|
||||||
```
|
|
||||||
/new_project ~/Python_Programs/mein_tool
|
|
||||||
```
|
|
||||||
|
|
||||||
Was passiert:
|
|
||||||
- Verzeichnis `~/Python_Programs/mein_tool` wird angelegt
|
|
||||||
- `git init` wird ausgeführt
|
|
||||||
- `.gitignore` wird mit Standardeinträgen angelegt und committed
|
|
||||||
|
|
||||||
**Wichtig:** pi agent wechselt **nicht automatisch** in das neue Verzeichnis —
|
|
||||||
die Session bleibt im aktuellen Verzeichnis. Nach dem Anlegen:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ~/Python_Programs/mein_tool
|
|
||||||
pi
|
|
||||||
```
|
|
||||||
|
|
||||||
Dann kannst du `/coder` oder `/optimize` mit dem neuen Projekt verwenden.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Manueller Workflow
|
|
||||||
|
|
||||||
Der manuelle Workflow gibt dir volle Kontrolle über jeden Schritt.
|
|
||||||
|
|
||||||
### Schritt 1: /coder — Aufgabe übergeben
|
|
||||||
|
|
||||||
```
|
|
||||||
/coder <auftrag>
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Coder:
|
|
||||||
1. Legt `TASK.md` im aktuellen Verzeichnis an (oder hängt an bestehende an)
|
|
||||||
2. Liest `TASK.md` und implementiert den Auftrag
|
|
||||||
3. Führt Tests oder Build-Checks aus
|
|
||||||
4. Erstellt einen Git-Commit
|
|
||||||
|
|
||||||
**Beispiel:**
|
|
||||||
|
|
||||||
```
|
|
||||||
/coder Schreibe ein Python-Kommandozeilenprogramm 'textcount'. Es soll eine Textdatei als Argument nehmen und folgendes ausgeben: Anzahl Zeichen, Wörter, Zeilen und die 5 häufigsten Wörter (ohne Stoppwörter).
|
|
||||||
```
|
|
||||||
|
|
||||||
Typische Ausgabe des Coders:
|
|
||||||
```
|
|
||||||
Implementierung abgeschlossen.
|
|
||||||
- src/textcount.py erstellt (Hauptprogramm)
|
|
||||||
- tests/test_textcount.py erstellt (Unit-Tests)
|
|
||||||
- requirements.txt angelegt (keine externen Abhängigkeiten)
|
|
||||||
- Alle 8 Tests bestanden
|
|
||||||
- Commit: feat: implement textcount CLI tool
|
|
||||||
Risiken: Stoppwortliste nur Deutsch/Englisch, keine Konfigurations-Option.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schritt 2: /judge — Code überprüfen lassen
|
|
||||||
|
|
||||||
```
|
|
||||||
/judge
|
|
||||||
```
|
|
||||||
|
|
||||||
Optionaler Fokus:
|
|
||||||
```
|
|
||||||
/judge Besonderes Augenmerk auf Fehlerbehandlung und Edge Cases
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Judge:
|
|
||||||
1. Liest `TASK.md` und prüft ob alle Anforderungen umgesetzt sind
|
|
||||||
2. Analysiert `git show HEAD`
|
|
||||||
3. Führt Tests aus
|
|
||||||
4. Gibt ein strukturiertes Urteil aus
|
|
||||||
|
|
||||||
**Beispiel-Ausgabe PASS:**
|
|
||||||
```
|
|
||||||
Urteil: PASS WITH CONCERNS
|
|
||||||
|
|
||||||
Blocker: keine
|
|
||||||
|
|
||||||
Major:
|
|
||||||
- Stoppwortliste ist hardcoded; große Projekte erwarten --stopwords-file Option
|
|
||||||
|
|
||||||
Minor:
|
|
||||||
- Keine --version Flag
|
|
||||||
- Fehlermeldung bei nicht-existenter Datei gibt keinen Exit-Code 1 zurück
|
|
||||||
|
|
||||||
Fehlende Tests:
|
|
||||||
- Test für leere Datei fehlt
|
|
||||||
- Test für Datei mit nur Leerzeichen fehlt
|
|
||||||
|
|
||||||
Produktionsrisiken:
|
|
||||||
- Bei sehr großen Dateien (>1 GB) wird alles in den RAM geladen
|
|
||||||
|
|
||||||
Konkrete Fix-Aufträge:
|
|
||||||
1. exit(1) bei FileNotFoundError
|
|
||||||
2. Test für leere Eingabedatei
|
|
||||||
```
|
|
||||||
|
|
||||||
**Beispiel-Ausgabe FAIL:**
|
|
||||||
```
|
|
||||||
Urteil: FAIL
|
|
||||||
|
|
||||||
Blocker:
|
|
||||||
- textcount.py importiert 'collections.Counter' aber das ist nicht installiert
|
|
||||||
(Counter ist stdlib, aber der Import-Fehler tritt bei Python < 3.9 auf)
|
|
||||||
- ./textcount.py existiert nicht — tests/test_textcount.py schlägt komplett fehl
|
|
||||||
|
|
||||||
Major: ...
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schritt 3: /fix — Kritik beheben
|
|
||||||
|
|
||||||
```
|
|
||||||
/fix
|
|
||||||
```
|
|
||||||
|
|
||||||
Optionaler Hinweis:
|
|
||||||
```
|
|
||||||
/fix Den Major-Punkt mit der Stoppwortliste kannst du weglassen, das ist kein Produktionsprojekt
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Coder arbeitet die Judge-Kritik ab (Blocker zuerst, dann Major, dann Minor)
|
|
||||||
und erstellt einen neuen Commit.
|
|
||||||
|
|
||||||
### Schritt 4: /shipit — Finale Freigabe
|
|
||||||
|
|
||||||
```
|
|
||||||
/shipit
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Judge gibt ein finales Urteil:
|
|
||||||
- `SHIP` — bereit für Produktion
|
|
||||||
- `NO-SHIP` — noch Probleme offen
|
|
||||||
|
|
||||||
**Beispiel:**
|
|
||||||
```
|
|
||||||
Urteil: SHIP
|
|
||||||
|
|
||||||
Letzte Blocker: keine
|
|
||||||
|
|
||||||
Restrisiken:
|
|
||||||
- Kein Streaming für sehr große Dateien (dokumentiert in README)
|
|
||||||
|
|
||||||
Empfohlene Sofortmaßnahmen: keine
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Automatischer Workflow: /optimize
|
|
||||||
|
|
||||||
`/optimize` führt den gesamten Coder→Judge→Fix-Zyklus automatisch durch.
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize <auftrag> [--rounds N] [--with-doku] [--continue] [--interactive]
|
|
||||||
[--no-tests] [--approve-concerns] [--test-cmd "cmd"] [--test-timeout N]
|
|
||||||
```
|
|
||||||
|
|
||||||
- `--rounds N` — maximale Anzahl Runden (Standard: 2)
|
|
||||||
- `--with-doku` — nach SHIP automatisch `/update_doku` ausführen
|
|
||||||
- `--continue` — überspringt die Implementierungsphase und startet direkt mit dem
|
|
||||||
Judge→Fix-Zyklus ab dem aktuellen Code-Stand. Nützlich wenn man bereits manuell
|
|
||||||
`/coder`, `/judge` und `/fix` durchgeführt hat und den Rest automatisieren möchte.
|
|
||||||
Im `--continue`-Modus werden Coder- und Judge-Server gleichzeitig geprüft.
|
|
||||||
- `--interactive` — pausiert nach erstem PASS für einen menschlichen Checkpoint.
|
|
||||||
Details: siehe [Interactive-Modus](#interactive-modus) weiter unten.
|
|
||||||
- `--no-tests` — überspringt die automatische Test-Erkennung. Sinnvoll wenn keine
|
|
||||||
Test-Suite vorhanden ist oder Tests über externe Infrastruktur laufen.
|
|
||||||
- `--approve-concerns` — behandelt „PASS WITH CONCERNS" wie „PASS": kein ShipIt-Call,
|
|
||||||
direktes SHIP. Für Projekte, bei denen du dem Judge-Urteil vertraust.
|
|
||||||
- `--test-cmd "befehl"` — überschreibt die automatische Test-Erkennung mit einem
|
|
||||||
eigenen Befehl (z.B. `--test-cmd "pytest tests/ -x"`).
|
|
||||||
- `--test-timeout N` — maximale Laufzeit pro Test-Befehl in Sekunden (Standard: 120).
|
|
||||||
|
|
||||||
### Beispiel: einfacher Auftrag
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize Schreibe ein Rust-Programm 'genpw' das sichere Passwörter generiert. Optionen: --length N (Standard 16), --count N (Standard 1), --no-symbols, --no-numbers.
|
|
||||||
```
|
|
||||||
|
|
||||||
Was im Hintergrund passiert:
|
|
||||||
```
|
|
||||||
Phase 1: Coder implementiert...
|
|
||||||
Phase 2: Runde 1/2: Quick-Check (kompakter Erstcheck)...
|
|
||||||
→ Urteil: FAIL (2 Blocker)
|
|
||||||
Phase 3: Runde 1/2: Coder fixt...
|
|
||||||
Phase 4: Runde 2/2: Judge — TASK.md + letzter Commit + Tests...
|
|
||||||
→ Urteil: PASS WITH CONCERNS
|
|
||||||
✓ PASS WITH CONCERNS nach Runde 2
|
|
||||||
Finale ShipIt-Prüfung... (nur bei PASS WITH CONCERNS, nicht bei klarem PASS)
|
|
||||||
→ SHIP
|
|
||||||
[Dialog: Version → v0.1.0 (empfohlen)]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Runde 1 = Quick-Check:** Kompakter Prompt ohne TASK.md-Analyse — erkennt offensichtliche
|
|
||||||
Fehler schnell. Erst ab Runde 2 (oder bei `--continue`) kommt der vollständige Judge-Prompt.
|
|
||||||
|
|
||||||
Bei klarem `PASS` entfällt die ShipIt-Runde — es wird direkt SHIP ausgelöst.
|
|
||||||
Mit `--approve-concerns` gilt das auch für `PASS WITH CONCERNS`.
|
|
||||||
|
|
||||||
Während des Ablaufs zeigt die Statuszeile immer die aktuelle Aktivität:
|
|
||||||
`Coder implementiert…` → `Quick-Check…` → `Coder fixt Blocker…` → `Judge reviewt (Runde 2/2)…`
|
|
||||||
|
|
||||||
### Beispiel: mehr Runden
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize Implementiere einen vollständigen REST-API-Client für die GitHub API in Python mit Rate-Limiting, Retry-Logic und Caching --rounds 5
|
|
||||||
```
|
|
||||||
|
|
||||||
### Beispiel: mit automatischer Dokumentation
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize Schreibe ein Go-Tool 'logfilter' das Logdateien nach Regex-Muster filtert --with-doku
|
|
||||||
```
|
|
||||||
|
|
||||||
Nach SHIP werden automatisch ausgeführt:
|
|
||||||
1. Code-Kommentare einfügen
|
|
||||||
2. README.md schreiben
|
|
||||||
3. BEDIENUNGSANLEITUNG.md schreiben
|
|
||||||
|
|
||||||
### Vom manuellen Workflow in den automatischen wechseln
|
|
||||||
|
|
||||||
Du hast bereits `/coder`, `/judge` und `/fix` manuell durchgeführt und möchtest
|
|
||||||
den Rest automatisch ablaufen lassen:
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize --continue
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize --continue --rounds 5
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize --continue --with-doku
|
|
||||||
```
|
|
||||||
|
|
||||||
Die Implementierungsphase wird übersprungen — der Judge prüft sofort den aktuellen
|
|
||||||
Stand und der Fix-Zyklus läuft automatisch bis PASS oder max. N Runden.
|
|
||||||
|
|
||||||
### Loop-Erkennung
|
|
||||||
|
|
||||||
Wenn zweimal hintereinander genau dieselben Blocker auftreten, bricht `/optimize` ab:
|
|
||||||
```
|
|
||||||
⚠ Derselbe Blocker tritt erneut auf – Schleife abgebrochen. Bitte manuell prüfen.
|
|
||||||
```
|
|
||||||
|
|
||||||
In diesem Fall: `/judge` manuell ausführen, Blocker lesen, mit `/fix` manuell eingreifen.
|
|
||||||
|
|
||||||
### Max. Runden ohne PASS
|
|
||||||
|
|
||||||
```
|
|
||||||
⚠ 2 Runden durchlaufen ohne PASS. Bitte manuell prüfen.
|
|
||||||
```
|
|
||||||
|
|
||||||
Dann: `/judge` und `/fix` manuell für gezielte Eingriffe.
|
|
||||||
Mit `--rounds N` kann die Grenze hochgesetzt werden, z.B. `--rounds 5` für komplexe Aufgaben.
|
|
||||||
|
|
||||||
### Interactive-Modus
|
|
||||||
|
|
||||||
Mit `--interactive` pausiert `/optimize` nach dem ersten PASS und wartet auf menschliches
|
|
||||||
Feedback — bevor das abschließende SHIP ausgelöst wird.
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize Implementiere Feature X --interactive
|
|
||||||
```
|
|
||||||
|
|
||||||
Typischer Ablauf:
|
|
||||||
```
|
|
||||||
Phase 1: Coder implementiert...
|
|
||||||
Phase 2: Judge prüft...
|
|
||||||
→ Urteil: PASS
|
|
||||||
⏸ PASS erreicht. Weitere Features? /continue "Zusatzauftrag" — oder /continue zum Shippern.
|
|
||||||
```
|
|
||||||
|
|
||||||
Jetzt hast du drei Optionen:
|
|
||||||
|
|
||||||
**Option A: Direkt shippern**
|
|
||||||
```
|
|
||||||
/continue
|
|
||||||
```
|
|
||||||
→ ShipIt wird gestartet, Version-Dialog erscheint.
|
|
||||||
|
|
||||||
**Option B: Zusatzauftrag hinzufügen**
|
|
||||||
```
|
|
||||||
/continue "Füge außerdem eine --verbose Option hinzu"
|
|
||||||
```
|
|
||||||
→ Coder implementiert den Zusatz, dann läuft der Judge-Loop erneut an.
|
|
||||||
→ Nach erneutem PASS erscheint der Checkpoint wieder — du kannst beliebig viele
|
|
||||||
Iterationen anhängen, bevor du mit `/continue` zum SHIP gehst.
|
|
||||||
|
|
||||||
**Option C: Abbrechen**
|
|
||||||
```
|
|
||||||
/cancel
|
|
||||||
```
|
|
||||||
→ Loop wird abgebrochen, kein SHIP.
|
|
||||||
|
|
||||||
**Timeout:** Wenn du 30 Minuten lang nichts eingibst, bricht `/optimize` automatisch ab.
|
|
||||||
|
|
||||||
**Wann ist `--interactive` sinnvoll?**
|
|
||||||
- Wenn der Auftrag aus mehreren voneinander abhängigen Features besteht
|
|
||||||
- Wenn du nach jeder fertigen Stufe entscheiden möchtest, ob du weitermachst
|
|
||||||
- Wenn du sicherstellen willst, dass nichts unbeabsichtigt committed wird
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Kleine Änderungen: /patch und /quick_check
|
|
||||||
|
|
||||||
Für minimale Korrekturen — kein voller Review-Zyklus, keine TASK.md-Änderungen.
|
|
||||||
|
|
||||||
### /patch — kleine Änderung umsetzen
|
|
||||||
|
|
||||||
```
|
|
||||||
/patch <beschreibung der änderung>
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Coder ändert **ausschließlich** das Beschriebene, prüft ob es noch kompiliert/startet
|
|
||||||
und erstellt einen Commit.
|
|
||||||
|
|
||||||
**Beispiele:**
|
|
||||||
|
|
||||||
```
|
|
||||||
/patch Mindestpasswortlänge von 4 auf 8 Zeichen erhöhen
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
/patch Fehlermeldung bei ungültigem Argument von stderr auf stdout umleiten
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
/patch Versionsnummer in Cargo.toml von 0.1.0 auf 0.2.0 erhöhen
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
/patch Die Funktion parse_args() soll bei fehlendem --input-Argument eine sinnvolle Hilfsnachricht ausgeben statt zu paniken
|
|
||||||
```
|
|
||||||
|
|
||||||
### /quick_check — Änderung schnell prüfen lassen
|
|
||||||
|
|
||||||
```
|
|
||||||
/quick_check [was geprüft werden soll]
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Judge schaut sich `git show HEAD` an und gibt nur `OK` oder `PROBLEM` zurück.
|
|
||||||
|
|
||||||
**Beispiele:**
|
|
||||||
|
|
||||||
```
|
|
||||||
/quick_check
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
/quick_check Prüfe ob die Mindestlängen-Änderung korrekt umgesetzt ist und keine Randfälle fehlen
|
|
||||||
```
|
|
||||||
|
|
||||||
**Typische Ausgaben:**
|
|
||||||
|
|
||||||
```
|
|
||||||
Urteil: OK
|
|
||||||
|
|
||||||
Die Änderung in src/main.rs Zeile 47 ist korrekt. Mindestlänge wird jetzt
|
|
||||||
sowohl bei --length als auch im Standardfall geprüft.
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
Urteil: PROBLEM
|
|
||||||
|
|
||||||
src/lib.rs Zeile 23: Der neue Mindestwert von 8 wird nur bei --length geprüft,
|
|
||||||
nicht beim Standardwert (16). Wenn jemand --length 6 übergibt, schlägt die
|
|
||||||
Validierung korrekt fehl, aber der Standardfall ist nicht abgedeckt.
|
|
||||||
Fix: Validierung in die Funktion generate_password() verschieben statt in parse_args().
|
|
||||||
```
|
|
||||||
|
|
||||||
### Typischer /patch + /quick_check Workflow
|
|
||||||
|
|
||||||
```
|
|
||||||
/patch Timeout bei HTTP-Requests von 30 auf 10 Sekunden setzen
|
|
||||||
```
|
|
||||||
*(Coder ändert, committet)*
|
|
||||||
|
|
||||||
```
|
|
||||||
/quick_check Prüfe ob der Timeout auch bei Retry-Versuchen korrekt gilt
|
|
||||||
```
|
|
||||||
*(Judge gibt OK oder zeigt konkretes Problem)*
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Dokumentation generieren: /update_doku
|
|
||||||
|
|
||||||
Nach Abschluss der Entwicklung (nach `/shipit` oder `/optimize`) erstellt `/update_doku`
|
|
||||||
drei Dinge automatisch:
|
|
||||||
|
|
||||||
1. **Code-Kommentare** — erklärt das WARUM in den Quelldateien (Deutsch)
|
|
||||||
2. **README.md** — Entwicklerperspektive: Installation, Build, Verwendung
|
|
||||||
3. **BEDIENUNGSANLEITUNG.md** — Endnutzerperspektive: einfach, ohne Jargon
|
|
||||||
|
|
||||||
```
|
|
||||||
/update_doku
|
|
||||||
```
|
|
||||||
|
|
||||||
### Inkrementelles Update
|
|
||||||
|
|
||||||
`/update_doku` merkt sich via Git-Tags welche Dateien seit dem letzten Lauf geändert wurden.
|
|
||||||
Nur geänderte Quelldateien werden neu kommentiert — unveränderte bleiben unangetastet.
|
|
||||||
|
|
||||||
```
|
|
||||||
Code-Kommentare: keine Änderungen seit letztem Lauf – übersprungen.
|
|
||||||
README.md: 2 Datei(en) geändert – wird geprüft
|
|
||||||
BEDIENUNGSANLEITUNG.md: 2 Datei(en) geändert – wird geprüft
|
|
||||||
```
|
|
||||||
|
|
||||||
### Zusammen mit /optimize
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize Implementiere Feature X --with-doku
|
|
||||||
```
|
|
||||||
|
|
||||||
Führt nach SHIP automatisch `/update_doku` aus.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Versionsverwaltung: /version
|
|
||||||
|
|
||||||
pi_coder verwaltet Versionsnummern im SemVer-Format (`vMAJOR.MINOR.PATCH`) automatisch —
|
|
||||||
basierend auf den Commit-Messages des generierten Codes.
|
|
||||||
|
|
||||||
### Wie Commit-Messages die Version bestimmen
|
|
||||||
|
|
||||||
Der Coder verwendet standardmäßig das Conventional-Commits-Format:
|
|
||||||
|
|
||||||
| Commit-Prefix | Beispiel | Bump-Typ |
|
|
||||||
|---|---|---|
|
|
||||||
| `feat!:` oder `BREAKING CHANGE` | `feat!: API komplett überarbeitet` | major (v1.0.0 → v2.0.0) |
|
|
||||||
| `feat:` | `feat: CSV-Export hinzugefügt` | minor (v1.0.0 → v1.1.0) |
|
|
||||||
| `fix:`, `chore:`, andere | `fix: Crash bei leerer Datei` | patch (v1.0.0 → v1.0.1) |
|
|
||||||
|
|
||||||
### Automatisch nach SHIP
|
|
||||||
|
|
||||||
Nach einem erfolgreichen SHIP-Verdikt in `/optimize` oder `/shipit` erscheint automatisch
|
|
||||||
ein Dialog:
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─ Version ──────────────────────────────────────────────┐
|
|
||||||
│ Aktuelle Version: v1.2.3. Commits seit letztem Tag: │
|
|
||||||
│ minor-Bump erkannt. │
|
|
||||||
│ │
|
|
||||||
│ patch → v1.2.4 │
|
|
||||||
│ minor → v1.3.0 (empfohlen) │
|
|
||||||
│ major → v2.0.0 │
|
|
||||||
│ Überspringen │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
Du kannst den empfohlenen Wert bestätigen oder manuell einen anderen wählen.
|
|
||||||
|
|
||||||
### Manuell aufrufen
|
|
||||||
|
|
||||||
```
|
|
||||||
/version
|
|
||||||
```
|
|
||||||
|
|
||||||
Nützlich wenn du den Tag nachträglich setzen möchtest oder nach manuellen Commits.
|
|
||||||
|
|
||||||
### Was passiert nach der Auswahl
|
|
||||||
|
|
||||||
1. Die Versionsnummer wird in die Projekt-Manifest-Datei geschrieben (falls vorhanden):
|
|
||||||
- `package.json` → `npm version --no-git-tag-version X.Y.Z`
|
|
||||||
- `Cargo.toml` → `version = "X.Y.Z"` in `[package]`
|
|
||||||
- `pyproject.toml` → `version = "X.Y.Z"` in `[project]`
|
|
||||||
- `VERSION` → Dateiinhalt `vX.Y.Z`
|
|
||||||
2. Commit: `chore: bump version to vX.Y.Z`
|
|
||||||
3. Git-Tag: `vX.Y.Z` wird gesetzt
|
|
||||||
|
|
||||||
Wenn keine der genannten Dateien vorhanden ist, wird nur der Git-Tag gesetzt.
|
|
||||||
|
|
||||||
### Erstes Mal — kein Tag vorhanden
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─ Version ──────────────────────────────────────────────┐
|
|
||||||
│ Noch kein Versions-Tag vorhanden. │
|
|
||||||
│ │
|
|
||||||
│ patch → v0.0.1 │
|
|
||||||
│ minor → v0.1.0 (empfohlen) │
|
|
||||||
│ major → v1.0.0 │
|
|
||||||
│ Überspringen │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
Empfehlung: `v0.1.0` für ein frisches, funktionierendes Projekt; `v1.0.0` wenn es
|
|
||||||
sofort produktionsreif ist.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. TASK.md verstehen und nutzen
|
|
||||||
|
|
||||||
`TASK.md` ist die persistente Aufgabenbeschreibung im Projektverzeichnis. Sie wird von
|
|
||||||
allen Kommandos als Referenz gelesen.
|
|
||||||
|
|
||||||
### Erstellt von /coder und /optimize
|
|
||||||
|
|
||||||
Beim ersten `/coder`-Aufruf:
|
|
||||||
```markdown
|
|
||||||
# Aufgabe
|
|
||||||
|
|
||||||
Schreibe ein Python-Kommandozeilenprogramm 'textcount'...
|
|
||||||
|
|
||||||
## Erstellt
|
|
||||||
2026-05-19T14:30:00.000Z
|
|
||||||
|
|
||||||
## Status
|
|
||||||
- [ ] Implementierung
|
|
||||||
- [x] Review bestanden (PASS)
|
|
||||||
- [ ] Produktionsreif (SHIP)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Zusatzauftrag hinzufügen
|
|
||||||
|
|
||||||
Wenn du später `/coder` mit einer neuen Aufgabe aufrufst, wird TASK.md erweitert statt überschrieben:
|
|
||||||
|
|
||||||
```
|
|
||||||
/coder Füge zusätzlich eine --csv-Option hinzu, die das Ergebnis als CSV ausgibt
|
|
||||||
```
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# Aufgabe
|
|
||||||
|
|
||||||
[...ursprüngliche Aufgabe...]
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Zusatzauftrag
|
|
||||||
|
|
||||||
2026-05-19T15:45:00.000Z
|
|
||||||
|
|
||||||
Füge zusätzlich eine --csv-Option hinzu...
|
|
||||||
|
|
||||||
## Status
|
|
||||||
- [ ] Implementierung
|
|
||||||
- [ ] Review bestanden (PASS)
|
|
||||||
- [ ] Produktionsreif (SHIP)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Status-Checkboxen
|
|
||||||
|
|
||||||
Die Checkboxen werden automatisch abgehakt:
|
|
||||||
- `[x] Implementierung` — nach erfolgreichem `/coder` oder `Phase 1` von `/optimize`
|
|
||||||
- `[x] Review bestanden (PASS)` — nach PASS durch `/judge` oder in `/optimize`
|
|
||||||
- `[x] Produktionsreif (SHIP)` — nach SHIP durch `/shipit` oder `/update_doku`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11. Typische Anwendungsfälle
|
|
||||||
|
|
||||||
### Neues Rust-Programm von Null
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Verzeichnis anlegen
|
|
||||||
/new_project ~/Rust_Programs/mein_tool
|
|
||||||
|
|
||||||
# 2. Terminal: in Verzeichnis wechseln und pi neu starten
|
|
||||||
# cd ~/Rust_Programs/mein_tool && pi
|
|
||||||
|
|
||||||
# 3. In pi: vollautomatisch implementieren + dokumentieren
|
|
||||||
/optimize Schreibe ein Rust-CLI-Tool 'csvfilter' das CSV-Dateien zeilenweise filtert. Optionen: --column NAME, --value WERT, --regex. Ausgabe auf stdout. --with-doku
|
|
||||||
```
|
|
||||||
|
|
||||||
### Bestehendes Projekt verbessern
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# In pi, im Projektverzeichnis:
|
|
||||||
/coder Refaktoriere die Datenbankschicht: ersetze das raw-SQL durch sqlx mit typsicheren Queries. Alle Tests müssen danach noch laufen.
|
|
||||||
/judge
|
|
||||||
/fix
|
|
||||||
/shipit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schnelle Bugfixes
|
|
||||||
|
|
||||||
```bash
|
|
||||||
/patch Die Funktion split_csv() schlägt bei Feldern mit eingebetteten Kommas fehl (RFC 4180 nicht implementiert)
|
|
||||||
/quick_check
|
|
||||||
```
|
|
||||||
|
|
||||||
### Repo ohne Test-Suite oder mit externer CI
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Test-Erkennung überspringen — Judge bewertet nur den Code
|
|
||||||
/optimize "Implementiere Feature X" --no-tests
|
|
||||||
|
|
||||||
# Externe Test-Suite explizit angeben
|
|
||||||
/optimize "Implementiere Feature X" --test-cmd "make integration-test"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schneller Loop ohne ShipIt-Runde
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Für Projekte wo "PASS WITH CONCERNS" ausreicht:
|
|
||||||
/optimize "Kleines Refactoring" --approve-concerns
|
|
||||||
|
|
||||||
# Kombination: kein Test, kein ShipIt bei Concerns, 1 Runde
|
|
||||||
/optimize "Typo-Fix in Fehlermeldungen" --rounds 1 --no-tests --approve-concerns
|
|
||||||
```
|
|
||||||
|
|
||||||
### Versionsnummer nach der Entwicklung setzen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Nach SHIP: Dialog erscheint automatisch
|
|
||||||
/optimize Neues Feature X --rounds 2
|
|
||||||
# → SHIP → Dialog → "minor → v1.1.0" wählen → Tag gesetzt
|
|
||||||
|
|
||||||
# Oder manuell:
|
|
||||||
/version
|
|
||||||
```
|
|
||||||
|
|
||||||
### Kommentarlosen Legacy-Code dokumentieren
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Nur Kommentare und Dokumentation, kein Code ändern:
|
|
||||||
/update_doku
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schrittweise mit manuellem Review
|
|
||||||
|
|
||||||
```bash
|
|
||||||
/coder Implementiere OAuth2-Login mit GitHub
|
|
||||||
# → Code lesen, verstehen
|
|
||||||
/judge Besonderes Augenmerk auf Token-Speicherung und CSRF-Schutz
|
|
||||||
# → Judge-Bericht lesen
|
|
||||||
/fix Ignoriere den Minor-Punkt mit der Logging-Verbosität, das ist Absicht
|
|
||||||
/shipit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Experiment: mehrere Runden explizit
|
|
||||||
|
|
||||||
```bash
|
|
||||||
/optimize Schreibe einen vollständigen Markdown-Parser mit AST in Python --rounds 5
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schrittweise Features hinzufügen mit --interactive
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Erst Grundgerüst implementieren und PASS abwarten:
|
|
||||||
/optimize Schreibe ein CLI-Tool 'filewatch' das Dateiänderungen überwacht --interactive
|
|
||||||
|
|
||||||
# Nach PASS erscheint: ⏸ PASS – warte auf /continue…
|
|
||||||
|
|
||||||
# Option A: Genug, direkt shippern:
|
|
||||||
/continue
|
|
||||||
|
|
||||||
# Option B: Weiteres Feature anhängen:
|
|
||||||
/continue "Füge außerdem einen --filter GLOB-Parameter hinzu"
|
|
||||||
# → Coder implementiert, Judge prüft erneut, PASS → Checkpoint wieder aktiv
|
|
||||||
|
|
||||||
# Nochmal erweitern:
|
|
||||||
/continue "Füge --output-log DATEI hinzu um Änderungen zu protokollieren"
|
|
||||||
|
|
||||||
# Fertig → shippern:
|
|
||||||
/continue
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 12. Fehlermeldungen und Lösungen
|
|
||||||
|
|
||||||
### "Modell-Datei nicht gefunden"
|
|
||||||
|
|
||||||
```
|
|
||||||
[!] Modell-Datei nicht gefunden: /home/.../models/qwen3/Qwen3.6-27B-Uncensored-...gguf
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ursache:** Die GGUF-Datei liegt nicht am erwarteten Ort.
|
|
||||||
|
|
||||||
**Lösung:**
|
|
||||||
```bash
|
|
||||||
# Pfad prüfen:
|
|
||||||
ls $HF_HOME/models/qwen3/
|
|
||||||
|
|
||||||
# Oder mit explizitem Pfad starten:
|
|
||||||
HF_HOME=/korrekter/pfad ./start-servers.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server startet nicht / HTTP nicht erreichbar
|
|
||||||
|
|
||||||
```
|
|
||||||
[!] HTTP-Server wurde nicht rechtzeitig erreichbar.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ursachen und Lösungen:**
|
|
||||||
|
|
||||||
1. Zu wenig VRAM — Container bricht beim Laden ab:
|
|
||||||
```bash
|
|
||||||
docker logs qwen36-27b-coder | tail -50
|
|
||||||
# Suche nach: "CUDA out of memory" oder "failed to allocate"
|
|
||||||
```
|
|
||||||
→ Kontext reduzieren: `-c 32768` statt `-c 131072`
|
|
||||||
|
|
||||||
2. GPU nicht verfügbar:
|
|
||||||
```bash
|
|
||||||
nvidia-smi # GPUs sichtbar?
|
|
||||||
docker run --gpus '"device=1,2"' --rm nvidia/cuda:12.0-base nvidia-smi
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Port bereits belegt:
|
|
||||||
```bash
|
|
||||||
ss -tlnp | grep 800[12]
|
|
||||||
docker ps -a # alter Container noch vorhanden?
|
|
||||||
./stop-servers.sh
|
|
||||||
./start-servers.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### "Agent is already processing a prompt"
|
|
||||||
|
|
||||||
**Ursache:** Ein Kommando wurde aufgerufen während pi agent noch auf eine Antwort wartet.
|
|
||||||
|
|
||||||
**Lösung:** Warten bis die aktuelle Antwort fertig ist, dann das Kommando wiederholen.
|
|
||||||
Bei `/optimize` passiert das automatisch — der interne Mechanismus wartet auf `idle`.
|
|
||||||
|
|
||||||
### "edits[n] ... oldText must match exactly"
|
|
||||||
|
|
||||||
**Ursache:** Der interne pi-agent-Edit-Mechanismus hat beim Anwenden mehrerer Änderungen
|
|
||||||
an derselben Datei versagt.
|
|
||||||
|
|
||||||
**Was pi_coder dagegen tut:** Ein `tool_call`-Hook in der Extension sortiert
|
|
||||||
Mehrfach-Edits automatisch von hinten nach vorne (Bottom-up-Reordering), sodass
|
|
||||||
frühere Edits spätere Positionen nicht verschieben. Zusätzlich steht das `apply_patch`-Tool
|
|
||||||
bereit, das GNU `patch -p1` mit Fuzzy-Matching nutzt.
|
|
||||||
|
|
||||||
**Falls es trotzdem auftritt:** Das Modell manuell anweisen:
|
|
||||||
```
|
|
||||||
Lies die Datei neu ein und wende die Änderungen als unified diff mit apply_patch an.
|
|
||||||
```
|
|
||||||
|
|
||||||
### "N Runden ohne PASS" / Loop-Erkennung schlägt an
|
|
||||||
|
|
||||||
```
|
|
||||||
⚠ Derselbe Blocker tritt erneut auf – Schleife abgebrochen.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ursache:** Der Coder kann einen bestimmten Blocker nicht beheben — z.B. weil die
|
|
||||||
Aufgabe einen Widerspruch enthält oder ein externes System fehlt.
|
|
||||||
|
|
||||||
**Lösung:** Manuell eingreifen:
|
|
||||||
```
|
|
||||||
/judge ← Judge-Bericht lesen
|
|
||||||
```
|
|
||||||
Dann den Blocker analysieren und entweder:
|
|
||||||
- `/fix Ignoriere Blocker X, das ist nicht Teil dieser Aufgabe`
|
|
||||||
- Den Code selbst anpassen und dann `/fix` aufrufen
|
|
||||||
- Die Aufgabe in TASK.md präzisieren
|
|
||||||
- Bei komplexen Aufgaben mit mehr Runden wiederholen: `/optimize --continue --rounds 5`
|
|
||||||
|
|
||||||
### Server läuft, aber pi wechselt nicht das Modell
|
|
||||||
|
|
||||||
**Ursache:** `models.json` wurde nach einer Änderung nicht neu deployt.
|
|
||||||
|
|
||||||
**Lösung:**
|
|
||||||
```bash
|
|
||||||
cd ~/pi_coder
|
|
||||||
./install.sh
|
|
||||||
# Dann /reload in pi agent
|
|
||||||
```
|
|
||||||
|
|
||||||
### "Neues Projekt" wechselt nicht das Verzeichnis
|
|
||||||
|
|
||||||
Das ist gewollt — pi-Sessions sind an ihr Startverzeichnis gebunden.
|
|
||||||
Nach `/new_project <pfad>` im Terminal:
|
|
||||||
```bash
|
|
||||||
cd <pfad>
|
|
||||||
pi
|
|
||||||
```
|
|
||||||
80
CLAUDE.md
80
CLAUDE.md
|
|
@ -1,80 +0,0 @@
|
||||||
# CLAUDE.md
|
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
||||||
|
|
||||||
## Was ist dieses Repo?
|
|
||||||
|
|
||||||
Eine **TypeScript-Extension** für den [`pi`-Coding-Agent](https://github.com/earendil-works/pi) (`@earendil-works/pi-coding-agent`). Sie implementiert einen automatisierten **Coder → Judge → Fix**-Loop mit zwei lokalen llama.cpp-Servern.
|
|
||||||
|
|
||||||
Nach jeder Änderung an `pi-coder-judge-extension.ts` oder `models.json` muss deployed werden:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./install.sh # kopiert nach ~/.pi/agent/extensions/ und ~/.pi/agent/
|
|
||||||
# dann in pi agent: /reload
|
|
||||||
```
|
|
||||||
|
|
||||||
## Server-Lifecycle
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./start-servers.sh # beide Container parallel starten (empfohlen, ~1–3 min)
|
|
||||||
./start-coder.sh # nur Coder :8001
|
|
||||||
./start-judge.sh # nur Judge :8002
|
|
||||||
./stop-servers.sh # beide stoppen
|
|
||||||
./status.sh # Container- und HTTP-Status beider Server
|
|
||||||
```
|
|
||||||
|
|
||||||
Die Start-Skripte stoppen existierende Container automatisch vor dem Neustart.
|
|
||||||
|
|
||||||
## Architektur der Extension
|
|
||||||
|
|
||||||
`pi-coder-judge-extension.ts` ist die einzige Logikdatei. Sie registriert alle Commands, das `apply_patch`-Custom-Tool und zwei Event-Hooks beim pi-Agent.
|
|
||||||
|
|
||||||
**Zwei LLM-Rollen:**
|
|
||||||
|
|
||||||
| Rolle | Port | Container | Alias |
|
|
||||||
|-------|------|-----------|-------|
|
|
||||||
| Coder (Implementierung, Fixes, Doku) | 8001 | `qwen36-27b-coder` | `qwen3.5-coder` |
|
|
||||||
| Judge (Review, ShipIt, QuickCheck) | 8002 | `qwen36-27b-judge` | `qwen3.5-judge` |
|
|
||||||
|
|
||||||
Beide nutzen dasselbe GGUF (`Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS.gguf`), aber unterschiedliche Serverparameter.
|
|
||||||
|
|
||||||
**Zentraler Ablauf in `/optimize`:**
|
|
||||||
1. `writeTaskMd()` → TASK.md anlegen
|
|
||||||
2. `--continue`-Modus: Coder- und Judge-Server **parallel** via `Promise.all(waitUntilModelReady×2)` prüfen
|
|
||||||
3. Coder: `coderKickoff()` → implementiert + committet
|
|
||||||
4. Äußere `while(keepGoing)`-Schleife (für `--interactive`-Zusatzaufträge)
|
|
||||||
5. Loop (max. N Runden, Standard 2):
|
|
||||||
- Runde 1 (ohne `--continue`): `quickJudgePrompt()` / `quickJudgeWithTestsPrompt()` — kurzer Erstcheck
|
|
||||||
- Runde 2+: `judgePrompt()` / `judgeWithTestsPrompt()` — vollständige Analyse mit TASK.md
|
|
||||||
- `parseVerdict()` → PASS? → break. FAIL? → `parseBlockers()` → `normalizeForComparison()` → Loop-Check → Fix → nächste Runde
|
|
||||||
6. Bei PASS + `--interactive`: Polling auf `interactiveContinueRequested`. Zusatzauftrag → `coderKickoff()` → `keepGoing = true`
|
|
||||||
7. SHIP-Schritt: `PASS` oder (`PASS WITH CONCERNS` + `--approve-concerns`) → direkt SHIP. `PASS WITH CONCERNS` sonst → `shipitPrompt()` → SHIP/NO-SHIP
|
|
||||||
8. Loop-Erkennung: `normalizeForComparison(currentBlockers) === normalizeForComparison(lastBlockers)` → Abbruch
|
|
||||||
9. Optional: `runUpdateDoku()` bei `--with-doku`
|
|
||||||
|
|
||||||
**`tool_call`-Hook (edit-Reordering):** Sortiert Multi-Edit-Aufrufe auf dieselbe Datei von hinten nach vorne. Verhindert den Fehler „edits[n] doesn't match" wenn mehrere Stellen einer Datei auf einmal geändert werden.
|
|
||||||
|
|
||||||
**`apply_patch`-Tool:** Wendet unified diffs via `patch -p1` an — robuster als mehrfache `edit`-Aufrufe bei umfangreichen Änderungen.
|
|
||||||
|
|
||||||
**Inkrementelle Dokumentation (`runUpdateDoku`):** Git-Tags (`docs-last-commented`, `docs-last-readme`, `docs-last-bedienungsanleitung`) markieren den letzten Dokumentationslauf. Nur Dateien, die sich seitdem geändert haben, werden neu verarbeitet.
|
|
||||||
|
|
||||||
## Modell-Konfiguration (`models.json`)
|
|
||||||
|
|
||||||
Fünf Provider: `ollama` (lokale Ollama-Instanz), `llama-cpp` (:8000), `llama-cpp-coder` (:8001), `llama-cpp-judge` (:8002), `openrouter`. Die beiden llama-cpp-\*-Provider werden von der Extension via `switchModel()` automatisch gewechselt — nie manuell setzen wenn die Extension läuft.
|
|
||||||
|
|
||||||
Kritische Felder bei llama-cpp-Providern: `contextWindow` muss mit dem `-c`-Parameter im Start-Skript übereinstimmen (aktuell 262144). `maxTokens` begrenzt die Ausgabelänge pro Request.
|
|
||||||
|
|
||||||
## Wichtige Invarianten
|
|
||||||
|
|
||||||
- **`cancelRequested`** ist eine modulare Variable — sie wird von `/cancel` gesetzt und nach jedem Loop-Schritt in `/optimize` geprüft und zurückgesetzt.
|
|
||||||
- **`currentModelKey`** — Cache für `switchModel()`: speichert `"provider/modelId"` des zuletzt gesetzten Modells. Bei identischem Key wird `pi.setModel()` übersprungen. Wird im `finally`-Block auf `""` resettet.
|
|
||||||
- **`normalizeForComparison(s)`** — Hilfsfunktion für die Loop-Erkennung: normalisiert Whitespace und Satzzeichen vor dem String-Vergleich, verhindert False-Negatives.
|
|
||||||
- **`quickJudgePrompt()` / `quickJudgeWithTestsPrompt()`** — kompakte Prompt-Varianten für Runde 1 (ohne `--continue`): kein TASK.md, nur Diff + Testergebnis. Bei FAIL folgt Runde 2 mit `judgePrompt()`.
|
|
||||||
- **`interactivePauseActive` / `interactiveContinueRequested` / `interactivePauseTask`** — drei modulare Variablen für den `--interactive`-Modus. `interactivePauseActive` wird vom `/continue`-Command geprüft, um zwischen Interactive-Pause-Signal und normalem Fortsetzen zu unterscheiden. Alle drei werden im `finally`-Block zurückgesetzt.
|
|
||||||
- **`sendAndWait()`** wartet erst auf `idle`, dann `deliverAs: "followUp"` — verhindert „Agent is already processing".
|
|
||||||
- **`tickTaskMdStatus()`** nutzt Python3 für den String-Ersatz in TASK.md (kein Shell-Escaping-Problem).
|
|
||||||
- Beide Start-Skripte warten bis zu 90×2 s auf HTTP-Erreichbarkeit und führen dann einen Smoke-Test-Completion durch.
|
|
||||||
|
|
||||||
## GPU-Setup
|
|
||||||
|
|
||||||
Hardware: 2× RTX 3090 (device=1,2), tensor-split 0.5,0.5. KV-Cache: `q4_0` (25 % des fp16-VRAM — nötig für 262k Kontext auf 2× 24 GB). Für andere GPU-Konfigurationen: README.md Abschnitt „Anpassung".
|
|
||||||
318
README.md
318
README.md
|
|
@ -1,317 +1,3 @@
|
||||||
# pi_coder — Automatisierter Coder/Judge-Workflow für pi agent
|
# pi_coder
|
||||||
|
|
||||||
Dieses Repository enthält die Konfiguration und Skripte für einen automatisierten
|
Automatischer Programm-Generator mit Pi Agent und zwei KI-Modelle als Coder und Judge, der solange Selbstoptimierungsscheifen dreht bis das Programm Produktionsniveau hat.
|
||||||
Coding-Workflow mit zwei lokalen LLaMA-Modellen: ein Coder-Modell und ein Judge-Modell,
|
|
||||||
gesteuert über [pi agent](https://github.com/earendil-works/pi).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Überblick
|
|
||||||
|
|
||||||
```
|
|
||||||
Nutzer gibt Auftrag
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
/coder → qwen3.5-coder (:8001) → Implementierung + git commit
|
|
||||||
│
|
|
||||||
▼
|
|
||||||
/judge → qwen3.5-judge (:8002) → Review: PASS / FAIL + Blocker
|
|
||||||
│
|
|
||||||
FAIL? ▼
|
|
||||||
/fix → qwen3.5-coder (:8001) → Fixes + git commit
|
|
||||||
│
|
|
||||||
PASS? ▼
|
|
||||||
/shipit → qwen3.5-judge (:8002) → Finale Freigabe: SHIP / NO-SHIP
|
|
||||||
(nur bei "PASS WITH CONCERNS" — klares PASS → direkt SHIP)
|
|
||||||
|
|
||||||
/optimize = Coder→Judge→Fix-Schleife automatisch (bis PASS oder max. N Runden)
|
|
||||||
--interactive: pausiert nach PASS für menschlichen Checkpoint + optionale Zusatzaufträge
|
|
||||||
```
|
|
||||||
|
|
||||||
Beide Modelle laufen als **separate llama.cpp-Docker-Container** und sprechen eine
|
|
||||||
OpenAI-kompatible API (`/v1/chat/completions`). pi agent wechselt automatisch zwischen
|
|
||||||
den Endpunkten wenn du ein `/judge`-, `/fix`- oder `/coder`-Kommando aufrufst.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Modelle
|
|
||||||
|
|
||||||
| Rolle | Modell | Port | Container | Alias |
|
|
||||||
|--------|---------------------------------------------------|------|------------------|----------------|
|
|
||||||
| Coder | Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS | 8001 | qwen36-27b-coder | qwen3.5-coder |
|
|
||||||
| Judge | Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS | 8002 | qwen36-27b-judge | qwen3.5-judge |
|
|
||||||
|
|
||||||
Beide Container verwenden dasselbe GGUF-Datei, aber mit unterschiedlichen
|
|
||||||
Serverparametern (Kontext, Temperatur, Parallelität).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Docker mit NVIDIA-GPU-Support:
|
|
||||||
```bash
|
|
||||||
# NVIDIA Container Toolkit installieren (falls nicht vorhanden)
|
|
||||||
distribution=$(. /etc/os-release; echo $ID$VERSION_ID)
|
|
||||||
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
|
|
||||||
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list \
|
|
||||||
| sudo tee /etc/apt/sources.list.d/nvidia-docker.list
|
|
||||||
sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
|
|
||||||
sudo systemctl restart docker
|
|
||||||
```
|
|
||||||
- Mindestens eine NVIDIA-GPU (empfohlen: zwei GPUs mit je ≥ 16 GB VRAM)
|
|
||||||
- GGUF-Modell vorhanden unter:
|
|
||||||
`$HF_HOME/models/qwen3/Qwen3.6-27B-Uncensored-HauhauCS-Aggressive-IQ4_XS.gguf`
|
|
||||||
- Standard-Pfad: `HF_HOME=/home/dschlueter/nvme2n1p7_home/huggingface`
|
|
||||||
- Überschreibbar: `HF_HOME=/anderer/pfad ./start-servers.sh`
|
|
||||||
- [pi agent](https://github.com/earendil-works/pi) installiert (`~/.pi/`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Repository klonen
|
|
||||||
git clone <repo-url> ~/pi_coder
|
|
||||||
cd ~/pi_coder
|
|
||||||
|
|
||||||
# 2. Extension und Modell-Config nach ~/.pi/agent/ deployen
|
|
||||||
./install.sh
|
|
||||||
|
|
||||||
# 3. pi agent neu laden (in der pi-Oberfläche)
|
|
||||||
# /reload
|
|
||||||
|
|
||||||
# 4. Server starten
|
|
||||||
./start-servers.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Nach späteren Änderungen an `pi-coder-judge-extension.ts` oder `models.json`:
|
|
||||||
```bash
|
|
||||||
./install.sh # kopiert nach ~/.pi/agent/
|
|
||||||
# dann /reload in pi agent
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Server starten / stoppen / status
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Beide Server parallel starten (empfohlen — dauert 1–3 Minuten)
|
|
||||||
./start-servers.sh
|
|
||||||
|
|
||||||
# Einzeln starten (z.B. nur einen neu starten)
|
|
||||||
./start-coder.sh # Port 8001
|
|
||||||
./start-judge.sh # Port 8002
|
|
||||||
|
|
||||||
# Beide stoppen
|
|
||||||
./stop-servers.sh
|
|
||||||
|
|
||||||
# Status beider Server prüfen
|
|
||||||
./status.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
`start-servers.sh` startet beide Container gleichzeitig und wartet bis beide
|
|
||||||
HTTP-ready sind. Logs werden getrennt gesammelt und nur bei Fehler ausgegeben.
|
|
||||||
|
|
||||||
Wenn Server bereits laufen und du `start-servers.sh` (oder ein Einzelskript)
|
|
||||||
aufrufst, werden die laufenden Container zuerst per `docker rm -f` gestoppt
|
|
||||||
und dann neu gestartet — ein laufender Inference-Request wird dabei abgebrochen.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## llama.cpp-Serverparameter im Detail
|
|
||||||
|
|
||||||
### Gemeinsame Parameter
|
|
||||||
|
|
||||||
| Parameter | Wert | Bedeutung |
|
|
||||||
|---|---|---|
|
|
||||||
| `--jinja` | — | Verwendet das im GGUF eingebettete Jinja-Chat-Template (Qwen-Format). Notwendig für korrekte `<\|im_start\|>`-Tokens. |
|
|
||||||
| `--no-context-shift` | — | Kontextfenster wird **nicht** verschoben wenn es voll ist — stattdessen Fehler. Verhindert stille Datenverluste. |
|
|
||||||
| `--repeat-penalty 1.05` | — | Leichte Penalty für Wiederholungen. Wert > 1.0 unterdrückt Loops. |
|
|
||||||
| `--top-k 40` | — | Nur die 40 wahrscheinlichsten nächsten Tokens werden berücksichtigt. |
|
|
||||||
| `--min-p 0.01` | — | Tokens mit Wahrscheinlichkeit < 1 % des wahrscheinlichsten Tokens werden ausgeschlossen. |
|
|
||||||
| `-ngl 999` | — | Alle Layer auf die GPU laden (999 = „alle"). Bei zu wenig VRAM reduzieren. |
|
|
||||||
| `-fa on` | — | Flash Attention — schnellere Attention-Berechnung, weniger VRAM für den Attention-Pass. |
|
|
||||||
| `--kv-unified` | — | Einheitlicher KV-Cache über alle Schichten. Effizienter bei langen Kontexten. |
|
|
||||||
| `--cache-type-k q4_0` | — | KV-Cache Keys in 4-Bit quantisiert. Spart ~75 % VRAM gegenüber fp16 — nötig für 256K Kontext auf 2× 24 GB. |
|
|
||||||
| `--cache-type-v q4_0` | — | KV-Cache Values ebenfalls 4-Bit quantisiert. |
|
|
||||||
| `--cont-batching` | — | Continuous Batching: neue Anfragen werden in laufende Batches eingefügt — höherer Durchsatz bei mehreren parallelen Anfragen. |
|
|
||||||
| `--main-gpu 0` | — | GPU-Index (0 = erste der übergebenen GPUs) für Nicht-Tensor-Operationen. |
|
|
||||||
| `--tensor-split 0.5,0.5` | — | Modell-Gewichte 50/50 auf zwei GPUs aufteilen. |
|
|
||||||
| `--gpus '"device=1,2"'` | — | Docker-Argument: GPU 1 und GPU 2 dem Container übergeben. |
|
|
||||||
|
|
||||||
### Coder-Server (Port 8001) — optimiert für Coding-Aufgaben
|
|
||||||
|
|
||||||
| Parameter | Wert | Erklärung / Wirkung |
|
|
||||||
|---|---|---|
|
|
||||||
| `-c 262144` | 256K Tokens | Sehr großes Kontextfenster: gesamte Codebasis + langer Gesprächsverlauf passt rein. **Sehr hoher VRAM-Bedarf.** Reduziere auf `65536` wenn VRAM knapp. |
|
|
||||||
| `-n 16384` | 16K Tokens | Maximale Ausgabelänge pro Anfrage. Für Kommentieraufgaben (`/update_doku`) nötig. |
|
|
||||||
| `--temp 0.2` | — | Niedrige Temperatur: deterministisch, konsistenter Code. Erhöhe auf `0.4–0.6` für kreativere Lösungsansätze. |
|
|
||||||
| `--top-p 0.95` | — | Nucleus Sampling: 95 % der Wahrscheinlichkeitsmasse. Passend zu temp 0.2. |
|
|
||||||
| `--batch-size 1024` | — | Prompt-Verarbeitungs-Batch. Größer = schnelleres Einlesen langer Dateien. |
|
|
||||||
| `--ubatch-size 512` | — | Micro-Batch für GPU-Kernel. Muss ≤ batch-size sein. |
|
|
||||||
| `--parallel 2` | — | 2 gleichzeitige Request-Slots. Nützlich wenn pi agent schnell Folgeanfragen schickt. |
|
|
||||||
|
|
||||||
### Judge-Server (Port 8002) — optimiert für Reviews
|
|
||||||
|
|
||||||
| Parameter | Wert | Erklärung / Wirkung |
|
|
||||||
|---|---|---|
|
|
||||||
| `-c 262144` | 256K Tokens | Großes Kontextfenster: nötig bei langen /optimize-Runden, wo der Gesprächsverlauf stark anwächst. |
|
|
||||||
| `-n 16384` | 16K Tokens | Lange Reviews und Begründungen passen vollständig in die Ausgabe. |
|
|
||||||
| `--temp 0.1` | — | Sehr niedrige Temperatur: maximale Konsistenz und Reproduzierbarkeit der Urteile. |
|
|
||||||
| `--top-p 0.9` | — | Etwas enger als beim Coder — weniger Variation im Urteil gewünscht. |
|
|
||||||
| `--batch-size 512` | — | Kleiner als beim Coder — Judge bekommt selten sehr lange Prompts. |
|
|
||||||
| `--ubatch-size 256` | — | Entsprechend kleiner. |
|
|
||||||
| `--parallel 1` | — | Judge-Aufgaben sind immer sequenziell im Workflow, daher 1 Slot ausreichend. |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Anpassung für eine einzelne GPU
|
|
||||||
|
|
||||||
Mit einer GPU läuft das Modell vollständig auf dieser GPU statt verteilt.
|
|
||||||
Anpassungen in `start-coder.sh` und `start-judge.sh`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Vorher (2 GPUs, device 1 und 2):
|
|
||||||
--gpus '"device=1,2"' \
|
|
||||||
--main-gpu 0 \
|
|
||||||
--tensor-split 0.5,0.5 \
|
|
||||||
|
|
||||||
# Nachher (1 GPU, z.B. device 0):
|
|
||||||
--gpus '"device=0"' \
|
|
||||||
--main-gpu 0 \
|
|
||||||
# --tensor-split ← diese Zeile komplett entfernen
|
|
||||||
```
|
|
||||||
|
|
||||||
### VRAM-Abschätzung für das 27B IQ4_XS-Modell
|
|
||||||
|
|
||||||
| Komponente | Größe (ca.) |
|
|
||||||
|---|---|
|
|
||||||
| Modell-Gewichte (IQ4_XS, 27B) | ~14,5 GB |
|
|
||||||
| KV-Cache bei 128K Kontext (q8_0) | ~14 GB |
|
|
||||||
| KV-Cache bei 64K Kontext (q8_0) | ~7 GB |
|
|
||||||
| KV-Cache bei 32K Kontext (q8_0) | ~3,5 GB |
|
|
||||||
|
|
||||||
Bei einer **24-GB-GPU** ist nur ein Server gleichzeitig sinnvoll betreibbar:
|
|
||||||
- Modell-Gewichte: ~14,5 GB
|
|
||||||
- KV-Cache bei 32K Kontext: ~3,5 GB
|
|
||||||
- Summe: ~18 GB → passt mit Puffer
|
|
||||||
|
|
||||||
**Empfehlung für eine 24-GB-GPU:**
|
|
||||||
```bash
|
|
||||||
# Coder — Kontext reduzieren
|
|
||||||
-c 32768 # statt 131072
|
|
||||||
-n 8192 # statt 16384
|
|
||||||
|
|
||||||
# Judge — Kontext reduzieren
|
|
||||||
-c 32768 # statt 131072
|
|
||||||
```
|
|
||||||
|
|
||||||
Bei einer **16-GB-GPU** ist die Modellgröße allein schon grenzwertig.
|
|
||||||
Entweder ein kleineres Modell verwenden oder die Quantisierung weiter erhöhen (IQ3_XS, Q4_K_M).
|
|
||||||
|
|
||||||
### Beide Server auf einer GPU betreiben
|
|
||||||
|
|
||||||
Technisch möglich, aber beide Server laden das Modell gleichzeitig → doppelter VRAM-Bedarf.
|
|
||||||
Auf einer 24-GB-GPU daher **nicht empfohlen**. Alternativen:
|
|
||||||
|
|
||||||
- Nur einen Server gleichzeitig starten (manuell umschalten)
|
|
||||||
- Kleinere Quantisierung wählen (IQ3_XS: ~11 GB)
|
|
||||||
- `ollama` als Alternative — lädt Modelle bei Bedarf und entlädt sie wieder
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Parameter-Tuning-Guide
|
|
||||||
|
|
||||||
### Temperatur (`--temp`)
|
|
||||||
|
|
||||||
| Wert | Eignung |
|
|
||||||
|---|---|
|
|
||||||
| `0.0–0.1` | Maximale Reproduzierbarkeit. Gut für Judge/Review. |
|
|
||||||
| `0.1–0.3` | Guter Kompromiss für Coding. **Empfohlen für Coder.** |
|
|
||||||
| `0.4–0.6` | Kreativere Lösungen, mehr Varianz. Sinnvoll für Prototyping. |
|
|
||||||
| `0.7–1.0` | Kreativschreiben, Brainstorming. Für Coding meist zu viel Rauschen. |
|
|
||||||
|
|
||||||
### Kontextgröße (`-c`)
|
|
||||||
|
|
||||||
Je größer der Kontext, desto mehr VRAM braucht der KV-Cache.
|
|
||||||
Faustregel: KV-Cache ≈ `context_size × layers × head_dim × 2 × bytes_per_element`.
|
|
||||||
Bei q8_0 (1 Byte/Element) und Qwen3-27B (28 Schichten, 128 Head-Dim, 32 Heads):
|
|
||||||
KV-Cache ≈ `context_size × 28 × 128 × 32 × 2 × 1 Byte ≈ context_size × 0,23 MB`
|
|
||||||
|
|
||||||
| Kontext | KV-Cache (q4_0) | Empfehlung |
|
|
||||||
|---|---|---|
|
|
||||||
| 32 768 | ~1,9 GB | 1 × 16-GB-GPU |
|
|
||||||
| 65 536 | ~3,7 GB | 1 × 24-GB-GPU |
|
|
||||||
| 131 072 | ~7,5 GB | 2 × 16-GB-GPU |
|
|
||||||
| 262 144 | ~15 GB | 2 × 24-GB-GPU — **aktuell gesetzt** |
|
|
||||||
|
|
||||||
### KV-Cache-Quantisierung
|
|
||||||
|
|
||||||
| `--cache-type-k/v` | VRAM | Qualität |
|
|
||||||
|---|---|---|
|
|
||||||
| `f16` | 100 % (Basis) | Referenz |
|
|
||||||
| `q8_0` | ~50 % | Kaum merklich schlechter |
|
|
||||||
| `q4_0` | ~25 % | Merklicher Qualitätsverlust bei langen Kontexten — aber nötig für 256K Kontext auf 2× 24 GB. **Aktuell gesetzt.** |
|
|
||||||
|
|
||||||
### Parallelität (`--parallel`)
|
|
||||||
|
|
||||||
Mehr parallele Slots erhöhen den Durchsatz bei gleichzeitigen Anfragen, aber jeder Slot
|
|
||||||
reserviert Speicher im KV-Cache. Im pi-coder-Workflow sind echte Parallelaufrufe selten,
|
|
||||||
daher ist `--parallel 1` für den Judge ausreichend. Coder `--parallel 2` bietet Puffer
|
|
||||||
wenn pi agent Folgeanfragen schnell hintereinander schickt.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Dateien
|
|
||||||
|
|
||||||
| Datei | Zweck |
|
|
||||||
|---|---|
|
|
||||||
| `pi-coder-judge-extension.ts` | pi agent Extension (Kommandos, Tools, Hooks) |
|
|
||||||
| `models.json` | Provider- und Modell-Konfiguration für pi agent |
|
|
||||||
| `start-servers.sh` | Beide Server parallel starten (empfohlen) |
|
|
||||||
| `start-coder.sh` | Nur Coder-Container starten (Port 8001) |
|
|
||||||
| `start-judge.sh` | Nur Judge-Container starten (Port 8002) |
|
|
||||||
| `stop-servers.sh` | Beide Container stoppen |
|
|
||||||
| `status.sh` | Laufstatus beider Server anzeigen |
|
|
||||||
| `install.sh` | Extension + models.json nach `~/.pi/agent/` kopieren |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## pi-Kommandos (Kurzübersicht)
|
|
||||||
|
|
||||||
| Kommando | Modell | Beschreibung |
|
|
||||||
|---|---|---|
|
|
||||||
| `/coder <auftrag>` | Coder | TASK.md anlegen, Implementierung starten |
|
|
||||||
| `/judge [fokus]` | Judge | Code-Review gegen TASK.md + letzten Commit |
|
|
||||||
| `/fix [hinweis]` | Coder | Judge-Kritik beheben, committen |
|
|
||||||
| `/shipit` | Judge | Finale Freigabeprüfung |
|
|
||||||
| `/optimize <auftrag> [--rounds N] [--with-doku] [--continue] [--interactive]` | beide | Vollautomatische Schleife bis PASS (Standard: 2 Runden, Runde 1: Quick-Judge) |
|
|
||||||
| `/optimize ... [--no-tests] [--approve-concerns] [--test-cmd "cmd"] [--test-timeout N]` | beide | Test-Erkennung überspringen / PASS WITH CONCERNS direkt shippern |
|
|
||||||
| `/patch <änderung>` | Coder | Gezielte Minimaländerung ohne Review |
|
|
||||||
| `/quick_check [was]` | Judge | Schnelle Prüfung der letzten Änderung |
|
|
||||||
| `/version` | — | Versionsnummer erhöhen (SemVer + Git-Tag) |
|
|
||||||
| `/update_doku` | Coder | Code kommentieren + README + Bedienungsanleitung |
|
|
||||||
| `/plan <auftrag>` | Coder | Implementierungsplan in PLAN.md (kein Code) |
|
|
||||||
| `/continue` | Coder | Unterbrochenen Prozess fortsetzen |
|
|
||||||
| `/cancel` | — | Laufenden Loop nach aktuellem Schritt abbrechen |
|
|
||||||
| `/new_project <pfad>` | — | Neues Projektverzeichnis + git init |
|
|
||||||
|
|
||||||
Ausführliche Beschreibung aller Kommandos mit Beispielen: siehe **BEDIENUNGSANLEITUNG.md**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Live-Aktivitätsstatus
|
|
||||||
|
|
||||||
Während der Ausführung zeigt pi_coder in der Statuszeile, was gerade passiert:
|
|
||||||
|
|
||||||
| Situation | Anzeige |
|
|
||||||
|---|---|
|
|
||||||
| Coder implementiert | `Coder implementiert…` |
|
|
||||||
| edit-Tool aktiv | `Editiere src/main.py…` |
|
|
||||||
| git commit | `Git-Commit…` |
|
|
||||||
| Judge reviewt (Runde 2/2) | `Judge reviewt (Runde 2/2)…` |
|
|
||||||
| Tests laufen | `Tests laufen…` |
|
|
||||||
| Fix-Phase | `Coder fixt Blocker…` |
|
|
||||||
| Interactive-Pause (--interactive) | `⏸ PASS – warte auf /continue…` |
|
|
||||||
|
|
||||||
So ist jederzeit erkennbar, in welcher Phase sich der automatische Loop befindet.
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
# pi-coder Beispielprojekte
|
|
||||||
|
|
||||||
Vier kleine, eigenständige Projekte als Demonstrationsgrundlage für die pi-coder-Features.
|
|
||||||
Jedes Projekt startet bewusst unvollständig — genau der Ausgangspunkt, für den pi-coder gebaut ist.
|
|
||||||
|
|
||||||
## Übersicht
|
|
||||||
|
|
||||||
| Verzeichnis | Sprache | Demonstriert |
|
|
||||||
|---|---|---|
|
|
||||||
| `python-calculator/` | Python | `/optimize` mit `--test-cmd pytest` |
|
|
||||||
| `rust-wordcount/` | Rust | `/optimize` mit `--test-cmd "cargo test"` + `/version` |
|
|
||||||
| `go-fibonacci/` | Go | `/optimize --interactive` + `/continue` + `/shipit` |
|
|
||||||
| `c-linkedlist/` | C | `/quick_check` + `/fix` + `/patch` |
|
|
||||||
|
|
||||||
## Demo-Workflow
|
|
||||||
|
|
||||||
### Schritt 1 — Vorbereitung: Sub-Repos anlegen
|
|
||||||
|
|
||||||
Jedes Example braucht ein eigenes git-Repo, damit pi-coder commit-basierte
|
|
||||||
Features nutzen kann (Loop-Erkennung, Diff-Anzeige, `/version`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
for dir in python-calculator rust-wordcount go-fibonacci c-linkedlist; do
|
|
||||||
cd examples/$dir
|
|
||||||
git init && git add -A && git commit -m "feat: initial $dir"
|
|
||||||
cd ../..
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
Für `/version` im rust-wordcount-Beispiel zusätzlich:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd examples/rust-wordcount && git tag v0.1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Schritt 2 — Demo ausführen
|
|
||||||
|
|
||||||
In pi das jeweilige Unterverzeichnis als Arbeitsverzeichnis öffnen.
|
|
||||||
Die genauen Befehle stehen im README.md des jeweiligen Examples.
|
|
||||||
Zeitmessung: Systemuhr notieren oder Terminal-Kommando `time` nutzen.
|
|
||||||
|
|
||||||
### Schritt 3 — Protokoll ausfüllen
|
|
||||||
|
|
||||||
Jedes Example enthält eine `PROTOKOLL.md`.
|
|
||||||
Startzeit, Endzeit, Rundenanzahl und Endergebnis eintragen.
|
|
||||||
|
|
||||||
### Schritt 4 — Ausgangszustand wiederherstellen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bash examples/restore-all.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Das Skript löscht Sub-Repos, restauriert alle Quelldateien aus dem Haupt-Repo
|
|
||||||
und bereinigt Build-Artefakte (`target/`, `__pycache__` etc.).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Empfohlene Demo-Reihenfolge
|
|
||||||
|
|
||||||
| # | Beispiel | Geschätzte Dauer | Highlights |
|
|
||||||
|---|---|---|---|
|
|
||||||
| 1 | `python-calculator` | ~5–10 min | Einstieg, Test-Loop |
|
|
||||||
| 2 | `c-linkedlist` | ~5 min | `/quick_check` + `/fix`, kein Loop |
|
|
||||||
| 3 | `rust-wordcount` | ~10–15 min | Loop + `/version` |
|
|
||||||
| 4 | `go-fibonacci` | ~15–20 min | `--interactive` + `/shipit` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Weitere Details
|
|
||||||
|
|
||||||
[python-calculator](python-calculator/README.md) ·
|
|
||||||
[rust-wordcount](rust-wordcount/README.md) ·
|
|
||||||
[go-fibonacci](go-fibonacci/README.md) ·
|
|
||||||
[c-linkedlist](c-linkedlist/README.md)
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
# Demo-Protokoll: c-linkedlist
|
|
||||||
|
|
||||||
## Lauf 1
|
|
||||||
|
|
||||||
**Datum:**
|
|
||||||
|
|
||||||
**Befehl /quick_check:**
|
|
||||||
```
|
|
||||||
/quick_check "Gibt es Speicherlecks oder sonstige Probleme in diesem C-Projekt?"
|
|
||||||
```
|
|
||||||
**Startzeit:**
|
|
||||||
**Endzeit:**
|
|
||||||
**Dauer (min):**
|
|
||||||
**Ergebnis:** OK / PROBLEM (Kurzbeschreibung):
|
|
||||||
|
|
||||||
**Befehl /fix:**
|
|
||||||
```
|
|
||||||
/fix "Implementiere list_free() korrekt, sodass valgrind --leak-check=full sauber ist."
|
|
||||||
```
|
|
||||||
**Startzeit:**
|
|
||||||
**Endzeit:**
|
|
||||||
**Dauer (min):**
|
|
||||||
**Ergebnis:** erledigt / fehlgeschlagen
|
|
||||||
|
|
||||||
**Befehl /patch (optional):**
|
|
||||||
```
|
|
||||||
/patch "Ergänze list_search(head, value) in Header und Implementierung.
|
|
||||||
Gibt den ersten Node* mit dem gesuchten Wert zurück, oder NULL."
|
|
||||||
```
|
|
||||||
**Startzeit:**
|
|
||||||
**Endzeit:**
|
|
||||||
**Dauer (min):**
|
|
||||||
**Besonderheiten / Beobachtungen:**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
# C Linked List
|
|
||||||
|
|
||||||
Vollständige einfach-verkettete Liste — bis auf `list_free()`, das als leerer Stub vorliegt.
|
|
||||||
Jeder Programmlauf leckt den gesamten Listen-Speicher.
|
|
||||||
|
|
||||||
## Aktueller Stand
|
|
||||||
|
|
||||||
```
|
|
||||||
linked_list.h Interface: node_new, list_prepend, list_append, list_print, list_free, list_length
|
|
||||||
linked_list.c Alles implementiert — außer list_free() (Stub, tut nichts)
|
|
||||||
main.c Baut Liste 1–5, gibt sie aus, ruft list_free() auf (ohne Wirkung)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Demo 1: `/quick_check` als Diagnose
|
|
||||||
|
|
||||||
```
|
|
||||||
/quick_check "Gibt es Speicherlecks oder sonstige Probleme in diesem C-Projekt?"
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Judge analysiert den Code und identifiziert das leere `list_free()` als Speicherleck-Quelle.
|
|
||||||
|
|
||||||
## Demo 2: `/fix` für gezieltes Nacharbeiten
|
|
||||||
|
|
||||||
```
|
|
||||||
/fix "Implementiere list_free() korrekt, sodass valgrind --leak-check=full sauber ist."
|
|
||||||
```
|
|
||||||
|
|
||||||
Coder implementiert die Funktion, committet. Kein vollständiger Judge-Loop —
|
|
||||||
ideal für kleine, klar abgegrenzte Fixes.
|
|
||||||
|
|
||||||
## Demo 3: `/patch` für Minimal-Erweiterungen
|
|
||||||
|
|
||||||
```
|
|
||||||
/patch "Ergänze list_search(head, value) in Header und Implementierung.
|
|
||||||
Gibt den ersten Node* mit dem gesuchten Wert zurück, oder NULL."
|
|
||||||
```
|
|
||||||
|
|
||||||
pi-coder wendet einen unified diff an (`apply_patch`-Tool), ohne den vollständigen Loop.
|
|
||||||
|
|
||||||
## Manueller Build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
gcc -Wall -Wextra -o ll_demo linked_list.c main.c
|
|
||||||
./ll_demo
|
|
||||||
|
|
||||||
# Mit Leak-Check:
|
|
||||||
valgrind --leak-check=full ./ll_demo
|
|
||||||
```
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "linked_list.h"
|
|
||||||
|
|
||||||
Node *node_new(int value) {
|
|
||||||
Node *n = malloc(sizeof(Node));
|
|
||||||
n->value = value;
|
|
||||||
n->next = NULL;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node *list_prepend(Node *head, int value) {
|
|
||||||
Node *n = node_new(value);
|
|
||||||
n->next = head;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node *list_append(Node *head, int value) {
|
|
||||||
Node *n = node_new(value);
|
|
||||||
if (!head) return n;
|
|
||||||
Node *cur = head;
|
|
||||||
while (cur->next) cur = cur->next;
|
|
||||||
cur->next = n;
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
void list_print(const Node *head) {
|
|
||||||
for (const Node *cur = head; cur; cur = cur->next)
|
|
||||||
printf("%d ", cur->value);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BUG: Speicher wird nicht freigegeben — valgrind meldet Leaks. */
|
|
||||||
void list_free(Node *head) {
|
|
||||||
(void)head; /* TODO: implementieren */
|
|
||||||
}
|
|
||||||
|
|
||||||
int list_length(const Node *head) {
|
|
||||||
int len = 0;
|
|
||||||
for (const Node *cur = head; cur; cur = cur->next)
|
|
||||||
len++;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
#ifndef LINKED_LIST_H
|
|
||||||
#define LINKED_LIST_H
|
|
||||||
|
|
||||||
typedef struct Node {
|
|
||||||
int value;
|
|
||||||
struct Node *next;
|
|
||||||
} Node;
|
|
||||||
|
|
||||||
Node *node_new(int value);
|
|
||||||
Node *list_prepend(Node *head, int value);
|
|
||||||
Node *list_append(Node *head, int value);
|
|
||||||
void list_print(const Node *head);
|
|
||||||
void list_free(Node *head);
|
|
||||||
int list_length(const Node *head);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include "linked_list.h"
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
Node *list = NULL;
|
|
||||||
|
|
||||||
for (int i = 1; i <= 5; i++)
|
|
||||||
list = list_append(list, i);
|
|
||||||
|
|
||||||
printf("Liste: ");
|
|
||||||
list_print(list);
|
|
||||||
printf("Länge: %d\n", list_length(list));
|
|
||||||
|
|
||||||
list_free(list); /* leckt wegen unvollständigem TODO */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
# Demo-Protokoll: go-fibonacci
|
|
||||||
|
|
||||||
## Lauf 1
|
|
||||||
|
|
||||||
**Datum:**
|
|
||||||
**Befehl:**
|
|
||||||
```
|
|
||||||
/optimize "Ersetze die naive Rekursion durch Memoization.
|
|
||||||
fib(50) soll in unter 1ms abgeschlossen sein.
|
|
||||||
Bestehende Tests müssen weiterhin grün bleiben." \
|
|
||||||
--test-cmd "go test ./..." --interactive
|
|
||||||
```
|
|
||||||
**Startzeit:**
|
|
||||||
**Ende Loop (PASS):**
|
|
||||||
**Dauer Loop (min):**
|
|
||||||
**Runden:**
|
|
||||||
**Endergebnis Loop:** PASS / PASS WITH CONCERNS
|
|
||||||
|
|
||||||
**Befehl im --interactive-Checkpoint:**
|
|
||||||
```
|
|
||||||
/continue "Gib zusätzlich die Berechnungszeit in Mikrosekunden aus."
|
|
||||||
```
|
|
||||||
*(oder: `/continue` ohne Zusatzauftrag)*
|
|
||||||
|
|
||||||
**Startzeit /continue:**
|
|
||||||
**Ende /continue:**
|
|
||||||
|
|
||||||
**Befehl /shipit:**
|
|
||||||
```
|
|
||||||
/shipit
|
|
||||||
```
|
|
||||||
**Startzeit /shipit:**
|
|
||||||
**Endzeit /shipit:**
|
|
||||||
**Endergebnis /shipit:** SHIP / NO-SHIP
|
|
||||||
**Besonderheiten / Beobachtungen:**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
# Go Fibonacci
|
|
||||||
|
|
||||||
Naive rekursive Fibonacci-Implementierung — korrekt, aber exponentiell langsam.
|
|
||||||
`fib(45)` dauert mehrere Sekunden; `fib(50)` läuft praktisch nicht durch.
|
|
||||||
|
|
||||||
## Aktueller Stand
|
|
||||||
|
|
||||||
```
|
|
||||||
main.go fib(n) — rekursiv, O(2^n)
|
|
||||||
main_test.go TestFib mit 5 Tabellen-Tests (alle grün)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Demo 1: `/optimize --interactive`
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize "Ersetze die naive Rekursion durch einfache Memoization mit einer map[int]int.
|
|
||||||
Kein Mutex, kein Goroutine-Overhead — Single-Threaded reicht.
|
|
||||||
fib(50) soll in unter 1ms abgeschlossen sein.
|
|
||||||
Bestehende Tests müssen weiterhin grün bleiben." \
|
|
||||||
--test-cmd "go test ." --interactive
|
|
||||||
```
|
|
||||||
|
|
||||||
Nach dem ersten PASS hält pi-coder im **interaktiven Checkpoint** an.
|
|
||||||
Hier kann ein Zusatzauftrag erteilt werden:
|
|
||||||
|
|
||||||
```
|
|
||||||
/continue "Gib zusätzlich die Berechnungszeit in Mikrosekunden aus."
|
|
||||||
```
|
|
||||||
|
|
||||||
Oder einfach bestätigen:
|
|
||||||
|
|
||||||
```
|
|
||||||
/continue
|
|
||||||
```
|
|
||||||
|
|
||||||
## Demo 2: Abschluss mit `/shipit`
|
|
||||||
|
|
||||||
```
|
|
||||||
/shipit
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Judge prüft nochmals explizit auf Produktionsreife und gibt SHIP oder NO-SHIP zurück.
|
|
||||||
|
|
||||||
## Manueller Test
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go test .
|
|
||||||
go run main.go
|
|
||||||
```
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func BenchmarkFib50(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
fib(50)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
module fibonacci
|
|
||||||
|
|
||||||
go 1.21
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// fib berechnet die n-te Fibonacci-Zahl rekursiv.
|
|
||||||
// Korrekt, aber für n > 40 sehr langsam (exponentiell).
|
|
||||||
func fib(n int) int {
|
|
||||||
if n <= 1 {
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
return fib(n-1) + fib(n-2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
for i := 0; i <= 10; i++ {
|
|
||||||
fmt.Printf("fib(%2d) = %d\n", i, fib(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestFib(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
n, want int
|
|
||||||
}{
|
|
||||||
{0, 0},
|
|
||||||
{1, 1},
|
|
||||||
{2, 1},
|
|
||||||
{5, 5},
|
|
||||||
{10, 55},
|
|
||||||
}
|
|
||||||
for _, c := range cases {
|
|
||||||
if got := fib(c.n); got != c.want {
|
|
||||||
t.Errorf("fib(%d) = %d, want %d", c.n, got, c.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
examples/python-calculator/.gitignore
vendored
2
examples/python-calculator/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
# Demo-Protokoll: python-calculator
|
|
||||||
|
|
||||||
## Lauf 1
|
|
||||||
|
|
||||||
**Datum:**
|
|
||||||
**Befehl:**
|
|
||||||
```
|
|
||||||
/optimize "Ergänze multiply, divide (wirft ZeroDivisionError bei 0) und power.
|
|
||||||
Schreibe pytest-Tests für alle neuen Funktionen." \
|
|
||||||
--test-cmd "pytest test_calculator.py -v"
|
|
||||||
```
|
|
||||||
**Startzeit:**
|
|
||||||
**Endzeit:**
|
|
||||||
**Dauer (min):**
|
|
||||||
**Runden:**
|
|
||||||
**Endergebnis:** PASS / PASS WITH CONCERNS / SHIP / NO-SHIP
|
|
||||||
**Besonderheiten / Beobachtungen:**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
# Python Calculator
|
|
||||||
|
|
||||||
Einfacher Taschenrechner mit `add()` und `subtract()`.
|
|
||||||
Multiply, divide, power und Fehlerbehandlung fehlen noch.
|
|
||||||
|
|
||||||
## Aktueller Stand
|
|
||||||
|
|
||||||
```
|
|
||||||
calculator.py add(), subtract()
|
|
||||||
test_calculator.py 5 pytest-Tests (alle grün)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Demo: `/optimize` mit Test-Integration
|
|
||||||
|
|
||||||
```
|
|
||||||
/optimize "Ergänze multiply, divide (wirft ZeroDivisionError bei 0) und power.
|
|
||||||
Schreibe pytest-Tests für alle neuen Funktionen." \
|
|
||||||
--test-cmd "pytest test_calculator.py -v"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Was pi-coder hier zeigt:**
|
|
||||||
- Coder implementiert, committet
|
|
||||||
- Extension führt `pytest` aus und übergibt das Ergebnis an den Judge
|
|
||||||
- Judge bewertet Korrektheit anhand der Testergebnisse
|
|
||||||
- Bei FAIL: Coder fixt, nächste Runde
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install pytest
|
|
||||||
```
|
|
||||||
|
|
||||||
## Weitere Demo-Befehle nach dem `/optimize`-Lauf
|
|
||||||
|
|
||||||
```
|
|
||||||
/quick_check "Sind alle Randfälle (negative Zahlen, floats) korrekt behandelt?"
|
|
||||||
```
|
|
||||||
Schnelle Einzel-Beurteilung ohne neuen Fix-Loop.
|
|
||||||
|
|
||||||
```
|
|
||||||
/update_doku
|
|
||||||
```
|
|
||||||
Lässt den Coder Code-Kommentare ergänzen, README aktualisieren und eine
|
|
||||||
Bedienungsanleitung erzeugen.
|
|
||||||
|
|
||||||
## Manueller Test
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pytest test_calculator.py -v
|
|
||||||
python calculator.py
|
|
||||||
```
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
def add(a, b):
|
|
||||||
return a + b
|
|
||||||
|
|
||||||
|
|
||||||
def subtract(a, b):
|
|
||||||
return a - b
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
print(add(3, 4)) # 7
|
|
||||||
print(subtract(10, 3)) # 7
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue