[FEATURE REQUEST] PreToolUse Hook should be able to modify tool inputs

Resolved 💬 4 comments Opened Jul 4, 2025 by csells Closed Dec 30, 2025

Summary

PreToolUse hooks can successfully process and modify tool input JSON, but the modified commands are not executed. Instead, Claude Code continues to execute the original unmodified command.

Environment

  • Claude Code Version: v1.0.43
  • Platform: macOS (Darwin 24.5.0)
  • Hook Type: PreToolUse
  • Tool: Bash

Expected Behavior

When a PreToolUse hook modifies the tool_input.command field and returns {"decision": "approve"}, Claude Code should execute the modified command.

Actual Behavior

Claude Code executes the original command, ignoring modifications made by the hook.

Reproduction Steps

  1. Create hook configuration in .claude/settings.local.json:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq '.tool_input.command = \"ANTHROPIC_API_KEY='$ANTHROPIC_API_TEST_KEY' \" + .tool_input.command | .decision = \"approve\"'"
          }
        ]
      }
    ]
  }
}
  1. Set environment variable in global ~/.claude/settings.json:
{
  "env": {
    "ANTHROPIC_API_TEST_KEY": "test-key-value"
  }
}
  1. Create test file example/hook_test.dart:
import 'dart:io';

void main() {
  print('ANTHROPIC_API_KEY.length: ${Platform.environment['ANTHROPIC_API_KEY']?.length ?? 0}');
  print('ANTHROPIC_API_TEST_KEY.length: ${Platform.environment['ANTHROPIC_API_TEST_KEY']?.length ?? 0}');
}
  1. Run command: dart run example/hook_test.dart
  1. Observe output:
ANTHROPIC_API_KEY.length: 0          // Should be 108 if hook worked
ANTHROPIC_API_TEST_KEY.length: 108   // Confirms env var is available

Verification that Hook Logic Works

Manual simulation of hook command:

echo '{"tool_input": {"command": "dart run example/hook_test.dart"}}' | jq '.tool_input.command = "ANTHROPIC_API_KEY='$ANTHROPIC_API_TEST_KEY' " + .tool_input.command | .decision = "approve"'

Output:

{
  "tool_input": {
    "command": "ANTHROPIC_API_KEY=sk-ant-api03-... dart run example/hook_test.dart"
  },
  "decision": "approve"
}

Manual execution of modified command:

ANTHROPIC_API_KEY=sk-ant-api03-... dart run example/hook_test.dart

Output:

ANTHROPIC_API_KEY.length: 108        // ✅ Works when run manually
ANTHROPIC_API_TEST_KEY.length: 108

Additional Evidence

  1. Hook is triggered: Confirmed by testing with deny hooks that successfully block commands
  2. Environment variables available: ANTHROPIC_API_TEST_KEY is accessible within hook context
  3. Hook processes JSON correctly: Manual testing shows jq command works perfectly
  4. Modified command works: Manual execution with injected environment variable succeeds

Impact

This prevents users from using hooks to inject environment variables, credentials, or other command modifications that are essential for many workflows.

Workaround

None available. Manual command execution works, but automated injection via hooks fails.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗