[BUG] --settings flag does not properly override hook configurations

Resolved 💬 3 comments Opened Aug 16, 2025 by arn314 Closed Jan 5, 2026

Environment

  • Platform (select one):
  • [x] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • [ ] Other: <!-- specify -->
  • Claude CLI version: 1.0.83
  • Operating System: macOS 14.6
  • Terminal: iTerm2

Bug Description

The --settings flag does not properly override hook configurations. When using --settings to provide a different hook configuration, both the original hooks (from settings.json) and the override hooks run simultaneously, instead of the override completely replacing the original configuration.

Steps to Reproduce

  1. Run the reproducer script below with a valid auth token:
#!/bin/bash

# Bug reproducer: --settings flag doesn't override hook configurations
# Usage: CLAUDE_CODE_OAUTH_TOKEN=your_token ./settings-bug-reproducer.sh

set -euo pipefail

echo "Claude Code version: $(claude --version)"
echo ""

if [[ -z "${CLAUDE_CODE_OAUTH_TOKEN:-}" ]]; then
  echo "Error: CLAUDE_CODE_OAUTH_TOKEN environment variable required"
  echo "Usage: CLAUDE_CODE_OAUTH_TOKEN=your_token $0"
  exit 1
fi

# Create isolated test environment
export HOME=/tmp/fake-home-claude-test-$(date +%s)
mkdir -p "$HOME/.claude"

# Create settings.json with default hook
echo '{
  "hooks": {
    "SessionStart": [{
      "hooks": [{"type": "command", "command": "echo DEFAULT_HOOK_OUTPUT"}]
    }]
  }
}' > "$HOME/.claude/settings.json"

echo "=== Testing --settings override behavior ==="

# Test 1: Default hook
TEST1_ID=$(uuidgen)
echo "Test 1 (default): $TEST1_ID"
claude --session-id "$TEST1_ID" -p "test" >/dev/null

# Test 2: --settings override  
TEST2_ID=$(uuidgen)
echo "Test 2 (override): $TEST2_ID"
claude --settings '{"hooks":{"SessionStart":[{"hooks":[{"type":"command","command":"echo OVERRIDE_HOOK_OUTPUT"}]}]}}' --session-id "$TEST2_ID" -p "test" >/dev/null

# Check results in specific transcripts  
PROJECT_DIR="$HOME/.claude/projects/$(pwd | sed 's|/|-|g' | sed 's|\.|-|g')"
TEST1_FILE="$PROJECT_DIR/$TEST1_ID.jsonl"
TEST2_FILE="$PROJECT_DIR/$TEST2_ID.jsonl"

if grep -q "DEFAULT_HOOK_OUTPUT" "$TEST1_FILE" && grep -q "OVERRIDE_HOOK_OUTPUT" "$TEST2_FILE" && grep -q "DEFAULT_HOOK_OUTPUT" "$TEST2_FILE"; then
  echo "🐛 BUG: Both hooks ran in test 2. --settings did not override properly."
elif grep -q "DEFAULT_HOOK_OUTPUT" "$TEST1_FILE" && grep -q "OVERRIDE_HOOK_OUTPUT" "$TEST2_FILE" && ! grep -q "DEFAULT_HOOK_OUTPUT" "$TEST2_FILE"; then
  echo "✅ OK: --settings override worked correctly."
else
  echo "❓ Unexpected results. Check transcripts manually:"
  echo "  Test 1: $TEST1_FILE"
  echo "  Test 2: $TEST2_FILE"
fi

echo "Test complete"

Expected Behavior

  • Test 1 should show only DEFAULT_HOOK_OUTPUT in the session transcript
  • Test 2 should show only OVERRIDE_HOOK_OUTPUT in the session transcript (the --settings should completely replace the hook configuration)

Actual Behavior

  • Test 1 shows DEFAULT_HOOK_OUTPUT (correct)
  • Test 2 shows BOTH DEFAULT_HOOK_OUTPUT AND OVERRIDE_HOOK_OUTPUT (incorrect - both hooks run instead of override replacing the original)

Additional Context

This suggests that --settings is merging with or adding to the existing configuration rather than completely overriding it. The expected behavior would be for --settings to completely replace the hook configuration, not supplement it.

View original on GitHub ↗

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