auspex: Claude Code Remote Settings and Managed Hooks (Windows)

Last updated: September 11, 2026

This page documents Claude Code behavior we have reproduced that can stop auspex from capturing Claude Code activity on managed (MDM) installations, along with the workarounds available today. It affects Claude Code only — auspex's capture from Cursor, Codex, GitHub Copilot and VS Code is unaffected.

Remote settings replace managed hooks on Windows

Summary. On Windows, publishing any remote (organization) settings for Claude Code causes the hooks installed in Claude Code's managed settings drop-in to stop firing. On macOS and Linux the same remote settings merge with the drop-in and hooks keep working. The behavior is inconsistent between the platforms.

auspex installs its hooks as a dedicated, auspex-owned file alongside your own managed settings, so it never modifies your configuration:

  • Windows: %ProgramFiles%\ClaudeCode\managed-settings.d\auspex.json
  • macOS: /Library/Application Support/ClaudeCode/managed-settings.d/auspex.json
  • Linux: /etc/claude-code/managed-settings.d/auspex.json

On Windows, once remote settings are published for the organization, the hooks in that file are no longer executed. This happens regardless of what the remote settings contain — an otherwise empty policy is enough to trigger it. The drop-in file is still on disk and still valid; Claude Code simply stops running the hooks it defines.

Symptoms

A device in this state looks healthy in every respect except that no Claude Code activity is ever recorded:

  • Span receives heartbeats from the device, and traces from the device's other tools (Cursor, Codex, Copilot) still arrive — only Claude Code sessions are missing, while the same users are demonstrably using Claude Code.
  • auspex status --verbose reports everything green, including [OK] capture_wiring: all N tools wired. That check verifies the hook entries auspex wrote are present and correct on disk — which they are. It cannot see that Claude Code has decided not to run them.
  • auspex status --json shows "event_counter": 0 (or a count that never moves) under queue, with "depth": 0 and no dead-lettered events. That is the tell: it means no hook has ever fired, rather than hooks having fired and failed to deliver.
  • Restarting the machine does not help, because nothing is broken on the device.

Confirming it

Run this as the signed-in user on an affected device. A managed (.msi) install puts auspex on the machine PATH, so the bare command works; if it does not, use the full path & "C:\Program Files\auspex\bin\auspex.exe".

auspex status --verbose
auspex status --json | ConvertFrom-Json | Select-Object -ExpandProperty queue
Get-Content "$env:USERPROFILE\.claude\remote-settings.json"
Test-Path "$env:ProgramFiles\ClaudeCode\managed-settings.d\auspex.json"

You are seeing this issue if all of the following hold: status --verbose reports no failing checks and capture_wiring passes, the queue's event_counter is 0 after the user has genuinely used Claude Code, the drop-in file exists, and remote-settings.json returns a policy (anything other than the empty {} placeholder).

Workarounds

Either of the following restores Claude Code capture. They can be used independently; pick the one that fits how you manage devices. Workaround 1 is the one we recommend — Workaround 2 is a last resort and carries the caveats set out below.

Workaround 1 — Copy the managed hooks into user settings via MDM (recommended)

Run a script from your MDM that reads the auspex-owned managed drop-in and merges its hooks into the user's own %USERPROFILE%\.claude\settings.json, which is still honored on Windows. The full script is at the end of this section.

The merge is additive and idempotent: existing hooks from other tools are left untouched, auspex hooks that are already present are not duplicated, and stale auspex hooks left over from an earlier version or a previous per-user install are removed. Entries are copied verbatim from the drop-in, so the "shell": "powershell" key, the per-hook "timeout", and the tool matchers auspex writes are all preserved exactly — which matters, because auspex's Windows hook command is a PowerShell call-operator invocation that only behaves correctly with that shell key attached.

Run it on a schedule so the user settings stay in step with the managed drop-in across auspex upgrades: when auspex updates its hook contract, the drop-in changes and the next scheduled run propagates the change automatically. Nothing has to be re-approved, re-published, or hand-edited.

Pros. Targetable at specific users or device groups rather than the whole organization. Windows-only by construction. Raises no approval prompt for users. Tracks auspex's own hook definitions automatically, so it cannot drift out of date. Changes nothing about your Claude Code organization policy.

Cons. It requires MDM setup and ongoing scheduling, and it writes auspex configuration into user-level settings, which is not where a managed installation would normally place it. Users can edit or delete that file themselves, so the script needs to run repeatedly rather than once. It also conflicts with allowManagedHooksOnly — see below.

The script

Download Merge-AuspexHooks.ps1 and run it from your MDM as the signed-in user. It needs no administrator rights, since it only writes inside the user's own profile:

powershell -ExecutionPolicy Bypass -File .\Merge-AuspexHooks.ps1

By default it reads the managed drop-in from %ProgramFiles%\ClaudeCode\managed-settings.d\auspex.json and the user settings from %USERPROFILE%\.claude\settings.json; both can be overridden with -ManagedFile and -SettingsFile. A timestamped .bak copy is written before any change, and the script prints exactly which hooks it added and removed.

To confirm it worked, have the user run Claude Code briefly and then check that the queue counter has moved:

auspex status --json | ConvertFrom-Json | Select-Object -ExpandProperty queue

Workaround 2 — Define the hooks in Claude Code remote settings (last resort)

Because remote settings take precedence, defining auspex's hooks there puts them back in effect. Remote settings are managed at https://claude.ai/admin-settings/claude-code by your Claude organization administrators.

⚠️ Read the caveats before using this. This workaround works, but it takes a copy of auspex's internal wiring and pastes it into a policy that auspex does not own and cannot update, applies it to every Claude Code user in your organization, and interrupts each of them with a security approval dialog. Prefer Workaround 1 unless you genuinely cannot run a script from your MDM.

What it requires

  • A Claude organization administrator, and the willingness to change organization-wide Claude Code policy. This is usually a different team from the one that owns your MDM, and the change is not scoped to the Span rollout.
  • Accepting that every Claude Code user is prompted. Claude Code treats hooks delivered through remote settings as security-sensitive. Each user is shown a "Managed settings require approval" dialog listing the hooks the first time the policy reaches them, and must choose "Yes, I trust these settings" before the hooks take effect. Choosing "No" exits Claude Code — so a user who declines is left unable to work until they re-open and accept. The prompt appears once per organization policy, and publishing a changed policy prompts everyone again. Tell your users to expect it, or they are likely to decline.
  • Organization-wide blast radius. There is no way to scope remote settings to a subset of users or machines. The policy reaches every Claude Code user in the organization — including contractors, users on devices that are not part of your AI trace tracking at all, and users on macOS and Linux where this issue does not exist.
  • Owning a hand-maintained copy of auspex's hook contract, forever. The block below is a snapshot of the ten events auspex captures and the exact command shape it invokes. auspex has no way to update it. When auspex adds an event, changes its command or its matchers, this copy silently goes stale and you lose the affected capture with no error anywhere — and fixing it means editing the policy by hand and re-triggering the approval prompt for every user. Workaround 1 has no equivalent of this, because it reads auspex's own file.
  • Re-checking it when Claude Code is fixed. If a future Claude Code release restores the managed drop-in on Windows, both copies of the hooks fire and every Claude Code event is captured twice, which distorts your trace data. You must remove this block from remote settings at that point; nothing will tell you to.
  • Not touching the shell key. auspex's own Windows drop-in sets "shell": "powershell", but this block must not — a single policy reaches macOS and Linux devices too, which have no PowerShell interpreter and would report a hook failure on every event. The commands below are therefore written for the POSIX shell Claude Code uses by default (Git Bash on Windows), referencing the machine-wide binary through its Git Bash path.
  • A managed (.msi) auspex install on the device. The commands bind auspex's fixed machine-wide install path, C:\Program Files\auspex\bin\auspex.exe. A user who self-installed auspex has the binary under %USERPROFILE%\.auspex\bin instead, and this workaround will silently do nothing for them. (Self-installs are not affected by this issue in the first place — they wire the user-tier hooks, not the managed drop-in.)

The hooks block

Add the hooks block below to your existing Claude Code remote settings, keeping the rest of your policy unchanged.

Every command resolves the auspex binary at its fixed managed location and runs it only if it is actually present, falling through to true otherwise. On devices where auspex is not installed at that path — and on macOS and Linux, where the path does not exist at all — the hook does nothing, raises no error, and exits successfully. That is what makes it safe to publish to a mixed fleet.

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code SessionStart || true"
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code UserPromptSubmit || true"
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code SessionEnd || true"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code PreToolUse || true"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code PostToolUse || true"
          }
        ]
      }
    ],
    "PostToolUseFailure": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code PostToolUseFailure || true"
          }
        ]
      }
    ],
    "SubagentStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code SubagentStart || true"
          }
        ]
      }
    ],
    "SubagentStop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code SubagentStop || true"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code Stop || true"
          }
        ]
      }
    ],
    "PreCompact": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "P=\"/c/Program Files/auspex/bin/auspex.exe\"; [ -x \"$P\" ] && \"$P\" hooks capture claude-code PreCompact || true"
          }
        ]
      }
    ]
  }
}

Pros. No per-device setup, applies immediately and everywhere, and nothing is written into user profiles.

Cons. Everything under What it requires above — in particular the approval prompt for every user, the organization-wide scope with no way to narrow it, and the hand-maintained copy of auspex's hook contract that will drift.

Settings that can conflict with auspex's hooks

The settings below are unrelated to the Windows issue above, but each one can stop auspex's hooks from running. If Claude Code traces stop arriving after a policy change, check these first.

disableAllHooks

Disables all hooks and status line execution, auspex's included. When set to true in managed settings, users and projects cannot override it. There is no exemption for managed or vendor hooks — if this is on, auspex captures nothing from Claude Code.

allowManagedHooksOnly

Managed settings only. Prevents user, project, and plugin hooks from loading; only managed and SDK hooks run.

This does not affect a standard auspex installation. auspex installs its hooks into Claude Code's managed settings drop-in (managed-settings.d/auspex.json), so they count as managed hooks and continue to run normally with this setting enabled.

It does, however, break Workaround 1 above, which works by copying those hooks into the user's own settings.json — user-level hooks are exactly what this setting blocks. If you rely on that workaround, leave allowManagedHooksOnly unset. It also breaks a self-install of auspex, which wires the user tier by design.

strictPluginOnlyCustomization

Managed settings. Blocks non-plugin customization sources for the surfaces you list. If the value is true, or an array containing "hooks", only plugin-provided hooks are allowed and auspex's hooks will not run.

Settings that are safe

allowedHttpHookUrls and httpHookAllowedEnvVars apply only to HTTP hooks. auspex installs command hooks, which these settings do not affect — including "allowedHttpHookUrls": [], which blocks all HTTP hooks but leaves auspex working normally.

Related