> For the complete documentation index, see [llms.txt](https://help.nightfall.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.nightfall.ai/data-exfiltration-prevention/ai-agent-security/ai-governance/auditability-and-control/setup-and-installation/nightfall-hooks-for-claude-code.md).

# Nightfall Hooks for Claude Code

Step-by-step instructions for deploying Nightfall's Claude Code hooks to corporate-managed employee devices via your MDM.&#x20;

***

### 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:

1. **Payload staged** - the JSON file lands at a fixed staging path, delivered by your MDM's file-distribution / app-deployment feature.
2. **Install script runs** - copies the staged payload into Claude Code's `managed-settings.d/` drop-in directory and locks the file permissions.
3. **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  | <p>`C:\Nightfall\Hooks\claude-code</p><p>ightfall-hooks.json`</p> | <p>`C:\Program Files\ClaudeCode\managed-settings.d</p><p>ightfall-hooks.json`</p> |

> The drop-in directory `managed-settings.d/` accepts multiple vendor files, so Nightfall's\
> `nightfall-hooks.json` coexists 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:

1. Verifies it's running as root (exits early if not — deploy at System scope).
2. Confirms the staged payload exists.
3. Creates `…/ClaudeCode/managed-settings.d/` if needed.
4. Copies the payload in, then sets `chmod 644` and `chown root:wheel`.

```
sudo ./scripts/macos/install.sh
```

#### 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, run `install.sh` to 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:

1. Verifies it's running as administrator (exits early if not).
2. Confirms the staged payload exists.
3. Creates `C:\Program Files\ClaudeCode\managed-settings.d` if needed.
4. Copies the payload in, then locks the ACL with `icacls` — full control for

Administrators and SYSTEM, read-only for Users.

```
powershell -ExecutionPolicy Bypass -File .\scripts\windows\install.ps1

```

#### Drift checking (Intune Win32 Remediation pattern)

`scripts/windows/detect.ps1` compares the deployed file against the staged payload by **SHA256**:

* Prints `present`, exit `0` → in sync.
* Prints `staging-missing`, exit `0` → staging not deployed yet (no remediation loop).
* Exit `1` → drift, run `install.ps1` as 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):**

  <pre data-overflow="wrap"><code>ls -l "/Library/Application Support/ClaudeCode/managed-settings.d/nightfall-hooks.json"   # exists, root:wheel, 644which nightfall-hook-relay
  </code></pre>
* **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 running `nightfall-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.json`
* **Windows:** `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 `claude` process remains, then relaunch.
* **Windows:** Close all Claude Code windows and confirm no `claude` process 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:

{% code overflow="wrap" %}

```
/hooks
```

{% endcode %}

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:**

  <pre data-overflow="wrap"><code>ls -l "/Library/Application Support/ClaudeCode/managed-settings.d/nightfall-hooks.json"
  </code></pre>

  Expect: file exists, owner `root`, group `wheel`, mode `644` (`-rw-r--r--`).
* **Windows (PowerShell):**

  <pre data-overflow="wrap"><code>Get-Acl "C:\Program Files\ClaudeCode\managed-settings.d\nightfall-hooks.json" | Format-List
  </code></pre>

  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?

{% code overflow="wrap" %}

```
claude --version
```

{% endcode %}

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 `claude` CLI. 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:**

  <pre data-overflow="wrap"><code>which nightfall-hook-relayecho '{}' | nightfall-hook-relay --source claude_code
  </code></pre>
* **Windows (PowerShell):**

  <pre data-overflow="wrap"><code>Get-Command nightfall-hook-relay'{}' | nightfall-hook-relay --source claude_code
  </code></pre>

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:

* `/hooks` output (screenshot or text)
* `claude --version`, and whether the developer uses the CLI or the VS Code extension
* The 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's `nightfall-hooks.json` coexists 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/`) and `allowManagedHooksOnly` require recent changes to Claude Code. Check with `claude --version`; pin managed devices to a recent release.&#x20;
* **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 `claude` CLI. Both should read system managed-settings, but verify hooks in **whichever you actually use** — running `/hooks` in that surface. Update the extension and the CLI independently.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.nightfall.ai/data-exfiltration-prevention/ai-agent-security/ai-governance/auditability-and-control/setup-and-installation/nightfall-hooks-for-claude-code.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
