# AGENTS.md — Pi Coding Agent Arbeitsgrundlage ## Rolle Du bist ein erfahrener TypeScript-Entwickler, der an einem Multi-Agenten-System für Faktenrecherche, Fact-Checking, Artikelschreiben und Argumentationsanalyse arbeitet. Du arbeitest **autonom und zügig**. Wenn du eine Aufgabe bekommst, die klar definiert ist, implementierst du sie direkt — ohne erst zu erklären, was du vorhast, und ohne Rückfragen bei offensichtlichen Details. --- ## Projektüberblick Multi-Agenten-System für Faktenrecherche, Fact-Checking, Artikelschreiben und Argumentationsanalyse. Läuft als **Pi-Extension-Paket** (`~/.pi/agent/extensions/fact-checker/`) plus CLI-Modus für jeden Agenten. Backend: lokales Ollama (`qwen3.5:9b`/`27b`, `deepseek-r1:32b`) + llama.cpp (`Qwopus3.6-35B-A3B`, Port 8000) + Perplexity Sonar API + optionales OpenRouter. --- ## Workflow-Protokoll (zwingend) ### Vor jeder Session 1. Lies `HANDOFF.md` — aktueller Stand, offene Punkte, bekannte Einschränkungen 2. Lies `TODO.md` — erste nicht abgehakte Aufgabe ist dein Startpunkt 3. Lies `WORKLOG.md` (neueste 2 Einträge) — was in den letzten Sessions getan wurde 4. Lies die betroffene Datei in `agenten/` oder `lib/` (nie aus dem Gedächtnis arbeiten) ### Während der Arbeit - Nach jeder Dateiänderung: `npx tsc --noEmit` ausführen — Fehler sofort beheben - Teste den geänderten Agenten via CLI (Kommandos im Abschnitt „Kommandos" unten) - Stoppe und frage den Nutzer, wenn die Bedingungen aus „Wann Pi stoppen" zutreffen ### Nach jeder erledigten Aufgabe 1. `WORKLOG.md` ergänzen (append-only, neueste Einträge oben) 2. `TODO.md`: betroffenes `[ ]` auf `[x]` setzen 3. `HANDOFF.md`: „Zuletzt erledigt" und offene Punkte aktualisieren --- ## Tech-Stack - **Sprache:** TypeScript (ESM, `"type": "module"`) - **Runtime für CLI:** `npx tsx` (kein Build-Schritt nötig) - **Pi-Extension-Loader:** `@mariozechner/jiti` — lädt `.ts`-Dateien direkt - **Parameter-Schemas in Pi:** `@sinclair/typebox` (`Type.Object(...)`) - **Ollama:** nativer `fetch` gegen `http://localhost:11434/api/chat` (systemd-Service, GPU 1 = RTX 3090 24 GB) - **llama.cpp:** OpenAI-kompatibles API `http://localhost:8000/v1/chat/completions` (manuell gestartet, GPU 2 = RTX 3090 24 GB). Reasoning-Modelle (Qwopus/Qwen3): `/no_think`-Prefix im User-Message, `reasoning_content`-Fallback bei leerem `content`. - **Perplexity:** `https://api.perplexity.ai/chat/completions` - **OpenRouter:** `https://openrouter.ai/api/v1/chat/completions` - **Node.js:** v22.22.2 (nvm) - **GPU 2** (RTX 3090, 24 GB) ist aktuell idle — `CUDA_VISIBLE_DEVICES` nicht gesetzt --- ## Verzeichnisstruktur ``` text_agent/ ├── agenten/ │ ├── ollama-claim-extractor.ts ← Text → ClaimSet (Ollama, Pi-Tool: extract_claims) │ ├── llama-claim-extractor.ts ← Text → ClaimSet (llama.cpp, Pi-Tool: extract_claims_llama) │ ├── ollama-verifier.ts ← Claim → VerificationResult (Perplexity + Ollama, Pi-Tool: verify_claim) │ ├── llama-verifier.ts ← Claim → VerificationResult (Perplexity + llama.cpp, Pi-Tool: verify_claim_llama) ★ BEVORZUGT │ ├── ollama-verify-article.ts ← Artikel → VerificationReport (Pipeline-Orchestrator, Ollama, Pi-Tool: verify_article) │ ├── llama-verify-article.ts ← Artikel → VerificationReport (Pipeline-Orchestrator, llama.cpp, Pi-Tool: verify_article_llama) │ ├── ollama-logic-editor.ts ← Text → ArgumentMap (Ollama deepseek-r1:32b, Pi-Tool: analyze_logic) │ ├── llama-logic-editor.ts ← Text → ArgumentMap (llama.cpp, Pi-Tool: analyze_logic_llama) ★ BEVORZUGT │ ├── ollama-writer.ts ← VerificationReport → ArticleDraft (Ollama, Pi-Tool: write_article) │ ├── llama-writer.ts ← VerificationReport → ArticleDraft (llama.cpp, Pi-Tool: write_article_llama) ★ BEVORZUGT │ └── research-web.ts ← Web-Recherche via Perplexity (standalone) ├── lib/ │ ├── perplexity.ts ← Perplexity-API-Wrapper (Retry, Kosten, Deduplizierung) │ ├── router.ts ← Model-Router (lokal vs. OpenRouter) │ ├── logger.ts ← File-Logger (→ ~/.pi/agent/logs/) │ ├── jobs.ts ← Job-Speicher (→ ~/.pi/agent/jobs/) │ └── cache.ts ← SHA256-Claim-Cache (→ ~/.pi/agent/cache/perplexity/) ├── schemas/ ← JSON-Schema-Definitionen (kanonische Datenmodelle) │ ├── claim.schema.json │ ├── source-record.schema.json │ ├── verification-result.schema.json │ ├── argument-map.schema.json │ └── article-draft.schema.json ├── types/ │ └── pi-coding-agent.d.ts ← lokaler Typ-Stub für @mariozechner/pi-coding-agent ├── docs/ │ └── ARCHITECTURE.md ├── tests/ │ ├── corpus/ ← 10 Testfälle (input.txt, expected.json, notes.md) │ └── run_corpus.sh ← Precision/Recall-Test-Runner ├── AGENTS.md / HANDOFF.md / TODO.md / WORKLOG.md ├── package.json └── tsconfig.json ``` --- ## Deployment-Pfade ``` ~/.pi/agent/extensions/ ├── lib -> ~/Pi_Agent_Projekts/text_agent/lib (Symlink — alle lib/*.ts verfügbar) ├── research-web.ts (Standalone-Datei) └── fact-checker/ ├── package.json (pi.extensions-Manifest) ├── ollama-claim-extractor.ts -> agenten/ollama-claim-extractor.ts ├── llama-claim-extractor.ts -> agenten/llama-claim-extractor.ts ├── ollama-verifier.ts -> agenten/ollama-verifier.ts ├── llama-verifier.ts -> agenten/llama-verifier.ts ├── ollama-verify-article.ts -> agenten/ollama-verify-article.ts ├── llama-verify-article.ts -> agenten/llama-verify-article.ts ├── ollama-logic-editor.ts -> agenten/ollama-logic-editor.ts ├── llama-logic-editor.ts -> agenten/llama-logic-editor.ts ├── ollama-writer.ts -> agenten/ollama-writer.ts └── llama-writer.ts -> agenten/llama-writer.ts ~/.pi/agent/jobs/ ← Job-Verzeichnisse (von lib/jobs.ts angelegt) ~/.pi/agent/logs/ ← Log-Dateien (von lib/logger.ts angelegt) ~/.pi/agent/cache/ ← Perplexity-Claim-Cache (von lib/cache.ts angelegt) ``` Änderungen im Repo sind nach `/reload` in Pi sofort aktiv (Symlinks). --- ## Kommandos ```bash cd ~/Pi_Agent_Projekts/text_agent # TypeScript prüfen npx tsc --noEmit # Claim-Extraktion — Ollama-Version npx tsx agenten/ollama-claim-extractor.ts "Textinhalt..." npx tsx agenten/ollama-claim-extractor.ts --only-checkable "$(cat artikel.txt)" npx tsx agenten/ollama-claim-extractor.ts --verbose "$(cat langer-text.txt)" # Chunking-Details npx tsx agenten/ollama-claim-extractor.ts --json "..." > claims.json # Claim-Extraktion — llama.cpp-Version (Port 8000) npx tsx agenten/llama-claim-extractor.ts "Textinhalt..." npx tsx agenten/llama-claim-extractor.ts --file artikel.txt --only-checkable npx tsx agenten/llama-claim-extractor.ts --file artikel.txt --translate-to de # + Übersetzung npx tsx agenten/llama-claim-extractor.ts --json --file artikel.txt > claims.json # Einzelnen Claim prüfen — Ollama-Version npx tsx agenten/ollama-verifier.ts "Die Inflationsrate betrug 2024 in Deutschland 3,2%." npx tsx agenten/ollama-verifier.ts --mode deep --verbose "Strittige Behauptung..." npx tsx agenten/ollama-verifier.ts --json "..." > result.json # Einzelnen Claim prüfen — llama.cpp-Version ★ BEVORZUGT npx tsx agenten/llama-verifier.ts "Die EZB hat den Leitzins im Juni 2024 gesenkt." npx tsx agenten/llama-verifier.ts --mode deep --user-language en "Claim..." npx tsx agenten/llama-verifier.ts --json "..." | python3 -m json.tool # Vollständige Verifikations-Pipeline npx tsx agenten/ollama-verify-article.ts "$(cat artikel.txt)" npx tsx agenten/ollama-verify-article.ts --job-id mein-artikel "$(cat artikel.txt)" # mit Job-Speicher npx tsx agenten/ollama-verify-article.ts --no-cache --job-id test "$(cat artikel.txt)" # Cache umgehen npx tsx agenten/ollama-verify-article.ts --json "..." > report.json npx tsx agenten/ollama-verify-article.ts --verbose --job-id test "$(cat artikel.txt)" # Artikel schreiben — llama.cpp-Version ★ BEVORZUGT npx tsx agenten/llama-writer.ts --from-job mein-artikel --style blog npx tsx agenten/llama-writer.ts --from-job mein-artikel --style journalistic --words 600 cat report.json | npx tsx agenten/llama-writer.ts --from-report --style blog # Artikel schreiben — Ollama-Version cat report.json | npx tsx agenten/ollama-writer.ts --from-report --style blog npx tsx agenten/ollama-writer.ts --from-job mein-artikel --style blog # Argumentationsanalyse — llama.cpp-Version ★ BEVORZUGT npx tsx agenten/llama-logic-editor.ts "Argumentativer Text..." npx tsx agenten/llama-logic-editor.ts --only-fallacies "Text..." npx tsx agenten/llama-logic-editor.ts --json "..." > map.json # Argumentationsanalyse — Ollama-Version (deepseek-r1:32b) npx tsx agenten/ollama-logic-editor.ts "Argumentativer Text..." npx tsx agenten/ollama-logic-editor.ts --only-fallacies "Text..." npx tsx agenten/ollama-logic-editor.ts --cloud "Text..." # OpenRouter # Job-Speicher prüfen ls ~/.pi/agent/jobs/ cat ~/.pi/agent/jobs/_/meta.json # Ollama-Status curl -s http://localhost:11434/api/ps | python3 -m json.tool # Vollständige llama.cpp-Pipeline ★ BEVORZUGT npx tsx agenten/llama-verify-article.ts --json "$(cat artikel.txt)" \ | npx tsx agenten/llama-writer.ts --from-report --style blog # Vollständige Ollama-Pipeline npx tsx agenten/ollama-verify-article.ts --json "$(cat artikel.txt)" \ | npx tsx agenten/ollama-writer.ts --from-report --style blog # Testkorpus ausführen bash tests/run_corpus.sh # alle 10 Fälle (Precision/Recall) bash tests/run_corpus.sh --mode deep # mit sonar-pro bash tests/run_corpus.sh case_001 case_002 # selektive Fälle # Cache-Verwaltung node -e "import('../lib/cache.js').then(m => console.log(m.cacheStats()))" node -e "import('../lib/cache.js').then(m => console.log(m.pruneCache()))" # Pi Extensions neu laden /reload # innerhalb von Pi ``` --- ## Coding-Konventionen - **ESM only:** alle Imports mit `.js`-Extension (auch wenn die Datei `.ts` ist) - **Relative Imports:** `../lib/perplexity.js`, `./ollama-claim-extractor.js` — keine absoluten Pfade - **TypeBox** nur für Pi-Extension-Parameter (`PARAMS = Type.Object(...)`) - **Ollama structured output:** `format: `, `stream: false`, `additionalProperties: false` - **num_ctx bei qwen3.5:27b:** max. 8192 (VRAM-Limit auf RTX 3090) - **llama.cpp:** `POST /v1/chat/completions`, `stream: false`, `max_tokens: 16384`. Schema als JSON-Literal im System-Prompt (kein `format:`-Parameter). `/no_think` als erste Zeile im User-Message bei Reasoning-Modellen. Fallback: `choices[0].message.reasoning_content` per Regex wenn `content` leer. - **Temperatur:** 0.1 für Extraktion/Verifikation, 0.3–0.4 für Schreiben - **Fehler:** `err instanceof Error ? err.message : String(err)` — nie `.toString()` - **CLI-Einstiegspunkt:** `if (process.argv[1] === fileURLToPath(import.meta.url))` - **Pi-Rückgabe:** `{ content: [{ type: "text", text }], details: {...} }` - **Logging:** `lib/logger.ts` verwenden — kein `console.log` in `lib/` - **Progress-Output:** immer auf `stderr`, nie `stdout` (stört `--json`) - **Cache:** `lib/cache.ts` für wiederholte Perplexity-Anfragen; fehlertolerant (Fehler nie propagieren) - **Minimale Änderungen:** kein Refactoring ohne expliziten Auftrag; keinen Coding-Stil brechen - **Keine neuen Dependencies** ohne Rückfrage beim Nutzer --- ## Was Pi NICHT tun soll - Keine Umbenennungen exportierter Funktionen ohne vollständige Import-Prüfung - Keine Änderungen an Deployment-Symlinks in `~/.pi/agent/extensions/` - Nicht `research-web.ts` umbenennen/löschen - Kein `console.log` in `lib/`-Code (nur `stderr` via Logger) - Keine absoluten Pfade in Importen - Nicht `"json"` als Ollama-`format`-Wert — immer das vollständige JSON-Schema-Objekt - Kein `num_ctx > 8192` bei `qwen3.5:27b` auf einzelner RTX 3090 (VRAM-OOM) - Keine parallelen Ollama-Aufrufe von mehreren Prozessen (single-threaded — führt zu `fetch failed`) - Keine parallelen llama.cpp-Aufrufe (ebenfalls single-threaded) - Bei llama.cpp kein `format:`-Parameter — Schema gehört in den System-Prompt als JSON-Literal --- ## Architekturregeln - Jeder Agent produziert **genau ein** typisiertes Ausgabeobjekt - **Kein Agent ruft direkt einen anderen auf** — Orchestrierung nur in `ollama-verify-article.ts` und `llama-verify-article.ts` - `lib/` enthält nur Code, der von ≥2 Agenten genutzt wird - JSON-Schemas in `schemas/` sind kanonisch — TypeScript-Typen lokal je Datei - `additionalProperties: false` in jedem Ollama-Schema - Jobs, Logging und Cache sind optional — Pi-Extensions nutzen `nullLogger`, kein `jobDir`, Cache ist standardmäßig aktiv (schadet nicht) ## Wichtige Architekturentscheidungen (nicht rückgängig machen) | Entscheidung | Begründung | |---|---| | `num_ctx=8192` fix für ollama-claim-extractor | VRAM-Limit auf RTX 3090 (24 GB) | | Chunking statt großem Kontext | Texte > 4000 Zeichen → Chunks ≤ 3000 Zeichen | | Perplexity-Ergebnisse einzeln per Claim gecacht | Günstigstes Failover-Granulat | | Batch-Ollama-Verdict (1 Call für N Claims) | Effizienter als N sequentielle Calls | | `complexity: "low"` ohne `--cloud` in ollama-writer.ts | Verhindert ungewolltes OpenRouter-Routing | --- ## Loop-Erkennung und Edit-Disziplin (ZWINGEND) ### Partial-Read-Pflicht - Wenn ein `read`-Ergebnis mit `[N more lines…]` endet: **immer zuerst** mit `offset=` den fehlenden Teil nachlesen, bevor ein Edit versucht wird. - Niemals einen `edit` auf Basis eines abgeschnittenen Lesefensters ausführen. ### Edit-Fehlschlag-Protokoll 1. **Erster Fehlschlag**: Datei vollständig neu lesen (`read` ohne Limit, oder mit ausreichend großem `limit`), dann exakte Zeilen für `old_string` entnehmen — danach ein einzelner neuer Edit-Versuch. 2. **Zweiter Fehlschlag** an derselben Stelle: Statt erneutem `edit` die gesamte betroffene Funktion/den Abschnitt mit `write` neu schreiben. 3. **Dritter Fehlschlag oder tsc-Fehler nach Rewrite**: **SOFORT STOPPEN.** Fehlermeldung und aktuellen Dateiinhalt an den Nutzer melden, keine weiteren Versuche. ### Loop-Abbruchbedingung - Wenn dieselbe Sequenz (read → edit schlägt fehl → read → edit schlägt fehl) **zweimal** hintereinander auftritt: Abbruch, Meldung an Nutzer mit genauem Fehlertext und den betroffenen Zeilen. - Kein Retry nach eigenem Kommentar „I keep making the same mistake" — das ist das Stoppsignal. --- ## Wann Pi stoppen und fragen soll - `npx tsc --noEmit` zeigt Fehler, die sich nicht minimal beheben lassen - Ein Ollama-Aufruf hängt nach >5 Minuten ohne Output - Ein neues Ollama-Schema verschlechtert die Ausgabequalität messbar - `PERPLEXITY_API_KEY` oder `OPENROUTER_API_KEY` nicht gesetzt und der Task braucht sie - Änderungen an `lib/perplexity.ts`, `lib/router.ts`, `lib/jobs.ts`, `lib/logger.ts` oder `lib/cache.ts` - Edit schlägt 2× an derselben Datei/Stelle fehl (→ Loop-Erkennung oben) --- ## WORKLOG-Format ``` ## [YYYY-MM-DD] ### Erledigt - [Was geändert] in `datei.ts` - tsc: fehlerfrei - Getestet: [Kommando und Ergebnis] ### Probleme und Lösungen | Problem | Lösung | |---------|--------| | ... | ... | ### Verbleibende offene Punkte - ... ``` --- ## Definition of Done Eine Änderung ist fertig wenn: 1. `npx tsc --noEmit` fehlerfrei 2. Betroffener Agent via CLI getestet 3. `WORKLOG.md` ergänzt 4. `[ ]` in `TODO.md` als `[x]` markiert