claude-code - 💡(How to fix) Fix [FEATURE] ~/.claude/hooks.d/ — upgrade-safe drop-in directory for user hook scripts [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#46039Fetched 2026-04-11 06:30:34
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Author
Participants
Timeline (top)
labeled ×2

Root Cause

  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.

Code Example

/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

---

{
    "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
    }]
}
RAW_BUFFERClick to expand / collapse

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.

extent analysis

TL;DR

Introduce a reserved, upgrade-safe directory ~/.claude/hooks.d/ for user hook descriptors to provide a stable foundation for extending Claude Code via hooks.

Guidance

  • Implement the proposed hooks.d/ directory structure with the specified search path to provide a standardized location for user-supplied hook descriptors.
  • Define a JSON descriptor format for hooks, including metadata and command specifications, to facilitate easy registration and management of hooks.
  • Enforce permission checks to ensure that descriptors and commands are owned by the running user and not world-writable, with logging and skipping of non-compliant hooks.
  • Ensure backward compatibility by making the new hooks.d/ system fully additive, leaving existing settings.json hooks unchanged.

Example

A sample JSON descriptor for a hook might look like this:

{
    "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": "/path/to/claude-settings-cleanup.sh",
        "timeout": 30
    }]
}

Notes

The proposed solution builds upon established Unix conventions for extensibility, such as the .d/ directory pattern, to provide a reliable and upgrade-safe mechanism for user-supplied hooks.

Recommendation

Apply the proposed hooks.d/ workaround to provide a stable foundation for user-supplied hooks, as it offers a well-structured and backward-compatible solution to the current instability and management issues with hooks in Claude Code.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING