Skip to content

PreToolUse Edit hook returns invalid {"decision":"allow"} — regression of #1573 in CLI handler #1847

Description

@michelhelsdingen

Repro (specweave 1.0.581)

echo '{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/tmp/foo","old_string":"a","new_string":"b"}}' | specweave hook pre-tool-use
# Output: {"decision":"allow"}

Claude Code rejects this with:

PreToolUse:Edit hook error
Hook JSON output validation failed — (root): Invalid input

Why it's invalid

Claude Code's hook output schema accepts either:

  • Legacy format: {"decision": "approve" | "block", "reason": "..."} — the value "allow" is not in the enum.
  • Current format: {"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow" | "deny" | "ask", "permissionDecisionReason": "..."}}

SpecWeave's CLI emits a bare {"decision":"allow"}, which matches neither. Returning {} (empty object), {"continue": true}, or migrating to the hookSpecificOutput shape would all fix this.

Why this is a regression of #1573

#1573 ("Eliminate PreToolUse Edit Hook Errors") was closed on 2026-03-15 with status:complete and 100% AC, but:

  • closedByPullRequestsReferences is empty — no PR was merged for the closure.
  • The fix described (set +e instead of set -e in pre-tool-use.sh) targeted a shell handler that has since been removed.
  • Commit 0f81519 ("rework hooks: remove shell-based handlers, consolidate to CLI-first approach") replaced that shell handler with the Node CLI dispatcher, which reintroduces the same user-visible symptom — but now from a different code path (TypeScript schema bug instead of bash exit code).

Impact

The hook matcher is Write|Edit, so this error fires on every file edit during a Claude Code session. It's cosmetic (fail-open, the edit still happens), but produces:

  1. Persistent red error noise in the Claude Code UI.
  2. Wasted time per hook invocation (the dispatch + JSON serialize) for no useful effect when the schema is invalid.
  3. Erosion of trust in the plugin — users who hit this and don't actively use SpecWeave end up disabling the whole plugin.

Environment

  • specweave: 1.0.581 (latest npm at time of report)
  • Claude Code: 2.x (current line)
  • macOS: Darwin 25.4.0 (arm64)
  • Node: v25.9.0

Suggested fix

In the CLI's pre-tool-use handler, change the success response from:

{ decision: "allow" }

to either:

{}  // simplest — nothing returned means "proceed normally"

or, if explicit permission control is intended:

{
  hookSpecificOutput: {
    hookEventName: "PreToolUse",
    permissionDecision: "allow",
    permissionDecisionReason: "<your reason>"
  }
}

Happy to test a candidate PR.

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