Ralph Wiggum Technique
- Entity ID:
ent-20260410-8a2383cf7446 - Type:
concept - Scope:
shared - Status:
active
Description
The Ralph Wiggum Technique is a community-developed pattern for building autonomous overnight agent loops using Claude Code's Stop hook system. When Claude finishes responding and believes its task is complete, the query loop in src/query.ts calls handleStopHooks() (from src/query/stopHooks.ts), which executes all user-configured Stop hooks. A Stop hook is a shell command (or function hook) that runs after every assistant turn and can inspect the last assistant message, the transcript, and the session state. If the hook exits with code 2, it produces a "blocking error" that is injected back into the conversation as a user message, forcing the query loop to continue with another iteration.
The core mechanism lives in the queryLoop() function (line 241 of src/query.ts). After the model's turn ends and stop hooks are executed, the result is checked: if stopHookResult.blockingErrors.length > 0, the blocking error messages are appended to the conversation history, stopHookActive is set to true, and the loop continues with transition: { reason: 'stop_hook_blocking' }. This means the model sees the hook's feedback as a new user message and responds again. If instead stopHookResult.preventContinuation is true (the hook output { "continue": false }), the loop terminates immediately. The stop_hook_active boolean is passed into subsequent hook executions so hooks can detect re-entrant invocation.
The Stop hook input includes last_assistant_message (the text content of the model's final response) and stop_hook_active (whether the model is already in a hook-driven continuation). This allows the hook script to implement completion validation: parse the assistant's output for a specific signal word or check that acceptance criteria are met, then either block (exit 2 with feedback) to continue the loop, or allow (exit 0) to let the agent stop. The hook can also output structured JSON with { "continue": false, "stopReason": "..." } to force termination. Additional hook types (TeammateIdle, TaskCompleted) follow the same blocking-error pattern for teammate agents.
Key claims
- Stop hooks are executed via
executeStopHooks()insrc/utils/hooks.ts(line 3639), which creates aStopHookInputcontainingstop_hook_activeandlast_assistant_message, then delegates to the genericexecuteHooks()infrastructure. - Blocking errors (exit code 2) are caught in
handleStopHooks()(src/query/stopHooks.tsline 257-267): each blocking error is wrapped increateUserMessage({ content: getStopHookMessage(...), isMeta: true })and yielded back to the query loop. - The query loop continues on blocking errors at
src/query.tsline 1282-1306: the state is updated with the error messages appended,stopHookActive: true, andtransition: { reason: 'stop_hook_blocking' }, thencontinuere-enters the loop. - Hooks can force termination via
preventContinuation(src/query/stopHooks.tsline 269-279) by outputting JSON with{ "continue": false }, which maps to thesyncHookResponseSchemainsrc/types/hooks.ts(line 51-53). - Hook errors are surfaced via a notification (
src/query/stopHooks.tsline 311-320) telling the user to press Ctrl+O to see stop hook errors in the transcript view.
Relations
- implemented-by:
src/query/stopHooks.ts--handleStopHooks()orchestrates Stop hook execution and yields blocking errors - implemented-by:
src/utils/hooks.ts--executeStopHooks()builds StopHookInput and runs hooks - consumed-by:
src/query.ts--queryLoop()checks blocking errors and loops or terminates - schema:
src/types/hooks.ts--syncHookResponseSchemadefinescontinue,stopReason,suppressOutput - schema:
src/entrypoints/sdk/coreSchemas.ts--StopHookInputSchemadefinesstop_hook_active,last_assistant_message
Sources
src/query.tssrc/query/stopHooks.tssrc/utils/hooks.tssrc/types/hooks.tssrc/entrypoints/sdk/coreSchemas.ts