Plugin framework deletes external hooks/hooks.json from working tree

Resolved 💬 4 comments Opened Apr 8, 2026 by github-gregory-rome Closed May 22, 2026

Bug description

When a plugin uses an external hooks/hooks.json file (the default location per plugin docs), Claude Code deletes the file and its parent directory from the working tree after loading it. This causes a persistent unstaged deletion in git status.

Reproduction steps

  1. Create a plugin with .claude-plugin/plugin.json and a hooks/hooks.json file:
my-plugin/
├── .claude-plugin/
│   └── plugin.json
├── hooks/
│   └── hooks.json    ← gets deleted
└── scripts/
    └── my-hook.sh
  1. Start a Claude Code session in the plugin directory (or use --plugin-dir)
  2. Observe that hooks/hooks.json (and the entire hooks/ directory) is deleted from disk within seconds

Observed behavior

  • The hooks/ directory and all its contents are deleted from the working tree
  • This includes untracked files placed in hooks/ (not just hooks.json)
  • git status shows deleted: hooks/hooks.json
  • Restoring the file via git checkout HEAD -- hooks/hooks.json triggers another deletion within seconds
  • The deletion also occurs when plugin.json explicitly declares "hooks": "./hooks/hooks.json"
  • The deletion also occurs when pointing to a different path like "hooks": "./config/hooks.json" — the file at the resolved path is deleted
  • Files in directories not targeted by the hooks field are unaffected (confirmed by control test)

Expected behavior

External hook files should remain on disk after being loaded, especially for local development plugins. The framework should read the file without deleting it.

Workaround

Inline the hooks configuration directly in plugin.json using the object form:

{
  "name": "my-plugin",
  "hooks": {
    "hooks": {
      "SessionStart": [
        {
          "hooks": [
            {
              "type": "command",
              "command": "${CLAUDE_PLUGIN_ROOT}/scripts/my-hook.sh"
            }
          ]
        }
      ]
    }
  }
}

Environment

  • Claude Code: latest (2026-04-08)
  • macOS Darwin 25.4.0
  • Plugin loaded via local working directory (.claude-plugin/plugin.json present in CWD)

Hypothesis

The plugin framework appears to apply a cache-and-cleanup pattern (designed for marketplace plugins copied to ~/.claude/plugins/cache/) to local development plugins as well, removing the source hook file after reading it into the hook registry.

View original on GitHub ↗

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