Ralph-Loop-Architektur — Mass-Implementation autonom über ready-for-agent Jira-Stories
scripts/ralph.sh <n> ersetzt den deprecated implement-Skill und die worktree-basierte Parallel-Pipeline (ADR-0030, detached-Mode) als Mass-Implementation-Driver. Strikt sequenziell, kein Worktree. Pro Sub-Task läuft eine Bash-orchestrierte Mehrstufen-Pipeline mit drei Phase-Prompt-Files (analog mattpocock .sandcastle/): plan → handoff file → n Slice-Iterationen (implement → check, rework bei Fail) → commit pro Slice → Sub-Task done. Keine Custom-Sub-Agent-Definitionen, keine --agents-JSON — jede Phase ist ein claude -p "$(envsubst < scripts/prompts/<phase>-prompt.md)"-Call mit klarem Output-Kontrakt. Sonnet 4.6 für alle Phasen. Pickup-Selektor: Jira-Label ready-for-agent auf Story-Level. Per-Story PROD-DB-Snapshot-Restore. Pre-PR-Tail: solcom-review plus einmaliger auto-review-fix-Pass; unfixed Findings landen im PR-Body. QA-Plan wird aus dem Story-Hub übernommen (Refinement-Pflicht), nicht generiert.
Kontext
Der SOLCOM-MVP-Termin 08.07.2026 erzwingt einen hohen Implementations-Durchsatz auf dem refinierten Story-Backlog (Projekt P2503). Bisherige autonome Bau-Mechaniken im Repo:
implement-Skill (Memory[[project_implement_pipeline_triple]]): End-to-End-Bau pro Story über Opus-Orchestrator + Sonnet-Sub-Agents (Heavy-Brief-Pattern), in-session, an Persistent-Monitor gekoppelt. Funktional, aber überladen und durch die User-Entscheidung „Sonnet-All ist ausreichend, weil Sub-Tasks nach Refinement gut decomposiert sind" architekturell überdimensioniert.- Worktree-basierte Parallel-Pipeline (ADR-0030): Dual-Mode-Architektur — in-session Sub-Agent via
Agent(isolation: "worktree", run_in_background: true)und detached Background-Claude vianohup claude --print --output-format stream-json --dangerously-skip-permissions. Setzt pro Worktree eine eigene DDEV-Site voraus, mit eigener Datenbank und eigenen Volumes. Friction-Quellen in der Praxis: konkurrierende DDEV-Instanzen auf demselben Mac, Snapshot-Restoration-Konflikte, fehlende Bonus-Stabilität gegenüber sequenziellem Lauf. auto-review-fix-Skill: Operiert seit ADR-0030 ausschließlich im Worktree-Modus. Damit an die Parallel-Pipeline gekoppelt und nicht im Main-Tree aufrufbar.- Office-Hours-Cron Mo-Fr 8:07-17:07 (Memory
[[project_office_hours_cron]]): wöchentlich neu armed, ruftauto-review-fixauf. Hängt an der Mac-Wach-Annahme und am Worktree-Mode.
Parallel dazu existiert in der externen Praxis das Ralph-Loop-Pattern (mattpocock/course-video-manager, chrismdp/ralph): ein minimaler Bash-Loop, der pro Iteration einen claude -p-Call ausführt, eine Aufgabe nach Priority pickt, lokal verifiziert (Typecheck, Tests, CI), committet und einen Exit-Marker in der LLM-Antwort sucht. Mattpococks Skript ist ~25 Zeilen Bash; chrismdps Variante ergänzt Recovery-Mechanik für unterbrochene Tickets und Branch-Discipline.
Die User-Anfrage 2026-05-17 stellt den Bezug her: man möchte einen analogen Mass-Loop für SOLCOM, der über Jira-ready-for-agent Stories iteriert, pro Story einen Feature-Branch anlegt, pro Sub-Task einen TDD-Loop ausführt, und am Ende einen Pull-Request mit konkreten human-testbaren Schritten öffnet. Ausdrücklich nicht-Ziele: Worktrees, Cron, Opus-Heavy-Brief, parallele Loops.
Der gegrillte Design-Tree (siehe Plan 2026-05-17-001-ralph-loop.html) hat folgende Entscheidungen zur Reife gebracht:
| Achse | Entscheidung |
|---|---|
| Topologie | Strikt sequenziell, ein Story-Branch nach dem anderen, kein Worktree |
| Pickup-Selektor | Jira-Label ready-for-agent auf Sub-Task (Refinement-Marker pro Sub-Task), ORDER BY rank ASC. Planner aggregiert eligible Sub-Tasks zu Parent-Stories und picked die höchstrangige Story. Eine Story ist eligible, sobald mindestens ein ihrer Sub-Tasks ready-for-agent trägt; das subtask_keys-Feld im Plan-Output enthält ausschließlich die ready-for-agent-markierten Sub-Tasks in Status Zu erledigen — andere Sub-Tasks der Story bleiben unberührt (Korrektur 2026-05-17, siehe Rejected-Alternatives unten). |
| Granularität pro Iteration | Pro Sub-Task: Plan-Phase + n Slice-Iterationen, jede Slice mit Implement- und Check-Phase (Bash-orchestriert, Handoff-File als State) |
| Workflow-Phasen | Drei Phase-Prompt-Files: plan-prompt.md → Handoff-File mit Slices; implement-prompt.md pro Slice; check-prompt.md kombiniert Standards-Review + Tech-Verify + Acceptance-Check in einem Pass mit drei VERDICT:-Markern |
| Model | Sonnet 4.6 für alle Phasen, kein Heavy-Brief, keine Custom-Sub-Agents |
| Verify-Achse pro Sub-Task | drupal-pre-merge-gate + (bei Touch von web/themes/custom/** oder Canvas-Komposition) agent-browser |
| Loop-Termination | ./scripts/ralph.sh <n>, Exit-Marker <promise>NO_AGENT_READY</promise> oder Iterations-Erschöpfung |
| Failure-Mode | Story stoppen, Sub-Task → Blocked, Jira-Comment, nächste Story |
| PR-Trigger | 1 PR pro Story nach letztem grünen Sub-Task |
| Pre-PR-Tail | solcom-review + einmaliger auto-review-fix-Pass, unfixed Findings → PR-Body |
| QA-Plan-Quelle | Story-Hub-Sektion QA-Plan, Refinement-Pflicht; Loop kopiert in PR-Body |
| DB-Sync | Pre-Loop: mw app exec ... drush sql-dump → DDEV-Snapshot prod-baseline. Pro Story: ddev snapshot restore prod-baseline + ddev drush cr |
| Recovery | Bei Re-Start: JQL status="In Progress"-Check, Branch-Exists-Check, Pre-Merge-Gate auf bestehenden Commits — resume statt skip |
| Driver-Modi | Mass-Loop = Shell-Skript; Single-Story = neues Skill solcom-implement-story, in-session, kompatibel mit /goal "implementier P2503-X" |
Verifizierte technische Voraussetzung (Pre-Write-Check 2026-05-17): claude -p in Version 2.1.143 unterstützt --permission-mode acceptEdits, --output-format stream-json --verbose und --allowedTools. Damit ist der phasenbasierte Workflow im non-interaktiven Modus baubar — Custom-Sub-Agent-Definitionen werden bewusst nicht genutzt.
Entscheidung
1. Shell-Skript scripts/ralph.sh als Mass-Loop-Driver
Ein ~80 Zeilen langes Bash-Skript wird unter scripts/ralph.sh abgelegt und vom Repo-Root mit ./scripts/ralph.sh <n> aufgerufen. <n> ist die Maximum-Anzahl an Story-Iterationen pro Lauf (mattpocock-Style; harter Cost-Cap pro Run). Das Skript läuft außerhalb der Claude-Code-Session als unabhängiger lokaler Prozess.
source scripts/lib/subtask-orchestrator.sh for ((i=1; i<=$1; i++)); do # 0. Recovery-Check: gibt es eine In-Progress-Story (+ Handoff-Files)? # 1. Pickup: JQL ready-for-agent Sub-Tasks → Parent-Story-Aggregation (rank ASC) # 2. Branch: git checkout develop && git pull && git checkout -b feature/<KEY> # 3. DB: ddev snapshot restore prod-baseline && ddev drush cr # 4. Pro Sub-Task: run_subtask_pipeline "$SUB" # → plan-prompt.md (einmalig) → Handoff-File mit Slices # → pro Slice: implement-prompt.md → check-prompt.md → bei Pass: commit # → SUBTASK_DONE | SUBTASK_BLOCKED # 5. Pre-PR-Tail: solcom-review + auto-review-fix single-shot # 6. PR: gh pr create mit Story-Hub-QA-Plan im Body # 7. Loop-Exit-Marker prüfen done
2. Phase-Prompt-Files — Shell ruft pro Phase einen Plain-claude -p-Call mit klarem Output-Kontrakt
Die Orchestrierung läuft in Bash, nicht über einen LLM-Orchestrator-Agenten. Jede Workflow-Phase ist ein eigenes Prompt-File unter scripts/prompts/ mit klarem Input/Output-Kontrakt (analog mattpocock/.sandcastle/). ralph.sh (bzw. die ausgelagerte Bash-Funktion in scripts/lib/subtask-orchestrator.sh) fährt die Phasen sequenziell ab, übergibt Werte via Environment-Vars + envsubst, liest strukturierten Output aus dem persistenten Handoff-File und entscheidet Pass/Fail/Loop selbst.
Keine Custom-Sub-Agent-Definitionen, keine --agents-JSON, kein --agent-Flag — schlanker als das Sub-Agent-Konstrukt. Vorteile: (a) claude -p ohne Agent-Setup ist schneller und billiger pro Call; (b) Prompts sind versionsverwaltete .md-Files, debuggbar und einzeln testbar; (c) keine Spawn-Komplexität, keine JSON-Parser-Disziplin; (d) /goal "@scripts/prompts/plan-prompt.md ad-hoc P2503-127" ruft eine Phase auch interaktiv auf.
Drei Phase-Prompt-Files pro Sub-Task:
-
scripts/prompts/plan-prompt.md— Planning-Phase. Läuft einmal pro Sub-Task vor dem ersten Slice. Input via Env:JIRA_KEY,STORY_KEY,STORY_HUB_PATH,HANDOFF_PATH. Anweisung: lies Story-Hub, lies Sub-Task-AKs (acli jira workitem view $JIRA_KEY --json --fields description), inventarisiere relevante Code-Files (Grep auf AK-Stichworte), zerlege den Sub-Task in eine geordnete Liste von TDD-Slices (typisch 1–3 Slices, je Slice red → green → refactor mit klarem Verhalten), schreibe Ergebnis als HTML nach$HANDOFF_PATH. Output-Kontrakt: Handoff-File existiert nach Lauf, enthält gültige Slice-Tabelle mit Statustodopro Slice. Kein Code-Write außerhalb des Handoff-Files. -
scripts/prompts/implement-prompt.md— Implementation-Phase. Läuft pro Slice + pro Rework-Iteration. Input via Env:JIRA_KEY,HANDOFF_PATH,SLICE_NUM,ITERATION. Anweisung: lies das Handoff-File, picked Slice$SLICE_NUM; wenn$ITERATION > 1, lies zusätzlich die Findings-Log-Sektion und adressiere die Reports surgical. Fahre einensolcom-tdd-Vertical-Slice (Test schreiben → Code → refactor). Output: Diff seit Slice-Base wird vom Shell-Caller geprüft, Implementation steht im Working-Tree.--permission-mode acceptEdits. -
scripts/prompts/check-prompt.md— Check-Phase (kombiniert Standards-Review + Tech-Verify + Acceptance-Check in einem Pass mit drei Sektionen). Input via Env:JIRA_KEY,HANDOFF_PATH,SLICE_BASE(Git-SHA),SLICE_NUM,ITERATION. Anweisung: drei explizite Sub-Stages — (1) Standards-Review gegenbyte_theme/AGENTS.md, ADRs, vier Code-Reviewer-Skill-Regeln; (2) Tech-Verify viadrupal-pre-merge-gateplus bei Frontend-Touchagent-browser-Visual-Verify gegen QA-Plan-URLs; (3) Acceptance-Check: pro Sub-Task-AK eine Verifikation (Test-Coverage, Browser-Pfad oder Drush/DB-Inspection) mit Pass/Fail/Inconclusive. Output: appende Findings-Log-Sektion ans Handoff-File mit drei Sub-Sektionen (standards, tech, acceptance), jede mit Verdict-MarkerVERDICT: passoderVERDICT: fail. Kein Code-Write außerhalb des Handoff-Files.
Die Phasen-Trennung folgt der Karpathy-/mattpocock-Discipline: ein Prompt = eine Phase = ein klarer Output-Kontrakt. Der Shell-Caller liest nur die VERDICT:-Marker im Handoff-File und entscheidet Pass/Loop. Keine LLM-zu-LLM-Kommunikation.
Handoff-File-Layout
Pro Sub-Task entsteht ein selbst-enthaltenes HTML-File unter scripts/state/ralph/${SUB}-handoff.html (gitignored, Verzeichnis wird beim ersten Bootstrap angelegt). Format folgt dem Karpathy-„doing"-Pattern (chrismdp/ralph): persistenter Workflow-State, der Mac-Restarts und Loop-Abbrüche überlebt.
<!doctype html>
<meta name="ralph:subtask" content="P2503-127">
<meta name="ralph:story" content="P2503-108">
<meta name="ralph:branch" content="feature/P2503-108">
<meta name="ralph:iter" content="2">
<meta name="ralph:status" content="doing">
<title>P2503-127 — handoff</title>
<section id="slices">
<table>
<tr><th>#</th><th>Slice</th><th>Expected changes</th><th>Status</th></tr>
<tr><td>1</td><td>Add migrate_plus source plugin for SF REST</td><td>config/sync/migrate_plus.*.yml + src/Plugin/migrate/source/*</td><td>done</td></tr>
<tr><td>2</td><td>Wire EventSubscriber for hard-delete sweep</td><td>src/EventSubscriber/* + tests/Kernel/*</td><td>doing</td></tr>
</table>
</section>
<section id="findings-log">
<h3>Iteration 1 (slice 2)</h3>
<p>reviewer: 1 high finding — EventSubscriber missing @priority arg</p>
<p>verifier: PHPCS clean, PHPStan level 5 ok, 2 Kernel tests added pass</p>
<p>acceptance-checker: AK1 pass, AK2 inconclusive (no DB-assertion of delete-sweep)</p>
</section>
Innerer Loop pro Sub-Task (Shell-implementiert)
Workflow: plan → Slice-Loop (n Slices) → pro Slice Rework-Loop (max 3 Iterationen).
export JIRA_KEY="$SUB"
export STORY_KEY="$STORY_KEY"
export STORY_HUB_PATH="$(ls docs/stories/${STORY_KEY}-*.html | head -1)"
export HANDOFF_PATH="scripts/state/ralph/${SUB}-handoff.html"
# 1) Plan once per sub-task (skip if handoff already exists from recovery)
if [ ! -f "$HANDOFF_PATH" ]; then
claude -p --permission-mode acceptEdits \
--output-format stream-json --verbose \
"$(envsubst < scripts/prompts/plan-prompt.md)" \
| tee "/tmp/ralph-${SUB}-plan.jsonl" | jq-filter
fi
# 2) Slice loop — iterate todo-slices until all done or one blocks
while next_todo_slice "$HANDOFF_PATH" > /dev/null; do
SLICE_NUM=$(next_todo_slice "$HANDOFF_PATH")
mark_slice_doing "$HANDOFF_PATH" "$SLICE_NUM"
export SLICE_NUM
export SLICE_BASE=$(git rev-parse HEAD)
# 3) Rework loop — max 3 iterations per slice
for iter in 1 2 3; do
export ITERATION="$iter"
# implement-phase
claude -p --permission-mode acceptEdits \
--output-format stream-json --verbose \
"$(envsubst < scripts/prompts/implement-prompt.md)" \
| tee "/tmp/ralph-${SUB}-slice${SLICE_NUM}-iter${iter}-impl.jsonl" | jq-filter
# check-phase (appends to handoff)
claude -p \
--output-format stream-json --verbose \
"$(envsubst < scripts/prompts/check-prompt.md)" \
| tee "/tmp/ralph-${SUB}-slice${SLICE_NUM}-iter${iter}-check.jsonl" | jq-filter
if passes_check "$HANDOFF_PATH" "$SLICE_NUM" "$iter"; then
git add . && git commit -m "feat(${SUB}): slice ${SLICE_NUM}"
mark_slice_done "$HANDOFF_PATH" "$SLICE_NUM"
break
fi
done
if ! passes_check "$HANDOFF_PATH" "$SLICE_NUM" "$iter"; then
mark_slice_blocked "$HANDOFF_PATH" "$SLICE_NUM"
echo "<promise>SUBTASK_BLOCKED:${SUB}:slice${SLICE_NUM}</promise>"
return 1
fi
done
# 4) All slices done — clean up handoff, emit done-promise
rm "$HANDOFF_PATH"
echo "<promise>SUBTASK_DONE:${SUB}</promise>"
Helper-Funktionen next_todo_slice, mark_slice_doing, mark_slice_done, mark_slice_blocked, passes_check liegen in scripts/lib/subtask-orchestrator.sh. passes_check liest die zuletzt geschriebene Findings-Log-Sektion des Handoff-Files (XPath auf section#findings-log/section[last()]) und prüft ob alle drei VERDICT:-Marker auf pass stehen. Handoff-Mutation läuft über xmlstarlet ed -L (in-place edit auf konkreten XPath-Knoten), nicht über naives sed.
Cleanup-Policy: bei SUBTASK_DONE wird das Handoff-File gelöscht (Sub-Task abgeschlossen, Diff in Git committed). Bei SUBTASK_BLOCKED bleibt das File für Mensch-Inspektion liegen — der Handoff-Status (welche Slices done, welche blocked, welche Findings) ist dann der Hand-Over für den manuellen Pickup.
Vorteile gegenüber einem LLM-Orchestrator: (a) deterministischer Kontrollfluss in Bash, debuggbar; (b) Persistenter Sub-Task-State im Handoff-File, übersteht Mac-Restart; (c) Sub-Agent-Outputs persistieren als /tmp/ralph-*.jsonl für Post-Mortem; (d) keine zusätzliche LLM-Token-Schicht; (e) set -euo pipefail fängt Bash-Fehler hart auf; (f) Multi-Slice-Sub-Tasks bekommen pro Slice einen sauberen Conventional-Commit.
3. Branch-Lifecycle zwischen Stories
Nach Pull-Request-Open für Story A: git checkout develop, git pull origin develop --rebase, git branch -D feature/P2503-A (lokaler Branch entfernt — der PR-Branch lebt remote weiter). Die nächste Story startet auf einem frischen Pull von develop. Damit basiert jeder neue Feature-Branch garantiert auf dem aktuellsten develop-Stand.
4. PROD-DB-Sync
Pre-Loop (einmal pro ralph.sh-Aufruf): mw app exec <app-id> "drush sql-dump --gzip" > /tmp/prod.sql.gz, gefolgt von ddev import-db --file=/tmp/prod.sql.gz und ddev snapshot prod-baseline. Per-Story: ddev snapshot restore prod-baseline && ddev drush cr (~30-60 Sekunden Overhead pro Story). Setzt Skill mittwald-hosting + die Mittwald-CLI mw mit gesetzter MITTWALD_API_TOKEN-Env-Var voraus.
5. Pre-PR-Tail
Nach dem letzten grünen Sub-Task öffnet das Skript zwei weitere claude -p-Calls:
/solcom-reviewauf den Story-Diff, mit explizit--no-persistim ralph-Modus (sonst entstehen pro Mass-Run bis zu 50 HTML-Reports unterdocs/reports/). Der Report wird stattdessen als Inline-Sektion in den PR-Body übernommen. Memory[[feedback_solcom_review_persist_default]]bleibt für manuelle Aufrufe gültig; der ralph-Modus überschreibt das Default.auto-review-fixim neuen single-shot Mode: liest den Review-Report, fixt was deterministisch fixbar ist (Typos, Imports, Format), kein Retry-bis-grün-Loop. Unfixed Findings landen als TODO-Liste im PR-Body.
Der PR-Body folgt dem neuen Template (siehe Plan) mit Sektionen: Story-Summary, Sub-Task-Commits, Open Findings, QA-Plan (aus Story-Hub kopiert).
6. Failure-Mode
Wenn ein Sub-Task nach maximal drei TDD-Loop-Versuchen rote Tests oder rotes drupal-pre-merge-gate liefert: Sub-Task wird in Jira auf Blocked transitioniert, Jira-Comment mit den letzten drei Versuchsbeschreibungen plus Branch-Name plus Stack-Trace, Branch bleibt lokal offen ohne PR, Loop kehrt zu develop zurück und picked die nächste ready-for-agent Story. Manueller Pickup durch den Menschen entscheidet ob der Branch fortgesetzt oder verworfen wird.
7. Recovery bei abgebrochenem Lauf
Pre-Loop-Check: JQL project = P2503 AND status = "In Progress" AND assignee = currentUser(). Bei null Treffern: regulärer Pickup. Bei mehr als einem Treffer: harter Stopp (Inconsistent State, Mensch muss aufräumen).
Bei einem Treffer: Branch-Exists-Check git rev-parse --verify feature/<STORY_KEY>; wenn vorhanden, Branch auschecken. Dann Handoff-File-Check über alle Sub-Tasks der Story:
- Pro Sub-Task: Datei
scripts/state/ralph/${SUB}-handoff.htmlexistiert? Wenn ja, lesesolcom:ralph:status-Meta und Slice-Tabelle. Statusdone→ Sub-Task war abgeschlossen, springe zum nächsten. Statusdoingoder Slice-Tabelle hat nochtodo/doing-Einträge → resume in der inneren Sub-Task-Loop ab der ersten nicht-done-Slice; das Handoff-File enthält bereits Plan und Findings-Log. Statusblocked→ Sub-Task wird übersprungen und Story landet im Failure-Mode (manueller Pickup). - Wenn Sub-Task in Jira „In Progress" ist, aber kein Handoff-File existiert: Inkonsistenz; Sub-Task wird zurückgesetzt auf den vorherigen Status und der reguläre Plan-Step neu ausgeführt.
- Pre-Merge-Gate auf existierenden Commits ausführen, bevor weitere Slices angefasst werden — schlägt das Gate fehl, ist die Branch in einem ungültigen Zwischenstand, harter Stopp.
8. Driver-Trennung
Mass-Loop ist scripts/ralph.sh. Single-Story ist ein neues Skill solcom-implement-story, das in-session aufgerufen wird, denselben Sub-Task-Choreographen nutzt, aber nur einen Story-Key entgegennimmt. /goal "implementier P2503-X" ist der Wrapper für das Skill.
Rejected alternatives
- Opus-4.7-Heavy-Brief-Pattern (Orchestrator) + Sonnet-Sub-Agents. Cost-Estimate ~$4.75 pro Sub-Task (gegen ~$2 bei Sonnet-All), bei 50 Sub-Tasks pro Run ~$237 vs. ~$100. Trade-off-Judgment durch Opus wäre wertvoll, wenn Sub-Tasks ein offenes Decision-Space hätten. Nach gegrilltem Stand sind Sub-Tasks aber bereits im Refinement entschieden (Architektur im Story-Hub, AKs testbar), der Orchestrator-Job ist also reine Choreographie. Verworfen wegen 2.4-facher Kosten ohne nachweisbaren Qualitätsgewinn. Real-Cost-Range bleibt $1.50–$5 pro Sub-Task abhängig von Story-Komplexität.
-
Hybrid: Opus pro Story (Slicing-Plan) + Sonnet pro Sub-Task (Execution). Pro Story einmaliger Opus-Call zur Verfeinerung des Slicing-Plans, danach Sonnet-Sub-Task-Iteration. Cost-Schätzung ~$150 pro Story-Batch. Verworfen, weil der Slicing-Plan bereits Teil des Refinements ist (
to-plan-Skill, Story-Hub) — die Opus-Stage wäre Duplikat. -
Worktree-basierte Parallel-Pipeline (ADR-0030, Detached-Mode). Mehrere DDEV-Sites parallel auf demselben Mac, mehrere Background-Claude-Prozesse via
nohup. Theoretischer Durchsatz-Gewinn nicht eingelöst: DDEV-Container-Konflikte auf demselben Docker-Daemon, Mac-Sleep-Probleme, Datenbank-Snapshot-Restore zwischen Worktrees, Debugging-Overhead bei Loop-Fehlern. Operativ instabiler als sequenzielles Pattern. In-Session-Sub-Agent-Modus (Mode A aus ADR-0030, viaAgent(isolation: "worktree")) bleibt für ad-hoc Use-Cases offen; nur der Detached-Mode wird deprecated. - PR pro Sub-Task statt pro Story. Sehr kleine reviewbare Diffs, aber n PRs pro Story (5–15 typisch) bedeuten 5–15-fachen Merge-Overhead und Story-QA als Ganzes wird schwer (Tester muss durch alle PRs durch). Verworfen wegen Mensch-QA-Aufwand.
-
Cron-getriebener vollautonomer Mass-Loop (Office-Hours Mo-Fr 8:07-17:07). Analog zum bestehenden
auto-review-fix-Cron. Verworfen, weil (a) Mac-Wach-Annahme bei lokalem Dev-Setup nicht haltbar ist, (b) DDEV-Stabilität bei langlaufenden Hintergrund-Prozessen nicht gegeben, (c) Cost-Kontrolle ohne manuellen Trigger schwer. -
/loop-Skill statt Shell-Skript. Der globale/loop-Skill kann beliebige Prompts auf einem Intervall ausführen und überlebt Claude-Code-Session-Restarts viaScheduleWakeup. Verworfen, weil (a) der Mass-Loop ein unabhängiger Prozess sein soll, der nicht an die Claude-Code-Session gebunden ist, (b) Shell-Loops sind lesbarer, portabler und mitset -e-Discipline einfacher zu debuggen als Skill-Wrapper, (c) Mattpocock-Pattern-Parity erleichtert das Onboarding für externe Mitleser. -
implement-Skill weiterführen mit Sonnet-Only-Mode. Theoretisch durch eine Skill-Variante adressierbar, aber das Skill ist seit Aufbau an Persistent-Monitor, Goal-Hook und Worktree-Mode gekoppelt — der Refactor wäre ein vollständiger Rewrite. Klarer Schnitt mit neuem Skillsolcom-implement-storyist sauberer. -
Reines Story-Level-Pickup (Label nur auf Story). Ursprünglicher Vorschlag:
ready-for-agentsitzt auf der Story,subtask_keyssind alle ihre Sub-Tasks. Verworfen am 2026-05-17 nach Backlog-Inspektion: Refinement im SOLCOM-Backlog markiert Sub-Tasks einzeln als ready-for-agent — nicht alle Sub-Tasks einer Story sind gleichzeitig Refinement-fertig, manche bleiben bewusst Mensch-Arbeit. Gewählter Pickup: Sub-Task-Level-Label, Parent-Aggregation im Planner. Vorteile: (a) Refinement-Granularität bleibt erhalten, (b) Sub-Tasks ohne Label bleiben außerhalb des Loops, (c) PR-pro-Story bleibt baubar weil Planner zur Parent-Story aggregiert und alle gewählten Sub-Tasks im selben Branch landen. Anti-Risiko (kein gemeinsamer Feature-Branch) wird durch die Aggregation neutralisiert: der Loop arbeitet genau die ready-for-agent Sub-Tasks der gewählten Story ab, nicht beliebige Sub-Tasks parallel. -
QA-Plan vom Loop generieren lassen. Ein vierter Sonnet-Sub-Agent („QA-Plan-Author") generiert den QA-Plan aus AKs plus Diff. Verworfen, weil Halluzinations-Risiko (falsche URLs, unklare Click-Pfade) hoch ist; QA-Plan muss vor dem Build mensch-validiert sein. Stattdessen wird die Story-Hub-Sektion QA-Plan zur Refinement-Pflicht erklärt; die Skills
to-prd,to-planundgrill-with-docserzwingen sie im Output-Template.
Consequences
Deprecation und Supersession
implement-Skill: Status auf deprecated, Skill-File mit Header-Note belegen, dasssolcom-implement-storyundscripts/ralph.shdie Nachfolger sind. Nicht entfernen — Audit-Trail.- ADR-0030 (Worktree-Pattern): Partially superseded. Mode A („in-session Sub-Agent" via
Agent(isolation: "worktree")) bleibt gültig für ad-hoc-Isolation. Mode B („detached Background-Claude" vianohup) wird deprecated. Memory[[project_parallel_loops_architecture]]wird scope-narrowed auf Mode A. - Memory
[[project_implement_pipeline_triple]]: Re-write — Triple implement → solcom-review → auto-review-fix wird ersetzt durch ralph.sh / solcom-implement-story → solcom-tdd → solcom-review (no-persist) → auto-review-fix (single-shot). - Memory
[[project_office_hours_cron]]: Status auf obsolete. Office-Hours-Cron wird abgebaut, manuellerralph.sh-Trigger ersetzt den Cycle.
Neue Artefakte
scripts/ralph.sh— Bash-Skript (Story-Loop)scripts/prompts/plan-prompt.md— Planning-Phase-Prompt (einmal pro Sub-Task)scripts/prompts/implement-prompt.md— Implement-Phase-Prompt (pro Slice + Rework-Iteration)scripts/prompts/check-prompt.md— Combined-Check-Phase-Prompt (Standards-Review + Tech-Verify + Acceptance, drei VERDICT-Marker)scripts/lib/subtask-orchestrator.sh— Bash-Helper-Library (run_subtask_pipeline, Handoff-Mutation viaxmlstarlet,passes_check)scripts/lib/db-sync.sh— PROD-Pull + DDEV-Snapshot-Mechanikscripts/lib/pr-body-template.md— PR-Body-Template mit Sektionen Story-Summary / Sub-Task-Commits / Open Findings / QA-Planscripts/state/ralph/.gitkeep— State-Verzeichnis (Handoff-Files*-handoff.htmlsind gitignored).claude/skills/solcom-ralph-loop/SKILL.md— Operator-Dokumentation des Mass-Loops.claude/skills/solcom-implement-story/SKILL.md— Single-Story-Variante für/goal "implementier P2503-X"
Skill-Updates
to-prd,to-plan,grill-with-docs: Output-Template um Pflicht-Sektion QA-Plan erweitern (Click-Pfad: URL, Action, Expected Result; pro Story-AK eine Zeile).auto-review-fix: Single-Shot-Mode hinzufügen (Flag--single-pass), Worktree-Mode bleibt als Default für legacy-Use-Cases; im ralph-Modus wird--single-passerzwungen und Worktree-Setup übersprungen.solcom-review:--no-persist-Flag respektieren wenn aus ralph-Kontext aufgerufen (Environment-VarRALPH_LOOP=1); ansonsten bleibt--persistDefault.
Operative Annahmen
- Conventional-Commit-Format pro Sub-Task:
<type>(<jira-key>): <subject>, z. B.feat(P2503-127): add vacancy hard-delete sweep. Type aus dem Standard-Set feat / fix / refactor / docs / test / chore. Branch-Trailer im Commit-Body verlinkt auf Story-Hub und Sub-Task-Jira-URL. - Jira-Transitions: Vor erstem Lauf via
acli jira workitem transition --key P2503-XXX --listverifizieren, dass In Progress, Fertig, Blocked exakt so existieren. Falls Workflow umbenannt, ralph.sh-Konstanten anpassen. - Cost-Range: ~$1.50–$5 pro Sub-Task (variabel je nach Story-Komplexität und Diff-Größe). Bei 50 Sub-Tasks pro Run grobe Spanne $75–$250. Cap durch
<n>-Argument am Aufruf. - DB-Sync-Overhead: ~30–60 Sekunden pro Story. Bei 10 Stories pro Run = 5–10 Minuten reine DB-Zeit. Akzeptabel, weil sequenziell.
- Story-Hub-QA-Plan: Stories ohne QA-Plan-Sektion werden vom Loop übersprungen und in Jira mit Comment „missing QA plan, refine before ready-for-agent" auf den ursprünglichen Status zurückgesetzt. Damit wird Refinement-Discipline erzwungen.
git branch -D feature/<KEY> erst aus, nachdem der PR remote angelegt und das CI-Build gestartet ist (gh pr view --json url liefert Bestätigung). Bei lokalem Push-Fehler bleibt der Branch lokal stehen und Loop transitioniert in den Failure-Mode für diese Story.Migrations-Pfad
- Plan 2026-05-17-001-ralph-loop.html baut die neun Tracer-Bullet-Slices.
- Nach grünem End-to-End-Lauf auf einer Pilot-Story (Empfehlung: kleinster offener ready-for-agent Sub-Task): Memory-Updates und Deprecation-Header in den alten Skills.
- Cron-Job-Abbau (Office-Hours) separat im selben Sprint.
Amendment 2026-05-20 — Anthropic-Harness-Adaption
Diese ADR ist partially superseded durch das ADR-Quartett 0040 / 0041 / 0042 / 0043. Drei Veränderungen sind material:
- Loop-Phasen-Anordnung erweitert — zwischen
planundimplementkommen zwei neue PhasenCONTRACT(Sprint-Contract pro Story) undCONTRACT-EVAL(4-Check-Verdict, bis zu 3 Retries). Details: ADR-0040. - Handoff-File-Pattern endgültig gestrichen — das ursprünglich in dieser ADR vorgesehene
${HANDOFF_PATH}-HTML mit<section id="findings-log">wurde in der tatsächlichen Implementation weggelassen und nie durch ein gleichwertiges Konstrukt ersetzt. ADR-0041 ersetzt es durch eine Hub-interne<section id="implementation-notes">mit Sub-Task-Granularität, akkumuliert über drei Phasen (implement/review/merge). Die in dieser ADR oben referenzierten Abschnitte "Handoff-File-Layout" und das im Plan 2026-05-17-001 erwähnte${HANDOFF_PATH}sind durch ADR-0041 obsolet. - Sonnet-only und Reviewer-Calibration — User-Direktive vom 2026-05-20: alle Loop-Phasen laufen Sonnet. Das Heavy-Brief-Pattern aus Memory
project_implement_pipeline_triple(Opus orchestriert, Sonnet implementiert) ist damit für den Ralph-Loop relativiert. Da Sonnet als QA-Agent kalibriert werden muss (Anthropic-Warnung), wird in ADR-0042 ein zwei-stufiges Calibration-Pattern eingeführt: Few-shot-Examples plus Post-mortem-Lessons-Log unterdocs/agents/reviewer-calibration.html.
Zusätzlich wird der Out-of-Scope-Pool (ADR-0043) als eigenständiger Strang eingeführt: docs/refactoring-pool.html als append-only Audit-Trail für Refactoring-Funde, bewusst nicht als Jira-Sub-Tasks. Dies ist eine bewusste Abkehr von der Jira-als-kanonische-Senke-Konvention und ist nur für den Refactoring-Strang zulässig.
Die in dieser ADR beschriebene 4-Phasen-Pipeline bleibt strukturell gültig (plan / implement / review / merge); ADR-0040 fügt zwei Phasen vor implement ein, verändert aber weder Story-Pickup noch Sub-Task-Loop noch Promise-Marker-Mechanik. Implementation-Plan: docs/plans/2026-05-20-001-anthropic-harness-adaption.html.
Amendment 2026-05-21 — Deprecation of Git Worktrees
Diese ADR und der Ralph-Loop werden am 2026-05-21 im Rahmen von ADR-0045 angepasst:
- Verzicht auf Git-Worktrees: Der Ralph-Loop läuft nicht mehr in isolierten, parallelen Worktrees mit dynamischen DDEV-Port-Zuweisungen. Alle Ausführungen laufen sequentiell direkt im Hauptarbeitsverzeichnis (primary workspace).
- Sequentielle Ausführung: Da keine parallelen Instanzen mehr gestartet werden können (Gefahr von Port- und Datenbankkonflikten), werden offene Aufgaben nacheinander abgearbeitet.
- Sauberes Arbeitsverzeichnis als Voraussetzung: Vor dem Start eines Loops oder Skills (z. B.
auto-review-fix) wird zwingend geprüft, ob das Arbeitsverzeichnis sauber ist (git status --porcelainist leer), um uncommittete Änderungen des Entwicklers vor Überschreiben zu schützen.