spec: article pipeline workflow for Cody

This commit is contained in:
Hermes Agent
2026-06-23 14:26:02 +02:00
parent e63004daca
commit 85aa2781f1
+383
View File
@@ -0,0 +1,383 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Anforderungsdefinition: Vollautomatischer Artikel-Workflow</title>
<meta name="description" content="Spezifikation für eine vollautomatische Pipeline von Input (Thema/PDF/URL) → QC-geprüfter HTML-Artikel. Stages: Input Prep → Research → Write → QC → Deliver.">
<style>
:root {
--accent: #20228a;
--accent-light: #3b3da8;
--bg: #f8f9fb;
--surface: #ffffff;
--text: #1a1a2e;
--text-muted: #6b7280;
--border: #e5e7eb;
--radius: 10px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; padding: 2rem 1.5rem; max-width: 900px; margin: 0 auto; }
header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 3px solid var(--accent); }
h1 { font-size: 1.8rem; color: var(--accent); margin-bottom: 0.4rem; letter-spacing: -0.02em; }
header p { color: var(--text-muted); font-size: 0.95rem; }
h2 { font-size: 1.3rem; color: var(--accent); margin: 2rem 0 0.8rem; padding-bottom: 0.4rem; border-bottom: 1px solid var(--border); }
h3 { font-size: 1.1rem; color: var(--accent-light); margin: 1.5rem 0 0.5rem; }
h4 { font-size: 1rem; color: #444; margin: 1rem 0 0.3rem; }
p, li { margin-bottom: 0.5rem; }
ul, ol { padding-left: 1.5rem; margin-bottom: 1rem; }
li { margin-bottom: 0.25rem; }
code { background: #f0f0f5; padding: 0.15em 0.4em; border-radius: 4px; font-size: 0.9em; font-family: 'SF Mono', 'Fira Code', monospace; }
pre { background: #1a1a2e; color: #e0e0e0; padding: 1rem 1.2rem; border-radius: var(--radius); overflow-x: auto; font-size: 0.85rem; line-height: 1.5; margin: 1rem 0; }
pre code { background: none; padding: 0; color: inherit; }
table { width: 100%; border-collapse: collapse; margin: 1rem 0; background: var(--surface); border-radius: var(--radius); overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
th { background: linear-gradient(135deg, var(--accent), var(--accent-light)); color: #fff; font-weight: 600; padding: 0.6rem 0.8rem; text-align: left; font-size: 0.9rem; }
td { padding: 0.5rem 0.8rem; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
tr:last-child td { border-bottom: none; }
tbody tr:nth-child(even) { background: rgba(32,34,138,0.03); }
.pipeline { display: flex; align-items: center; gap: 0.3rem; flex-wrap: wrap; font-family: monospace; font-size: 0.85rem; margin: 1rem 0; padding: 0.8rem; background: var(--surface); border-radius: var(--radius); overflow-x: auto; }
.stage { background: linear-gradient(135deg, var(--accent), var(--accent-light)); color: #fff; padding: 0.3rem 0.6rem; border-radius: 6px; white-space: nowrap; font-weight: 600; }
.arrow { color: var(--accent); font-weight: bold; }
.badge { display: inline-block; padding: 0.15em 0.5em; border-radius: 4px; font-size: 0.8rem; font-weight: 600; margin-right: 0.3rem; }
.badge-green { background: #d1fae5; color: #065f46; }
.badge-red { background: #fee2e2; color: #991b1b; }
.badge-blue { background: #dbeafe; color: #1e40af; }
.badge-yellow { background: #fef3c7; color: #92400e; }
.checklist { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; margin: 1rem 0; }
.checklist-item { display: flex; align-items: flex-start; gap: 0.4rem; padding: 0.3rem 0; font-size: 0.9rem; }
.checklist-item .icon { flex-shrink: 0; width: 1.3em; }
hr { border: none; border-top: 1px solid var(--border); margin: 2rem 0; }
footer { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--border); color: var(--text-muted); font-size: 0.85rem; }
</style>
</head>
<body>
<article>
<header>
<h1>Anforderungsdefinition: Vollautomatischer Artikel-Workflow</h1>
<p>Spezifikation für Cody · 23. Juni 2026 · Stand: final</p>
</header>
<h2>1. Ziel</h2>
<p>Eine Pipeline, die aus einem beliebigen Input (Thema, PDF, URL, Stichwort) einen <strong>QC-geprüften, publikationsfertigen HTML-Artikel</strong> produziert. Basti gibt den Auftrag — der Rest läuft autonom.</p>
<h2>2. Eingabe-Schnittstelle</h2>
<pre><code>Input: {
topic: string, // "Gamegenic wird Partner von Tolarian Community College"
sources: string[], // ["/pfad/pm.pdf", "https://icv2.com/...", "https://gamegenic.com"]
category_id: number, // Joomla-Rubrik (default: 61 = Korrektur)
rubric: string, // "Neuerscheinungen" | "Crowdfunding" | "Nachrichten" | ...
image_urls: string[], // optionale Bild-URLs aus PM
deadline: string | null // optional: ISO-Timestamp für zeitkritische Artikel
}</code></pre>
<h3>Input-Quellen-Erkennung (automatisch)</h3>
<table>
<tr><th>Input</th><th>Quelle</th></tr>
<tr><td>PDF</td><td>Pfad aus <code>~/.hermes/cache/documents/</code></td></tr>
<tr><td>URL</td><td>Direkt übernehmen</td></tr>
<tr><td>Nur Thema</td><td>Sub-Agent recherchiert selbstständig Quellen</td></tr>
</table>
<h2>3. Pipeline-Stufen</h2>
<div class="pipeline">
<span class="stage">STAGE 0<br>Input Prep</span>
<span class="arrow"></span>
<span class="stage">STAGE 1<br>Research</span>
<span class="arrow"></span>
<span class="stage">STAGE 2<br>Write</span>
<span class="arrow"></span>
<span class="stage">STAGE 3<br>QC</span>
<span class="arrow"></span>
<span class="stage">STAGE 4<br>Deliver</span>
</div>
<p style="font-size:0.85rem;color:var(--text-muted);margin-top:0.3rem;">Dauer: ~1015 Minuten von Input bis fertigem Artikel</p>
<h3>STAGE 0: Input Preparation</h3>
<p><span class="badge badge-blue">Basti</span> (nicht Sub-Agent)</p>
<ol>
<li>PDFs OCRen: <code>python3 -c "import pymupdf; doc=pymupdf.open('…'); [print(page.get_text()) …]"</code></li>
<li>Prompt bauen aus Input + OCR-Text + Quellen-URLs</li>
<li>Skills-Array: <code>["journalistic-article-writing", "korrekturschleife", "article-management"]</code></li>
<li>Toolsets: <code>["web", "terminal", "file", "search", "skills"]</code></li>
</ol>
<p><strong>Output:</strong> Fertiger Prompt für Stage 1</p>
<h3>STAGE 1: Research</h3>
<p><span class="badge badge-green">Sub-Agent #1</span> (Leaf, <code>delegate_task</code>)</p>
<table>
<tr><th>Feld</th><th>Wert</th></tr>
<tr><td>Skills</td><td>journalistic-article-writing</td></tr>
<tr><td>Toolsets</td><td>web, terminal, file, search, skills</td></tr>
</table>
<ol>
<li>Alle Quellen abrufen (<code>web_extract</code>, <code>curl</code>, <code>web_search</code>)</li>
<li>Jede Quelle bewerten: <strong>AAA</strong> (Primär) / <strong>AA</strong> (Sekundär) / <strong>A</strong> (schwach)</li>
<li>Fehlende Fakten ergänzen:
<ul>
<li>BGG-Eintrag suchen: <code>web_search site:boardgamegeek.com SPIELNAME</code></li>
<li>Autor/Illustrator/Verlag verifizieren</li>
<li>Preise, Daten, Awards gegenprüfen</li>
</ul>
</li>
</ol>
<p><strong>Output:</strong> <code>research_brief.md</code></p>
<pre><code># Research Brief: THEMA
## Quellenbewertung
| Quelle | Stufe | URL |
|---------|---------|-----------------------|
| PM | AAA | https://gamegenic.com |
## Fakten
- Fakt 1 (Quelle: URL, AAA)
- Fakt 2 (Quelle: URL, AA)
## Offene Punkte
- Punkt X konnte nicht verifiziert werden → STREICHEN</code></pre>
<p><strong>Exit-Codes:</strong> <span class="badge badge-green">0</span> = vollständig · <span class="badge badge-red">1</span> = unvollständig (Abbruch, an Basti melden)</p>
<h3>STAGE 2: Write</h3>
<p><span class="badge badge-green">Sub-Agent #2</span> (Leaf, <code>delegate_task</code>)</p>
<table>
<tr><th>Feld</th><th>Wert</th></tr>
<tr><td>Skills</td><td>journalistic-article-writing, korrekturschleife, article-management</td></tr>
<tr><td>Toolsets</td><td>web, terminal, file, search, skills</td></tr>
<tr><td>Context</td><td>Research Brief + Original-Prompt</td></tr>
</table>
<div class="checklist">
<div class="checklist-item"><span class="icon"></span> KEINE "XML API v2" → klickbare BGG-Links</div>
<div class="checklist-item"><span class="icon"></span> KEIN "Betriebsgeheimnis"</div>
<div class="checklist-item"><span class="icon"></span> Quellen = <code>&lt;a href="…" target="_blank"&gt;</code></div>
<div class="checklist-item"><span class="icon"></span> <code>&lt;span&gt;&lt;strong&gt;Quellen&lt;/strong&gt;&lt;/span&gt;</code></div>
<div class="checklist-item"><span class="icon"></span> KEINE Emojis/Icons</div>
<div class="checklist-item"><span class="icon"></span> Datei endet mit <code>&lt;/html&gt;</code></div>
</div>
<p><strong>Output:</strong> <code>/home/hermes/workspace/artikel_NAME_DATUM.html</code></p>
<p><strong>Pflicht-Elemente im HTML:</strong></p>
<pre><code>&lt;head&gt;
&lt;meta charset="UTF-8"&gt;
&lt;title&gt;TITEL&lt;/title&gt;
&lt;meta name="description" content="…"&gt;
&lt;meta name="keywords" content="…"&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;article&gt;
&lt;h1&gt;TITEL&lt;/h1&gt;
&lt;p class="meta"&gt;DATUM · Lesezeit: ca. N Minuten&lt;/p&gt;
&lt;!-- Inhalt --&gt;
&lt;hr id="system-readmore" /&gt;
&lt;span style="…"&gt;&lt;strong&gt;Quellen&lt;/strong&gt;&lt;/span&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="URL" target="_blank"&gt;Name&lt;/a&gt; — Beschreibung&lt;/li&gt;
&lt;/ol&gt;
&lt;p class="qc"&gt;&lt;!-- QC: Quelle1=AAA|URL, … --&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p><strong>Exit-Codes:</strong> <span class="badge badge-green">0</span> = Artikel geschrieben · <span class="badge badge-red">1</span> = Fehler</p>
<h3>STAGE 3: Quality Control</h3>
<p><span class="badge badge-green">Sub-Agent #2</span> (gleicher Agent, nach dem Schreiben)</p>
<pre><code>bash /home/hermes/workspace/verify_article.sh artikel_NAME.html</code></pre>
<h4>13 Checks (Stand 23.06.2026)</h4>
<table>
<thead>
<tr><th>#</th><th>Check</th><th>Kriterium</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>Read-More</td><td>Genau 1 × <code>&lt;hr id="system-readmore"&gt;</code></td></tr>
<tr><td>2</td><td>br nach Read-More</td><td>Kein <code>&lt;br&gt;</code> direkt danach</td></tr>
<tr><td>3</td><td>p.meta</td><td><code>&lt;p class="meta"&gt;</code> (nicht <code>&lt;div&gt;</code>)</td></tr>
<tr><td>4</td><td>Emojis</td><td>Keine im Body</td></tr>
<tr><td>5</td><td>Dateiende</td><td>Endet mit <code>&lt;/html&gt;</code></td></tr>
<tr><td>6</td><td>Meta im Body</td><td>Keine doppelte Datum·Lesezeit-Zeile</td></tr>
<tr><td>7</td><td>Quellen-Überschrift</td><td>Kein <code>&lt;h2&gt;Quellen&lt;/h2&gt;</code></td></tr>
<tr><td>8</td><td>Links target</td><td>Alle mit <code>target="_blank"</code></td></tr>
<tr><td>9</td><td>Meta-Description</td><td>Vorhanden und nicht leer</td></tr>
<tr><td>10</td><td>QC-Zeile</td><td>In <code>&lt;p class="qc"&gt;</code></td></tr>
<tr><td><strong>11</strong></td><td><strong>BGG-Autorencheck</strong></td><td><strong>Designer gegen BGG verifizieren</strong></td></tr>
<tr><td style="color:#991b1b;font-weight:600;">12</td><td style="color:#991b1b;font-weight:600;">XML-API-Referenzen</td><td style="color:#991b1b;font-weight:600;">Keine "XML API" / "Betriebsgeheimnis"</td></tr>
<tr><td style="color:#991b1b;font-weight:600;">13</td><td style="color:#991b1b;font-weight:600;">Quellen verlinkt</td><td style="color:#991b1b;font-weight:600;">Quellen-Block hat <code>&lt;a href&gt;</code> Links</td></tr>
</tbody>
</table>
<p><strong>Fehlerbehandlung:</strong></p>
<ul>
<li><span class="badge badge-green">Exit 0</span> → Stage 4</li>
<li><span class="badge badge-red">Exit 1</span> → Korrigieren, erneut verify → max 3 Versuche → ABBRUCH, an Basti melden</li>
<li>CHECK 11 (BGG-Autoren) <span class="badge badge-yellow">Warnung</span> → dokumentieren, nicht blocken</li>
</ul>
<h3>STAGE 4: Deliver</h3>
<p><span class="badge badge-blue">Basti</span></p>
<ol>
<li>Git-Commit: <code>git add artikel_NAME.html && git commit -m "artikel: THEMA"</code></li>
<li>Article-Server prüfen: Direkt-URL testen<br>
<code>curl "http://185.162.249.159:8890/artikel_NAME.html?key=…" | head -3</code></li>
<li>Meldung:</li>
</ol>
<pre><code>✅ Artikel THEMA fertig
📄 /home/hermes/workspace/artikel_NAME.html
🔗 http://185.162.249.159:8890/artikel_NAME.html?key=…
📊 verify: 0 Fehler</code></pre>
<h2>4. Fehlermodi & Recovery</h2>
<table>
<tr><th>Fehler</th><th>Erkennung</th><th>Recovery</th></tr>
<tr>
<td>PDF nicht OCR-bar</td>
<td>pymupdf wirft Exception</td>
<td>Basti manuell OCRen, Text in Prompt geben</td>
</tr>
<tr>
<td>Quelle nicht erreichbar</td>
<td>curl/web_extract Timeout/404</td>
<td>5-Stufen-Eskalation:<br>curl → wget+UA → Wayback → Tavily → Google Cache</td>
</tr>
<tr>
<td>Keine AAA-Quelle für Kern-Fakt</td>
<td>Research-Gap</td>
<td>Fakt streichen → "unvollständig" an Basti</td>
</tr>
<tr>
<td>verify_article.sh fail</td>
<td>Exit ≠ 0</td>
<td>3 Korrekturversuche → Abbruch</td>
</tr>
<tr>
<td>BGG-Autorencheck uneindeutig</td>
<td>check_authors.py Warnung</td>
<td>Dokumentieren, Basti entscheidet</td>
</tr>
<tr>
<td>Article-Server down</td>
<td>curl auf :8890 Timeout</td>
<td>Server neu starten via <code>python3 article_server.py &</code></td>
</tr>
</table>
<h2>5. Cronjob-Integration</h2>
<p>Der Workflow läuft als One-Shot-Cronjob mit <code>deliver="local"</code>:</p>
<pre><code>cronjob(
action="create",
schedule="1m",
repeat=1,
deliver="local",
skills=["journalistic-article-writing", "korrekturschleife", "article-management"],
enabled_toolsets=["web", "terminal", "file", "search", "skills", "delegation"],
prompt="…" // Stage-0-Output
)</code></pre>
<p><strong>Wichtig:</strong> <code>deliver="local"</code> — der Cronjob meldet sich NICHT bei Daniel. Basti pollt das Ergebnis.</p>
<h2>6. Batch-Modus</h2>
<p>Für mehrere Artikel: Parallele Cronjobs (max 3 gleichzeitig via <code>delegation.max_concurrent_children</code>). Jeder Cronjob bekommt denselben Prompt-Aufbau, nur mit anderem Input.</p>
<h2>7. Was Cody bauen muss</h2>
<h3>7.1 <code>article_pipeline.py</code> — Orchestrator-Script</h3>
<ul>
<li>Input entgegennimmt (JSON oder CLI-Args)</li>
<li>Stage 0 ausführt (PDF-OCR, Prompt-Bau)</li>
<li>Zwei <code>delegate_task</code>-Aufrufe (Stage 1 Research, Stage 2 Write+QC)</li>
<li>Stage 4 ausführt (Git-Commit, Verify)</li>
<li>Exit-Code zurückgibt</li>
</ul>
<h3>7.2 Integration</h3>
<ul>
<li>Als Cronjob-Script lauffähig (<code>no_agent=false</code> Modus)</li>
<li>ODER: Als Hermes-Skill <code>article-pipeline</code> registrierbar</li>
</ul>
<h3>7.3 Config</h3>
<table>
<tr><th>Element</th><th>Pfad / Wert</th></tr>
<tr><td>Workspace</td><td><code>/home/hermes/workspace/</code></td></tr>
<tr><td>verify_article.sh</td><td><code>/home/hermes/workspace/verify_article.sh</code></td></tr>
<tr><td>article_server.py</td><td><code>/home/hermes/workspace/article_server.py</code></td></tr>
<tr><td>PDF-Cache</td><td><code>~/.hermes/cache/documents/</code></td></tr>
<tr><td>Skills</td><td>journalistic-article-writing, korrekturschleife, article-management</td></tr>
</table>
<h2>8. Aufruf-Beispiele</h2>
<pre><code># Variante A: Thema + PDF
python3 article_pipeline.py \
--topic "Gamegenic wird Partner von Tolarian Community College" \
--pdf "/home/hermes/.hermes/cache/documents/GG_Press_release.pdf" \
--rubric "Nachrichten" \
--category-id 9
# Variante B: Nur Thema (autonome Recherche)
python3 article_pipeline.py \
--topic "Neue Kennerspiel-Nominierungen 2026" \
--rubric "Nachrichten"
# Variante C: Batch
python3 article_pipeline.py --batch topics.json</code></pre>
<h2>9. Erfolgskriterium</h2>
<div style="background:linear-gradient(135deg,#d1fae5,#a7f3d0);border-radius:10px;padding:1.5rem;margin:1.5rem 0;text-align:center;">
<p style="font-size:1.1rem;margin:0;"><strong>🎯 Basti gibt ein Thema ein → nach ~10 Minuten liegt ein Artikel im Workspace mit</strong></p>
<p style="font-size:1.4rem;font-weight:700;color:#065f46;margin:0.3rem 0;">verify_article.sh: 0 Fehler</p>
<p style="font-size:0.9rem;color:#555;margin:0;">Kein manuelles Eingreifen. Kein Nachbessern. Kein "XML API v2".</p>
</div>
<hr>
<h2>Anhang: Skills-Dokumentation</h2>
<p>Folgende Skills werden im Workflow verwendet. Cody muss ihre Schnittstellen kennen:</p>
<table>
<tr><th>Skill</th><th>Typ</th><th>Funktion</th></tr>
<tr>
<td><code>journalistic-article-writing</code></td>
<td>Writing</td>
<td>HTML-Template, Quellenregeln, Sprachregeln, Formatvorgaben</td>
</tr>
<tr>
<td><code>korrekturschleife</code></td>
<td>QC</td>
<td>Zweistufiger Workflow (Write + Fact-Check), Writer-Fehler-Tabelle, Quellenbewertung AAA/AA/A</td>
</tr>
<tr>
<td><code>article-management</code></td>
<td>Deploy</td>
<td>Article-Server (Port 8890), Joomla-API, verify_article.sh, VG-Wort</td>
</tr>
</table>
</article>
<footer>
<p>Spezifikation für Cody · 23. Juni 2026 · brettspiel-news.de Redaktion</p>
</footer>
</body>
</html>