Claude Code writes each assistant content block (text/tool_use/thinking)
as its own JSONL line. The hook's `grep role:assistant | tail -1` would
grab whichever block happened to be last — often tool_use — then jq's
text filter returned empty string, triggering the 'no text content' path
which deletes the state file and exits without blocking.
Net effect: the loop silently never fires. In one observed session, 62%
of assistant lines were tool_use-only; the hook deleted state on the
very first Stop event every time.
Fix: slurp all assistant lines with jq -rs, flatten to text blocks only,
take the last. Empty result is now non-fatal — no text means no <promise>
tag, so the loop continues. Also absorbs jq parse errors (control chars
in text) via || fallback instead of aborting under set -e.
- Rename plugin from "ralph-wiggum" to "ralph-loop" to avoid trademark concerns
- Update all internal references to use "Ralph Loop" as the prominent name
- Keep explanatory text noting it "implements the Ralph Wiggum technique" (allowed)
- Rename plugin directory from plugins/ralph-wiggum to plugins/ralph-loop
- Update marketplace.json with new plugin name and source path
- Update plugin-dev documentation references
This change follows legal's recommendation to replace "Wiggum" with "Loop"
in the plugin name while still explaining the technique origin.
Slack thread: https://anthropic.slack.com/archives/C09KU300P7F/p1767741142753959
Co-authored-by: Claude <noreply@anthropic.com>