[FEATURE] ~/.claude/hooks.d/ — upgrade-safe drop-in directory for user hook scripts
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.jsonwith 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
- I maintain three hook scripts: security cleanup (clears credentials from
permissions.allowon 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). - Currently I manually register all three in
~/.claude/settings.jsonwith hardcoded/Users/mark/...paths that break on my second machine. - With
hooks.d/, I drop three JSON descriptors into~/.claude/hooks.d/, my dotfiles repo syncs them across machines, and aninstall.shwrites the machine-specific absolute paths once. Nosettings.jsonsurgery needed. - 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.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗