Skip to content

PreToolUse hook uses deprecated decision field — needs migration to hookSpecificOutput #59

@brettohland

Description

@brettohland

I've been using xcsift with Claude Code for a few days now and I noticed a small visual bug while using the tool.

Just a heads up, the summary of the situation and the patch file were generated by Claude Code. I've verified that it does fix the issue, and the fix seems reasonable.


Summary

The pre-xcsift.sh PreToolUse hook uses the deprecated top-level decision field for its JSON output. Claude Code has replaced this with a hookSpecificOutput wrapper structure, so the hook output is no longer recognized — resulting in a PreToolUse:Bash hook error + (No output) on every Bash tool call that isn't an xcodebuild/swift build command.

The tool call still proceeds (Claude Code defaults to allow on hook errors), so nothing is broken functionally — but the error banner appears on every non-build Bash invocation.

Affected Version

xcsift plugin v1.0.2

Details

plugins/claude-code/scripts/pre-xcsift.sh currently outputs the deprecated format:

{"decision": "allow"}

The current expected format is:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow"
  }
}

This affects all four output paths in the script — the three passthrough cases (lines 14, 22, 44) and the build-command rewrite (line 41), where updatedCommand should also become updatedInput.

Separately, set -e on line 5 can cause the script to exit silently with no output if jq or grep fails unexpectedly, which also triggers the error banner.

Steps to Reproduce

  1. Install xcsift plugin in Claude Code
  2. Run any non-build Bash command (e.g., git status, ls, open ...)
  3. Observe PreToolUse:Bash hook error / (No output) in output

Suggested Fix

--- a/plugins/claude-code/scripts/pre-xcsift.sh
+++ b/plugins/claude-code/scripts/pre-xcsift.sh
@@ -2,8 +2,6 @@
 # xcsift pre-tool hook for Claude Code
 # Intercepts xcodebuild and swift build/test commands and pipes through xcsift

-set -e
-
 # Read tool input from stdin (JSON with tool_input field)
 INPUT=$(cat)

@@ -12,14 +10,14 @@

 if [ -z "$COMMAND" ]; then
     # No command field, allow as-is
-    echo '{"decision": "allow"}'
+    echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
     exit 0
 fi

 # Check if xcsift is available
 if ! command -v xcsift &> /dev/null; then
     # xcsift not installed, allow command as-is
-    echo '{"decision": "allow"}'
+    echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
     exit 0
 fi

@@ -38,8 +36,8 @@
     MODIFIED_COMMAND="$COMMAND | xcsift -f toon"

     # Return modified command
-    jq -n --arg cmd "$MODIFIED_COMMAND" '{"decision": "allow", "updatedCommand": $cmd}'
+    jq -n --arg cmd "$MODIFIED_COMMAND" '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","updatedInput":{"command":$cmd}}}'
 else
     # Not a build command, allow as-is
-    echo '{"decision": "allow"}'
+    echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
 fi

A patch file is also attached for convenience.

Reference

The current hook output format is documented at https://docs.claude.com/en/docs/hooks — the hookSpecificOutput structure with permissionDecision replaces the deprecated top-level decision field.

fix-pre-xcsift-hook-output-format.patch

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions