Nightfall Hooks for Claude Code
Step-by-step instructions for deploying Nightfall's Claude Code hooks to corporate-managed employee devices via your MDM.
1. What gets deployed
Nightfall ships a managed-settings drop-in (payloads/nightfall-hooks.json) that registers the nightfall-hook-relay binary against four Claude Code events:
Event
When it fires
Purpose
PreToolUse
Before Claude Code runs a tool (file write, bash, etc.)
Inspect/intercept the action before it happens
PostToolUse
After a tool runs
Capture the result
UserPromptSubmit
When the developer submits a prompt
Inspect prompt content
Stop
When the agent finishes responding
Capture the completed turn
Every event runs the same command — nightfall-hook-relay --source claude_code - with a 15-second timeout. The payload also sets "allowManagedHooksOnly": true, which prevents users from registering their own hooks alongside the managed ones.
{
"hooks": {
"PreToolUse": [ { "hooks": [ { "type": "command", "command": "nightfall-hook-relay --source claude_code", "timeout": 15 } ] } ],
"PostToolUse": [ { "hooks": [ { "type": "command", "command": "nightfall-hook-relay --source claude_code", "timeout": 15 } ] } ],
"UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "nightfall-hook-relay --source claude_code", "timeout": 15 } ] } ],
"Stop": [ { "hooks": [ { "type": "command", "command": "nightfall-hook-relay --source claude_code", "timeout": 15 } ] } ]
},
"allowManagedHooksOnly": true
}2. How the deployment works
Each device needs two things to happen, in order:
Payload staged - the JSON file lands at a fixed staging path, delivered by your MDM's file-distribution / app-deployment feature.
Install script runs - copies the staged payload into Claude Code's
managed-settings.d/drop-in directory and locks the file permissions.Developer relaunches Claude Code - Managed settings are read at startup. Any Claude Code session already running when the file lands will not pick up the hooks until it is fully quit and reopened. Hooks take effect on the next launch — there is no live reload.
The install scripts are idempotent: re-running just re-copies the file, so it's safe to wire them to a recurring trigger.
Staging and target paths
Platform
Staging path (step 1)
Target path (step 2)
macOS
/opt/nightfall/hooks/claude-code/nightfall-hooks.json
/Library/Application Support/ClaudeCode/managed-settings.d/nightfall-hooks.json
Windows
C:\Nightfall\Hooks\claude-code\nightfall-hooks.json
C:\Program Files\ClaudeCode\managed-settings.d\nightfall-hooks.json
The drop-in directory
managed-settings.d/accepts multiple vendor files, so Nightfall'snightfall-hooks.jsoncoexists with anything else already there. The install just adds one file.
3. macOS setup
Step 1 - Stage the payload
Deliver payloads/nightfall-hooks.json to /opt/nightfall/hooks/claude-code/nightfall-hooks.json using your MDM's file-distribution or app-deployment feature (e.g. wrap the JSON in a .pkg, or use Workspace ONE's Files feature).
Step 2 - Run the install script
Wire scripts/macos/install.sh into your MDM as a System-context script. It:
Verifies it's running as root (exits early if not — deploy at System scope).
Confirms the staged payload exists.
Creates
…/ClaudeCode/managed-settings.d/if needed.Copies the payload in, then sets
chmod 644andchown root:wheel.
Drift checking (optional, recommended for Kandji-style audit/remediation MDMs)
scripts/macos/audit.sh compares the deployed file against the staged payload byte-for-byte (cmp -s):
Exit
0> in sync, no action.Exit
1> drift detected, runinstall.shto remediate.
(If the staging file is missing, audit exits 0 to avoid a remediation loop it can't fix.)
4. Windows setup
Step 1 - Stage the payload
Deliver payloads/nightfall-hooks.json to C:\Nightfall\Hooks\claude-code\nightfall-hooks.json using your MDM's file-distribution feature (e.g. an .msi or .intunewin).
Step 2 - Run the install script
Wire scripts/windows/install.ps1 into your MDM as a SYSTEM-context script. It:
Verifies it's running as administrator (exits early if not).
Confirms the staged payload exists.
Creates
C:\Program Files\ClaudeCode\managed-settings.dif needed.Copies the payload in, then locks the ACL with
icacls— full control for
Administrators and SYSTEM, read-only for Users.
Drift checking (Intune Win32 Remediation pattern)
scripts/windows/detect.ps1 compares the deployed file against the staged payload by SHA256:
Prints
present, exit0→ in sync.Prints
staging-missing, exit0→ staging not deployed yet (no remediation loop).Exit
1→ drift, runinstall.ps1as the remediation.
5. Wiring into your MDM
The scripts are MDM-agnostic - the same install script works regardless of vendor. Wire each into the matching MDM feature:
MDM
Platform
Wire into
Script
Rippling
macOS
Custom Script (on enrollment + daily)
scripts/macos/install.sh
Rippling
Windows
PowerShell Script
scripts/windows/install.ps1
Jamf Pro
macOS
Script + Policy (Recurring Check-in + Enrollment)
scripts/macos/install.sh
Kandji
macOS
Custom Script — Audit
scripts/macos/audit.sh
Kandji
macOS
Custom Script — Remediation
scripts/macos/install.sh
Microsoft Intune
Windows
Win32 Remediation - Detection
scripts/windows/detect.ps1
Microsoft Intune
Windows
Win32 Remediation - Remediation
scripts/windows/install.ps1
Workspace ONE
macOS
Script (System context, Periodic + Enrollment)
scripts/macos/install.sh
Workspace ONE
Windows
Script (SYSTEM context, Periodic + Enrollment)
scripts/windows/install.ps1
Two drift strategies:
Re-run on a schedule (Rippling / Jamf / Workspace ONE) - the install script is idempotent, so a periodic trigger simply re-copies and re-locks. Simplest.
Audit/detect → remediate (Kandji / Intune) - pair the audit/detect script with the install script so a re-install only fires when drift is detected.
6. Validation
After deployment, open the Devices page in the Nightfall console. Each device shows a per-client hook status indicator. A healthy status for Claude Code means the hooks are registered and the relay is responding - the deployment is working.
On a single device you can also confirm the file landed at the target path and that nightfall-hook-relay resolves on PATH (the endpoint agent provides it).
Admin-side (on the device):
Developer-side (in a fresh Claude Code session) — this is the missing one:
Run
/hooks. You should see four hooks (PreToolUse, PostToolUse, UserPromptSubmit, Stop), each runningnightfall-hook-relay --source claude_code. If the list is empty, Claude Code has not loaded the managed file — confirm you relaunched after deployment and that your Claude Code version is current (Section X).
7. Rollback
Delete the deployed file; the relay binary stays installed (the Nightfall agent owns its lifecycle):
macOS:
/Library/Application Support/ClaudeCode/managed-settings.d/nightfall-hooks.jsonWindows:
C:\Program Files\ClaudeCode\managed-settings.d\nightfall-hooks.json
If you wired the install to a recurring trigger, remove that MDM assignment first - otherwise the next check-in will re-deploy the file.
8. Troubleshooting
Hooks for Claude Code are not firing? Work through the checks below in order. Each step narrows down where the chain is broken: MDM deployment → file on disk → Claude Code loads it → relay runs → event reaches Nightfall. Most "deployed but not working" cases are resolved at Step 1.
The logic is the same on macOS and Windows; where a command or path differs, both variants are shown.
Step 1 — Did the developer relaunch Claude Code?
Managed settings are read only at startup. A Claude Code session that was already open when the MDM pushed the file keeps running without the hooks — there is no live reload.
Fix: Fully quit and reopen Claude Code, then re-test.
macOS: Quit with Cmd+Q (don't just close the window); confirm no
claudeprocess remains, then relaunch.Windows: Close all Claude Code windows and confirm no
claudeprocess remains in Task Manager, then relaunch.
This is the most common cause. If hooks were deployed while Claude Code was open, this step alone usually fixes it.
Step 2 — Does Claude Code show the hooks as registered?
In a fresh Claude Code session, run:
You should see four hooks — PreToolUse, PostToolUse, UserPromptSubmit, Stop — each running nightfall-hook-relay --source claude_code.
Hooks listed → Claude Code loaded the managed file. Skip to Step 5.
List empty / hooks missing → Claude Code did not load the file. Continue to Step 3.
You can also run /doctor for a built-in settings/installation diagnostic.
Step 3 — Is the managed-settings file on disk and locked down?
Confirm the file exists at the target path with the correct ownership/permissions.
macOS:
Expect: file exists, owner
root, groupwheel, mode644(-rw-r--r--).Windows (PowerShell):
Expect: file exists, ACLs locked to SYSTEM/Administrators (as set by
install.ps1).
If the file is missing: the MDM install step did not complete on this device. Confirm the payload was staged, then re-run the install script at System scope (see the macOS/Windows setup sections). If the file exists but content looks wrong, validate it parses as JSON and matches the deployed payload.
Step 4 — Is Claude Code a supported version?
Managed-settings drop-in directories (managed-settings.d/) and allowManagedHooksOnly require a recent Claude Code build. Pin managed devices to a current release; builds that predate this support will not register managed hooks even when the file is present and correct.
CLI vs. VS Code extension: the Claude Code VS Code extension bundles its own CLI binary, which can be a different version than the standalone
claudeCLI. Verify hooks (Step 2) in whichever surface the developer actually uses, and update the CLI and the extension independently.
After updating, fully relaunch Claude Code (Step 1) and re-check /hooks.
Step 5 — Does the relay run and respond?
Confirm the relay binary is on PATH and returns a valid response.
macOS:
Windows (PowerShell):
Expect output {"continue":true} and a success exit code. If the relay is missing or errors, re-check the deployment; the relay must be installed and on PATH for the hook command to succeed.
Step 6 — Hooks fire, but nothing appears in the Nightfall console?
If /hooks shows the hooks and the relay responds, but the Devices page shows no hook activity, the events are being captured locally but not reaching Nightfall. Check the device's network egress to endpoint.nightfall.ai — TLS, DNS, proxy, or connectivity failures will drop event uploads even though hooks are working correctly. This is a network/connectivity issue, not a hooks issue.
Still stuck?
Collect and send to Nightfall support:
/hooksoutput (screenshot or text)claude --version, and whether the developer uses the CLI or the VS Code extensionThe Step 3 file listing
The Step 5 relay output and exit code
This set pinpoints exactly which link in the chain is broken.
8. Notes & Known Issues
Hooks not active after deployment? The file is loaded only at app launch. A Claude Code instance open since before the MDM push keeps running without the hooks. Fully quit (Cmd+Q / confirm the process is gone) and relaunch.
User-consent dialog. Any managed Claude Code setting that contains hooks triggers a one-time security dialog the user must accept. Plan internal comms before rollout so employees aren't surprised.
Anthropic Windows path migration (March 2026). Claude Code on Windows moved managed-settings to
C:\Program Files\ClaudeCode. The shipped scripts target this new path — pin managed devices to a recent Claude Code version so the path matches.Multi-vendor coexistence. The
managed-settings.d/drop-in directory accepts multiple vendor files. Nightfall'snightfall-hooks.jsoncoexists with anything else there - the install adds a single file and never overwrites others.allowManagedHooksOnly: true. This locks out user-defined hooks. If a team has a legitimate need for their own Claude Code hooks, that's a policy decision to revisit before rollout.Minimum / recommended version. Managed-settings drop-in directories (
managed-settings.d/) andallowManagedHooksOnlyrequire recent changes to Claude Code. Check withclaude --version; pin managed devices to a recent release.CLI vs. VS Code extension. The Claude Code VS Code extension bundles its own CLI binary, which may be a different version than the standalone
claudeCLI. Both should read system managed-settings, but verify hooks in whichever you actually use — running/hooksin that surface. Update the extension and the CLI independently.
Last updated
Was this helpful?