Hooks in Skills, Plugins, and Managed Settings
- Embed hooks in skill frontmatter to activate them only when the skill is in use
- Bundle hooks in a plugin hooks.json file for automatic team-wide distribution
- Apply managed settings to enforce organization-wide hook policies that users cannot override
Hooks Beyond Personal Settings
The settings.json files covered in earlier lessons are the primary place to configure hooks. But they are not the only place. Hooks can be embedded in skill definitions, bundled in plugin packages, and enforced via managed organizational settings.
Each mechanism solves a different distribution problem. Skill hooks activate contextually — only when the skill is in use. Plugin hooks ship with a capability package — developers who install the plugin get the hooks automatically. Managed hooks are policy tools — they apply to everyone in the organization and cannot be disabled.
Understanding all three mechanisms lets you choose the right distribution strategy for each hook rather than putting everything in user or project settings.
Skill Frontmatter Hooks
Skills in Claude Code are defined with a YAML frontmatter block that can include a hooks key. Hooks defined in skill frontmatter activate only while the skill is active and deactivate automatically when the skill completes. They do not appear in the global hook configuration and do not affect any session where the skill is not in use.
The skill frontmatter hook format uses the same event, matcher, and handler structure as settings.json hooks:
---
name: secure-deploy
description: Deploy to production with safety checks
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: ${CLAUDE_PLUGIN_ROOT}/hooks/deploy-guard.sh
Stop:
- matcher: ""
hooks:
- type: command
command: ${CLAUDE_PLUGIN_ROOT}/hooks/deploy-notify.sh
---
The once: true field on a handler causes it to run once per session and then remove itself from the active hooks. Use this for initialization tasks that the skill triggers exactly once at startup — loading credentials, verifying prerequisites, sending a session-start notification — without running on every subsequent event.
Skill hooks are scoped to the skill's context. They can use ${CLAUDE_PLUGIN_ROOT} to reference files that ship with the skill's plugin, enabling self-contained skill packages where the hooks, scripts, and configuration all travel together.
Plugin hooks.json
Plugins can bundle hooks in a hooks/hooks.json file within the plugin package. When a user enables the plugin, these hooks activate automatically alongside the plugin's other capabilities — no manual settings.json editing required.
The hooks.json format is the same object structure as the hooks key in settings.json. Plugin hooks can reference files within the plugin using the ${CLAUDE_PLUGIN_ROOT} path placeholder, and persistent data using ${CLAUDE_PLUGIN_DATA}.
Plugin-scoped MCP servers use a compound naming convention in matchers. A tool named query on the database server in the my-analytics plugin is addressed as mcp__plugin_my-analytics_database__query. This allows plugin hooks to precisely target their own MCP tools without conflicting with hooks from other plugins or user configuration.
The benefit of plugin hooks over project hooks is portability across projects. A security-scanning plugin with bundled PreToolUse hooks applies its security rules to every project where the plugin is enabled, without requiring each project to copy hook configuration into its own settings.json.
Managed Settings and Organizational Enforcement
Managed settings are the highest-priority configuration layer in Claude Code. They are deployed by organizations through MDM (Mobile Device Management) systems, OS-level policy tools, or a managed-settings.json file. Individual developers cannot override them.
Hooks in managed settings apply to every Claude Code session on the managed devices. They are the right mechanism for:
- Compliance requirements that must apply to all developers regardless of their personal configuration
- Audit logging that the organization needs to trust was not bypassed
- Security policies that prevent certain actions across the entire engineering organization
- Notifications to centralized monitoring systems that developers should not be able to disable
The allowManagedHooksOnly setting (available only in managed settings) provides the strongest enforcement option. When set to true, it disables all hooks from user settings, project settings, and plugins — leaving only the managed hooks and hooks from force-enabled plugins active. This ensures that no developer can accidentally or intentionally add hooks that interfere with organizational policy, or remove hooks that enforce it.
Force-enabled plugins (declared in managed settings' enabledPlugins array) are exempt from allowManagedHooksOnly. This allows organizations to distribute security and compliance tooling as plugins while still blocking all other plugin and user hooks.
Hook Source Priority and Override Order
When hooks from multiple sources are active simultaneously, they all run. Managed hooks do not replace project hooks — they supplement them. The priority order governs conflict resolution, not suppression.
The effective hook set for any session is the union of all hooks from all active sources: managed settings, project settings.json, user settings.json, local settings.local.json, active skill frontmatter, and enabled plugin hooks.json files. All matching handlers from all sources run in parallel when an event fires.
The exception is when allowManagedHooksOnly is set. In that case, only managed hooks and force-enabled plugin hooks are active. All other sources are silenced.
The /hooks browser reflects the complete merged hook set, with the source column showing which settings file or plugin contributed each hook. Use it to audit what is actually running in a session when the configuration is complex.
- Skill frontmatter hooks activate only while the skill is active — they do not pollute the global hook configuration and deactivate automatically when the skill completes
- once: true in a skill hook runs the handler exactly once per session then removes it — use this for session initialization tasks that should not repeat on every subsequent event
- Plugin hooks.json bundles hooks with the plugin — developers who enable the plugin get the hooks automatically, with no manual settings.json edits required
- allowManagedHooksOnly blocks all user, project, and plugin hooks except those in managed settings and force-enabled plugins — the strongest enforcement option for organizational compliance
- Hook sources supplement rather than replace each other — the effective hook set is the union of all active sources, with allowManagedHooksOnly as the only mechanism for silencing non-managed hooks