@@ -273,6 +273,7 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
273273 stdout , stderr , exitCode , err := e .runner .RunCommandWithOutput (cmd , action .UseStdin , rawJSON )
274274
275275 // Command failed with non-zero exit code
276+ // Per official spec: hook errors are non-blocking → allow stop
276277 if exitCode != 0 {
277278 errMsg := fmt .Sprintf ("Command failed with exit code %d: %s" , exitCode , stderr )
278279 if strings .TrimSpace (stderr ) == "" && err != nil {
@@ -281,8 +282,7 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
281282 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
282283 return & ActionOutput {
283284 Continue : true ,
284- Decision : "block" ,
285- Reason : errMsg ,
285+ Decision : "" , // Allow stop on error
286286 SystemMessage : errMsg ,
287287 }, nil
288288 }
@@ -302,8 +302,7 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
302302 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
303303 return & ActionOutput {
304304 Continue : true ,
305- Decision : "block" ,
306- Reason : errMsg ,
305+ Decision : "" , // Allow stop on error
307306 SystemMessage : errMsg ,
308307 }, nil
309308 }
@@ -315,8 +314,7 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
315314 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
316315 return & ActionOutput {
317316 Continue : true ,
318- Decision : "block" ,
319- Reason : errMsg ,
317+ Decision : "" , // Allow stop on error
320318 SystemMessage : errMsg ,
321319 }, nil
322320 }
@@ -327,8 +325,7 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
327325 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
328326 return & ActionOutput {
329327 Continue : true ,
330- Decision : "block" ,
331- Reason : errMsg ,
328+ Decision : "" , // Allow stop on error
332329 SystemMessage : errMsg ,
333330 }, nil
334331 }
@@ -349,14 +346,14 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
349346 case "output" :
350347 processedMessage := unifiedTemplateReplace (action .Message , rawJSON )
351348
352- // Empty message check → fail-safe (decision: block)
349+ // Empty message check → allow stop (error in systemMessage)
350+ // Per official spec: hook errors are non-blocking → allow stop
353351 if strings .TrimSpace (processedMessage ) == "" {
354352 errMsg := "Empty message in Stop action"
355353 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
356354 return & ActionOutput {
357355 Continue : true ,
358- Decision : "block" ,
359- Reason : errMsg ,
356+ Decision : "" , // Allow stop on error
360357 SystemMessage : errMsg ,
361358 }, nil
362359 }
@@ -375,8 +372,7 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
375372 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
376373 return & ActionOutput {
377374 Continue : true ,
378- Decision : "block" ,
379- Reason : processedMessage ,
375+ Decision : "" , // Allow stop on error
380376 SystemMessage : errMsg ,
381377 }, nil
382378 }
@@ -402,13 +398,13 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
402398 }
403399
404400 // Final validation: decision "block" requires non-empty reason
401+ // Per official spec: hook errors are non-blocking → allow stop on validation error
405402 if decision == "block" && strings .TrimSpace (reason ) == "" {
406403 errMsg := "Empty reason when decision is 'block' (reason is required for block)"
407404 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
408405 return & ActionOutput {
409406 Continue : true ,
410- Decision : "block" ,
411- Reason : errMsg ,
407+ Decision : "" , // Allow stop on error
412408 SystemMessage : errMsg ,
413409 }, nil
414410 }
@@ -425,14 +421,15 @@ func (e *ActionExecutor) ExecuteStopAction(action Action, input *StopInput, rawJ
425421}
426422
427423// ExecuteSubagentStopAction executes an action for the SubagentStop event.
428- // Command failures result in exit status 2 to block the subagent stop operation .
424+ // Per official Claude Code hooks spec: hook errors are non-blocking (allow subagent stop) .
429425func (e * ActionExecutor ) ExecuteSubagentStopAction (action Action , input * SubagentStopInput , rawJSON any ) (* ActionOutput , error ) {
430426 switch action .Type {
431427 case "command" :
432428 cmd := unifiedTemplateReplace (action .Command , rawJSON )
433429 stdout , stderr , exitCode , err := e .runner .RunCommandWithOutput (cmd , action .UseStdin , rawJSON )
434430
435431 // Command failed with non-zero exit code
432+ // Per official spec: hook errors are non-blocking → allow subagent stop
436433 if exitCode != 0 {
437434 errMsg := fmt .Sprintf ("Command failed with exit code %d: %s" , exitCode , stderr )
438435 if strings .TrimSpace (stderr ) == "" && err != nil {
@@ -441,8 +438,7 @@ func (e *ActionExecutor) ExecuteSubagentStopAction(action Action, input *Subagen
441438 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
442439 return & ActionOutput {
443440 Continue : true ,
444- Decision : "block" ,
445- Reason : errMsg ,
441+ Decision : "" , // Allow subagent stop on error
446442 SystemMessage : errMsg ,
447443 }, nil
448444 }
@@ -462,8 +458,7 @@ func (e *ActionExecutor) ExecuteSubagentStopAction(action Action, input *Subagen
462458 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
463459 return & ActionOutput {
464460 Continue : true ,
465- Decision : "block" ,
466- Reason : errMsg ,
461+ Decision : "" , // Allow subagent stop on error
467462 SystemMessage : errMsg ,
468463 }, nil
469464 }
@@ -475,8 +470,7 @@ func (e *ActionExecutor) ExecuteSubagentStopAction(action Action, input *Subagen
475470 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
476471 return & ActionOutput {
477472 Continue : true ,
478- Decision : "block" ,
479- Reason : errMsg ,
473+ Decision : "" , // Allow subagent stop on error
480474 SystemMessage : errMsg ,
481475 }, nil
482476 }
@@ -487,8 +481,7 @@ func (e *ActionExecutor) ExecuteSubagentStopAction(action Action, input *Subagen
487481 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
488482 return & ActionOutput {
489483 Continue : true ,
490- Decision : "block" ,
491- Reason : errMsg ,
484+ Decision : "" , // Allow subagent stop on error
492485 SystemMessage : errMsg ,
493486 }, nil
494487 }
@@ -509,14 +502,14 @@ func (e *ActionExecutor) ExecuteSubagentStopAction(action Action, input *Subagen
509502 case "output" :
510503 processedMessage := unifiedTemplateReplace (action .Message , rawJSON )
511504
512- // Empty message check → fail-safe (decision: block)
505+ // Empty message check → allow subagent stop (error in systemMessage)
506+ // Per official spec: hook errors are non-blocking → allow subagent stop
513507 if strings .TrimSpace (processedMessage ) == "" {
514508 errMsg := "Empty message in SubagentStop action"
515509 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
516510 return & ActionOutput {
517511 Continue : true ,
518- Decision : "block" ,
519- Reason : errMsg ,
512+ Decision : "" , // Allow subagent stop on error
520513 SystemMessage : errMsg ,
521514 }, nil
522515 }
@@ -535,8 +528,7 @@ func (e *ActionExecutor) ExecuteSubagentStopAction(action Action, input *Subagen
535528 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
536529 return & ActionOutput {
537530 Continue : true ,
538- Decision : "block" ,
539- Reason : processedMessage ,
531+ Decision : "" , // Allow subagent stop on error
540532 SystemMessage : errMsg ,
541533 }, nil
542534 }
@@ -562,13 +554,13 @@ func (e *ActionExecutor) ExecuteSubagentStopAction(action Action, input *Subagen
562554 }
563555
564556 // Final validation: decision "block" requires non-empty reason
557+ // Per official spec: hook errors are non-blocking → allow subagent stop on validation error
565558 if decision == "block" && strings .TrimSpace (reason ) == "" {
566559 errMsg := "Empty reason when decision is 'block' (reason is required for block)"
567560 fmt .Fprintf (os .Stderr , "Warning: %s\n " , errMsg )
568561 return & ActionOutput {
569562 Continue : true ,
570- Decision : "block" ,
571- Reason : errMsg ,
563+ Decision : "" , // Allow subagent stop on error
572564 SystemMessage : errMsg ,
573565 }, nil
574566 }
0 commit comments