[FEATURE] ~/.claude/hooks.d/ — upgrade-safe drop-in directory for user hook scripts

Resolved 💬 2 comments Opened Apr 10, 2026 by menkhus Closed May 22, 2026

Problem Statement

Claude Code's hook system has no safe, upgrade-proof home for user-supplied scripts. Users must invent their own paths (~/.claude/scripts/, ~/.claude/user_hook_scripts/, etc.) that Claude Code does not document, reserve, or protect. These paths can be overwritten or disappear on any upgrade. There is no discovery mechanism — every hook must be manually registered in settings.json. There is no permission enforcement and no identity logging for user-supplied hooks.

Users doing exactly the right thing — extending Claude Code via hooks for security cleanup, session auditing, and prompt grounding — are doing so on an unstable foundation that breaks silently across upgrades and machines.

Proposed Solution

Introduce ~/.claude/hooks.d/ as a reserved, upgrade-safe drop-in directory for user hook descriptors, following the standard Unix .d/ convention (cron.d/, sudoers.d/, systemd drop-ins). Claude Code searches this directory at startup, loads JSON descriptors it finds there, and merges them with hooks registered in settings.json.

The upgrade contract: Claude Code explicitly guarantees it never creates, modifies, or deletes files in ~/.claude/hooks.d/. This is the missing primitive.

Search path (lowest to highest priority):

/etc/claude/hooks.d/         # system-managed, enterprise policy
~/.claude/hooks.d/           # user-global, roaming, dotfiles-managed
.claude/hooks.d/             # project-level, git-tracked
.claude/hooks.d/local/       # project-local, gitignored

Descriptor format (self-identifying, JSON):

{
    "name": "security-cleanup",
    "version": "1.0.0",
    "description": "Clear permissions.allow on session exit",
    "author": "Mark Menkhus",
    "source": "https://github.com/menkhus/claude_code_management_scripts",
    "hooks": [{
        "event": "Stop",
        "command": "/Users/mark/.claude/user_scripts/claude-settings-cleanup.sh",
        "timeout": 30
    }]
}

Permission enforcement (cron/sudo model): descriptor and command must be owned by the running user, not world-writable. Violations logged with a fix: line, hook skipped, session continues.

Backward compatibility: fully additive. Existing settings.json hooks are unchanged.

Alternative Solutions

Currently users work around this by:

  • Inventing their own paths with no stability guarantee
  • Manually registering each hook in settings.json with hardcoded absolute paths
  • Re-wiring everything on each new machine by hand

The existing plugin system (~/.claude/plugins/*/hooks/hooks.json) is close but heavyweight — requires full plugin structure for what should be a simple script drop.

Priority

High — significant impact on productivity and security for long-term Claude Code users managing multiple machines and projects.

Feature Category

Configuration and settings

Use Case Example

  1. I maintain three hook scripts: security cleanup (clears credentials from permissions.allow on exit), startup audit (warns on high token context load), and an autogrounding hook (queries a local knowledge DB and writes session context for the next session).
  2. Currently I manually register all three in ~/.claude/settings.json with hardcoded /Users/mark/... paths that break on my second machine.
  3. With hooks.d/, I drop three JSON descriptors into ~/.claude/hooks.d/, my dotfiles repo syncs them across machines, and an install.sh writes the machine-specific absolute paths once. No settings.json surgery needed.
  4. On upgrade, my hooks survive untouched because hooks.d/ is explicitly not Claude Code's namespace.

Additional Context

Full design document with requirements, security model, load algorithm, permission enforcement, backward compatibility proof, and 13 required tests:
https://github.com/menkhus/claude_code_management_scripts/blob/main/docs/USER_HOOKS_EXTENSIBILITY_DESIGN.md

Reference implementation (working hooks demonstrating the pattern):
https://github.com/menkhus/claude_code_management_scripts/tree/main/hooks

This pattern is 40 years old and correct. Every serious extensible Unix tool uses it. Claude Code's hook system is one of its strongest features — it deserves a foundation users can rely on.

Submitted by Mark Menkhus and Claude Sonnet 4.6 (Anthropic), April 2026.

View original on GitHub ↗

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