Wie 8 Agenten orchestriert werden: Agent-Definitionen, Batch-Algorithmus, Intermediate Files, Merge-Script, Zwei-Ebenen-Architektur.
Jeder der 8 Agenten wird durch eine eigene Markdown-DateiDie Dateien in agents/ folgen einem einheitlichen Schema: YAML-Frontmatter (name, description, model: inherit), dann die Rollenbeschreibung, Task-Definition und Output-Format-Spezifikation. im agents/-Ordner definiert. Der Frontmatter legt Name, Beschreibung und Modell fest. Der Body beschreibt die Aufgabe in zwei Phasen: Script-Ausfuehrung + LLM-Analyse.
# agents/project-scanner.md — Header-Analyse
---
name: project-scanner
description: |
Scans a codebase directory to produce a structured
inventory of all project files, detected languages,
frameworks, import maps, and estimated complexity.
model: inherit
---
# Rollenbeschreibung
You are a meticulous project inventory specialist.
Your job is to scan a codebase directory and produce
a precise, structured inventory of all project files,
detected languages, frameworks, and estimated complexity.
Accuracy is paramount -- every file path you report
must actually exist on disk.
name: Der Slug wird intern fuer Dispatch und Logging verwendet. Keine Leerzeichen, keine Umlaute.
description: Multi-Line YAML (mit |). Beschreibt praezise was der Agent tut -- nicht was er KOENNTE tun.
model: inherit: Der Agent nutzt dasselbe Modell wie der Haupt-Kontext. Kein Fallback auf ein guenstigeres Modell.
Rollenbeschreibung: Der erste Absatz definiert die Identitaet. "Meticulous" und "Accuracy is paramount" sind gezielte Prompt-Engineering-Techniken die die Praezision des Outputs erhoehen.
Alle 8 Agenten folgen dem Zwei-Phasen-Muster: Erst ein deterministisches Discovery-ScriptEin Node.js- oder Python-Script das der Agent schreibt und ausfuehrt. Es extrahiert strukturelle Daten (Dateipfade, Funktionen, Imports) die reproduzierbar sind. Die LLM-Phase baut darauf auf., dann LLM-Semantik-Analyse:
# Die 8 Agenten und ihre Aufgaben
| Agent | Phase | Aufgabe |
| project-scanner | 1 | Datei-Inventar, Sprachen, |
| | | Frameworks, Import-Map |
| file-analyzer | 2 | Nodes + Edges pro Datei-Batch |
| | | (5 parallel, 20-30 Dateien/Batch)|
| assemble-reviewer | 3 | Graph-Validierung nach Merge |
| architecture-analyzer | 4 | Layer-Zuordnung (3-10 Schichten) |
| tour-builder | 5 | Lernpfad durch den Graph |
| graph-reviewer | 6 | Finale Graph-Validierung |
| domain-analyzer | - | Domain-spezifische Erweiterung |
| knowledge-graph-guide | - | Dashboard-Konfiguration |
# Jeder Agent hat zwei Phasen:
Phase 1: Script schreiben + ausfuehren (deterministisch)
Phase 2: LLM-Analyse auf Script-Output (semantisch)
file-analyzer ist der einzige Agent der MEHRFACH parallel gestartet wird (bis zu 5 Instanzen). Jede Instanz erhaelt einen anderen Batch von 20-30 Dateien. Die Batches ueberlappen sich NIE -- die Partitionierung ist deterministisch.
Der Batch-AlgorithmusPartitioniert die Dateiliste aus Phase 1 in Gruppen von 20-30 Dateien. Zusammengehoerige Dateien (z.B. Dockerfile + docker-compose.yml) werden im selben Batch gehalten. partitioniert die Dateiliste aus dem project-scanner in analysierbare Einheiten. Ziel: Jeder file-analyzer-Agent erhaelt genug Kontext um sinnvolle Edges zu erkennen, aber nicht so viel dass der Kontext-Buffer ueberlaeuft.
# Batch-Konstruktion: Pseudocode
FUNCTION create_batches(files, import_map):
# 1. Dateien nach fileCategory gruppieren
groups = group_by(files, f.fileCategory)
# categories: code, config, docs, infra,
# data, script, markup
# 2. Zusammengehoerige Dateien identifizieren
co_locate_pairs = [
("Dockerfile", "docker-compose.*"),
("package.json", "tsconfig.json"),
("*.prisma", "*.sql"),
("Makefile", "*.sh"),
]
# 3. Batches fuellen
batches = []
current_batch = []
FOR EACH file IN files (sortiert nach Pfad):
current_batch.append(file)
# Co-located Partner dazupacken
FOR EACH partner IN co_locate_pairs:
IF file matches partner[0]:
add_matching(partner[1], current_batch)
# Batch voll? (20-30 Dateien)
IF len(current_batch) >= 25:
batches.append(current_batch)
current_batch = []
# Rest-Batch anhaengen
IF current_batch:
batches.append(current_batch)
RETURN batches
fileCategory-Grouping: Dateien werden nach Typ klassifiziert: code, config, docs, infra, data, script, markup. Zusammengehoerige Dateien wie Dockerfile + docker-compose.yml landen im selben Batch, damit der Agent deren Beziehung erkennen kann.
Batch-Groesse 20-30: Ein Kompromiss. Weniger Dateien pro Batch = bessere Analyse-Qualitaet pro Datei, aber mehr Agent-Aufrufe. Mehr Dateien = weniger Aufrufe, aber der Kontext-Buffer kann ueberlaufen und die Analyse-Qualitaet sinkt.
25 als Default: Erfahrungswert. Bei einem typischen Projekt mit 200 Dateien ergeben sich 8 Batches, die in 2 Runden mit 5 parallelen Agents abgearbeitet werden.
Jeder Batch erhaelt seine eigene batchImportDataEin JSON-Objekt das fuer jede Datei im Batch die bereits aufgeloesten Import-Pfade enthaelt. Der file-analyzer muss Imports NICHT selbst aufloesen -- das hat der project-scanner bereits gemacht. -- die pre-resolved Import-Daten aus Phase 1:
# batchImportData: Pre-resolved Imports pro Datei
{
"batchImportData": {
"src/index.ts": [
"src/utils.ts",
"src/config.ts",
"src/routes/api.ts"
],
"src/utils.ts": [
"src/types.ts"
],
"README.md": [],
"Dockerfile": []
}
}
# WICHTIG: Der file-analyzer darf Imports
# NICHT selbst aufloesen. Er nutzt NUR diese
# pre-resolved Daten fuer Import-Edges.
# Grund: Der project-scanner hat eine globale
# Sicht auf alle Dateien. Der file-analyzer sieht
# nur seinen Batch von 20-30 Dateien.
Alle Agenten kommunizieren ueber Intermediate FilesJSON-Dateien in .claude-learning/intermediate/. Jeder Agent schreibt sein Ergebnis als JSON-Datei. Der naechste Agent in der Pipeline liest diese Datei als Input. Es gibt keine direkte Agent-zu-Agent-Kommunikation. im Verzeichnis .claude-learning/intermediate/. Dieses Verzeichnis wird in Phase 0 erstellt und enthaelt nach Abschluss alle Zwischenergebnisse.
# Intermediate-Verzeichnis nach vollstaendiger Pipeline
.claude-learning/intermediate/
scan-result.json # Phase 1: project-scanner
batch-1.json # Phase 2: file-analyzer #1
batch-2.json # Phase 2: file-analyzer #2
batch-3.json # Phase 2: file-analyzer #3
...
batch-N.json # Phase 2: file-analyzer #N
assembled-graph.json # Phase 2→3: Merge-Script
assemble-review.json # Phase 3: assemble-reviewer
layers.json # Phase 4: architecture-analyzer
tour.json # Phase 5: tour-builder
graph-review.json # Phase 6: graph-reviewer
scan-result.json: Enthaelt die komplette Dateiliste mit Pfaden, Sprachen, fileCategory, Zeilenanzahl und die Import-Map. Input fuer den Batch-Algorithmus.
batch-*.json: Jeder file-analyzer schreibt genau eine Datei. Sie enthaelt Nodes (file, function, class, etc.) und Edges (imports, calls, contains, etc.) fuer die Dateien in diesem Batch.
assembled-graph.json: Das Ergebnis des merge-batch-graphs.py Scripts. Alle Batches zu einem Graph kombiniert, Nodes normalisiert, Edges dedupliziert.
layers.json: Die Architektur-Schichten mit Zuordnung jeder Datei zu genau einer Schicht.
tour.json: Der geordnete Lernpfad durch die wichtigsten Knoten des Graphs.
Die JSON-Strukturen folgen einem einheitlichen Schema. Hier die wichtigsten:
# batch-*.json Schema (Output eines file-analyzer)
{
"nodes": [
{
"id": "file:src/index.ts",
"type": "file",
"name": "index.ts",
"filePath": "src/index.ts",
"summary": "Application entry point...",
"tags": ["entry-point", "server"],
"complexity": "moderate",
"lineCount": 150
},
{
"id": "function:src/index.ts:main",
"type": "function",
"name": "main",
"filePath": "src/index.ts",
"startLine": 10,
"endLine": 45
}
],
"edges": [
{
"source": "file:src/index.ts",
"target": "file:src/utils.ts",
"type": "imports"
},
{
"source": "file:src/index.ts",
"target": "function:src/index.ts:main",
"type": "contains"
}
]
}
[type]:[filePath]:[name]. Bei Dateien entfaellt der Name-Teil: file:src/index.ts. Bei Funktionen ist der Name noetig: function:src/index.ts:main. Wenn ein Agent den Typ-Prefix vergisst oder doppelt setzt (z.B. file:file:src/index.ts), korrigiert das merge-batch-graphs.py Script dies automatisch.
batch-existing.json geschrieben und erneut durch den Merge gefahren.
Das merge-batch-graphs.pyEin Python-Script das mit dem Skill ausgeliefert wird. Es liest alle batch-*.json aus dem intermediate/-Ordner und erzeugt assembled-graph.json. Der kritischste Schritt: Node-ID-Normalisierung. Script ist der zentrale Normalisierungs-Schritt zwischen Phase 2 und Phase 3. Es liest alle Batch-Dateien und erzeugt einen einzigen, konsistenten Graph.
# merge-batch-graphs.py — Algorithmus-Walkthrough
python <SKILL_DIR>/merge-batch-graphs.py $PROJECT_ROOT
# Das Script fuehrt in EINEM Pass 6 Schritte aus:
Schritt 1: Alle batch-*.json laden
FOR EACH file IN glob("intermediate/batch-*.json"):
data = json.load(file)
all_nodes.extend(data["nodes"])
all_edges.extend(data["edges"])
Schritt 2: Node-ID-Normalisierung
FOR EACH node IN all_nodes:
# Doppelte Prefixes strippen
"file:file:src/x.ts" -> "file:src/x.ts"
# Projekt-Name-Prefixes strippen
"file:myapp/src/x.ts" -> "file:src/x.ts"
# Fehlende Prefixes hinzufuegen
"src/x.ts" -> "file:src/x.ts"
# Mapping speichern: old_id -> new_id
Schritt 3: Complexity-Normalisierung
normalize_map = {
"low": "simple",
"medium": "moderate",
"high": "complex",
"very high": "complex",
}
FOR EACH node: node.complexity =
normalize_map.get(node.complexity, node.complexity)
Schritt 4: Edge-Rewrites
FOR EACH edge IN all_edges:
edge.source = id_mapping[edge.source]
edge.target = id_mapping[edge.target]
Schritt 5: Deduplizierung
# Nodes: by ID (letztes Vorkommen gewinnt)
nodes_by_id = {}
FOR EACH node: nodes_by_id[node.id] = node
# Edges: by (source, target, type)
edge_keys = set()
unique_edges = []
FOR EACH edge:
key = (edge.source, edge.target, edge.type)
IF key NOT IN edge_keys:
unique_edges.append(edge)
edge_keys.add(key)
Schritt 6: Dangling Edges droppen
valid_ids = set(nodes_by_id.keys())
FOR EACH edge IN unique_edges:
IF edge.source NOT IN valid_ids
OR edge.target NOT IN valid_ids:
log_warning + DROP
Schritt 1: Einfaches Laden aller Batch-Dateien. Die Reihenfolge ist egal -- die Deduplizierung in Schritt 5 handhabt Konflikte.
Schritt 2 (kritischster Schritt): LLM-generierte Node-IDs sind inkonsistent. Manche Agents setzen den Typ-Prefix doppelt ("file:file:"), andere vergessen ihn ganz ("src/x.ts"), wieder andere fuegen den Projektnamen ein ("file:myapp/src/x.ts"). Alle drei Fehlerarten werden korrigiert.
Schritt 3: Verschiedene file-analyzer-Instanzen verwenden unterschiedliche Woerter fuer Komplexitaet: "low" vs "simple", "medium" vs "moderate". Die Normalisierung stellt sicher, dass nur 3 Werte existieren: simple, moderate, complex.
Schritt 4: Nachdem Node-IDs korrigiert wurden, muessen alle Edges aktualisiert werden. Eine Edge die auf die alte ID "file:file:src/x.ts" zeigt, muss jetzt auf "file:src/x.ts" zeigen.
Schritt 5: Nodes mit identischer ID werden dedupliziert (letztes Vorkommen gewinnt). Edges mit identischem (source, target, type)-Tupel werden dedupliziert.
Schritt 6: Edges die auf nicht-existierende Nodes zeigen (weil z.B. eine Datei geloescht wurde oder ein Node-ID-Fehler nicht korrigierbar war) werden geloggt und entfernt.
Alle Korrekturen und Drops werden auf stderr geloggt. Dieser Output wird in der assemble-review Phase dem Reviewer uebergeben:
# Typische stderr-Ausgabe des Merge-Scripts
[NORMALIZE] file:file:src/auth.ts
-> file:src/auth.ts (double prefix)
[NORMALIZE] src/utils.ts
-> file:src/utils.ts (missing prefix)
[NORMALIZE] file:myapp/src/db.ts
-> file:src/db.ts (project prefix)
[COMPLEXITY] file:src/auth.ts
low -> simple
[DEDUP-NODE] file:src/index.ts
kept batch-3, dropped batch-1
[DEDUP-EDGE] file:src/index.ts -> file:src/utils.ts
type: imports (duplicate)
[DANGLING] file:src/old-file.ts -> file:src/auth.ts
source not found — DROPPED
Summary: 142 nodes, 287 edges
6 normalizations, 3 dedup-nodes,
12 dedup-edges, 1 dangling dropped
file:my-project/src/x.ts), wird der Projektname entfernt. Die Erkennung basiert darauf, ob das erste Pfad-Segment dem Projektnamen aus scan-result.json entspricht.
Die Zwei-Ebenen-ArchitekturEbene 1: Pipeline-Agents (1 pro Zielgruppe, steuert den gesamten Tiefenpfad). Ebene 2: Datei-Agents (1 pro HTML-Datei, werden vom Pipeline-Agent gestartet). Ebenen sind hierarchisch: Pipeline-Agent startet und wartet auf Datei-Agents. trennt Orchestrierung (Ebene 1) von Ausfuehrung (Ebene 2). Ein Pipeline-Agent weiss WAS zu bauen ist, ein Datei-Agent weiss WIE eine Seite gebaut wird.
# Ebene 1: Pipeline-Agent (1 pro Zielgruppe)
# Steuert den kompletten Tiefenpfad
Pipeline-Agent Entwickler:
max_level = L3
hs_schwelle = 6
hs_tiefer = 8
Schritt 1: Baue L0
-> Starte Datei-Agent: index_dev_de.html
-> Starte Datei-Agent: index_dev_en.html
-> WARTE bis beide fertig
Schritt 2: Baue L1 (NUR Themen mit HS >= 6)
-> Starte Datei-Agent: l1/skill-architektur_dev_de.html
-> Starte Datei-Agent: l1/skill-architecture_dev_en.html
-> Starte Datei-Agent: l1/agenten-pipeline_dev_de.html
-> Starte Datei-Agent: l1/agent-pipeline_dev_en.html
-> ... (alle L1-Themen x 2 Sprachen)
-> WARTE bis ALLE fertig
Schritt 3: Baue L2 (NUR Themen mit HS >= 8)
-> # Weniger Themen qualifizieren sich
-> Starte Datei-Agents fuer qualifizierte Themen
-> WARTE bis ALLE fertig
Schritt 4: Baue L3 (NUR Themen mit HS >= 8)
-> Starte Datei-Agents
-> WARTE bis ALLE fertig
Schritt 5: Pipeline-Zusammenfassung zurueckgeben
-> Erzeugte Dateien: [...]
-> Uebersprungene Themen: [...]
-> Stopp-Gruende: [...]
Warum Ebene 1? Ohne Pipeline-Agents muesste der Haupt-Orchestrator jede einzelne Datei dispatchen und die Level-Reihenfolge manuell sicherstellen. Pipeline-Agents kapseln diese Logik.
WARTE-Semantik: Der Pipeline-Agent wartet aktiv (poll loop) bis alle Datei-Agents eines Levels abgeschlossen sind. Erst dann startet das naechste Level. Das verhindert, dass L2-Seiten auf L1-Seiten verlinken die noch nicht existieren.
HS-Filter: Der Pipeline-Agent prueft vor jedem Datei-Agent-Start ob der HS des Themas die Schwelle erreicht. Themen unter der Schwelle werden NICHT als Datei-Agents gestartet.
Pipeline-Zusammenfassung: Am Ende meldet der Pipeline-Agent zurueck was gebaut wurde, was uebersprungen wurde und warum. Diese Daten fliessen in die Tiefenkarte (Phase 6).
# Ebene 2: Datei-Agent (1 pro HTML-Datei)
# Baut eine einzelne HTML-Datei
Datei-Agent Input:
{
"dateiname": "l1/skill-architektur_dev_de.html",
"zielgruppe": "Entwickler",
"sprache": "DE",
"level": "L1",
"thema": "Skill-Architektur",
"integration": "Eingebettet",
"hs": 9,
"breadcrumb": [
{"label":"L0","href":"../index_dev_de.html"},
{"label":"L1 Skill-Architektur","href":null}
],
"deep_dive_links": [
"../l2/phasen-orchestrierung_dev_de.html"
],
"siblings": [
"agenten-pipeline_dev_de.html",
"kg-pipeline_dev_de.html",
"kurs-pipeline_dev_de.html"
],
"sprach_pendant": "skill-architecture_dev_en.html",
"css_foundation": "[INLINE CSS]"
}
Datei-Agent Output:
-> Schreibt die komplette HTML-Datei auf Disk
-> Gibt Dateipfad + Dateigrösse zurueck
-> Meldet Fehler falls Qualitaetsgate fehlschlaegt