Skip to main content
Use this page when decommissioning AI Watch from a fleet, rolling back a test deployment, or cleaning up legacy script-based installs. If you are only migrating from the old script-based macOS Detect rollout to the package, use Legacy macOS Detect Cleanup.

Removal order

  1. Disable Enforce and Sessions while AI Watch is still installed.
  2. Let AI Watch reconcile to Detect-only mode so it removes Runlayer hook entries and preserves third-party hooks.
  3. Verify hook configs are absent.
  4. Remove the package, profiles, remediation scripts, and local agent artifacts.
  5. Restart AI clients so they stop reading any cached hook configuration.
Do not remove the package first if Enforce or Sessions installed hooks. The packaged aiwatch binary is what removes Runlayer hook entries safely when both capabilities are disabled.
pkgutil --forget is not an uninstaller. It only forgets the macOS installer receipt after files have been removed.

macOS

Phase 1 - Disable hooks

Re-push the AI Watch tenant configuration profile with both hook capabilities disabled:
<key>Enforcement</key>
<false/>
<key>Sessions</key>
<false/>
Keep the AI Watch .pkg and tenant configuration profile assigned until hook reconciliation finishes. The bootstrap LaunchDaemon runs aiwatch setup hooks install --mdm on its normal schedule and removes Runlayer hook entries when Enforcement and Sessions are both false. To force reconciliation immediately, push this one-time script as root:
#!/bin/bash
set -euo pipefail

/usr/local/bin/aiwatch setup hooks install --mdm
/usr/local/bin/aiwatch setup hooks check --mdm
check should exit 0 once the device is compliant with Detect-only hook state. When only Detect is enabled, stale Runlayer hooks are treated as drift so your MDM can remediate them.

Phase 2 - Remove the package

After hook reconciliation passes, unscope the device from the AI Watch .pkg assignment and the three AI Watch profiles:
  • Tenant configuration profile: com.runlayer.aiwatch
  • PPPC / Full Disk Access profile: com.runlayer.aiwatch.pppc
  • Login Items profile: com.runlayer.aiwatch.loginitems
Then push this one-time package cleanup script as root:
#!/bin/bash
set -euo pipefail

CONSOLE_UID=$(stat -f %u /dev/console 2>/dev/null || echo "")

# Unload bundled LaunchAgents from the console user's GUI domain.
if [ -n "$CONSOLE_UID" ] && [ "$CONSOLE_UID" != "0" ]; then
    launchctl bootout "gui/${CONSOLE_UID}/com.runlayer.aiwatch" 2>/dev/null || true
    launchctl bootout "gui/${CONSOLE_UID}/com.runlayer.aiwatch.enroll" 2>/dev/null || true
fi

# Unload the hook bootstrap LaunchDaemon.
launchctl bootout "system/com.runlayer.aiwatch.bootstrap" 2>/dev/null || true

# Remove package-owned files and local state.
rm -f /usr/local/bin/aiwatch
rm -rf /usr/local/lib/runlayer/aiwatch
rm -f /Library/LaunchAgents/com.runlayer.aiwatch.plist
rm -f /Library/LaunchAgents/com.runlayer.aiwatch.enroll.plist
rm -f /Library/LaunchDaemons/com.runlayer.aiwatch.bootstrap.plist
rm -rf /var/db/com.runlayer.aiwatch

# Forget the installer receipt after files are removed.
pkgutil --forget com.runlayer.aiwatch 2>/dev/null || true

# Clear cached consent decisions for the package binary identifier.
tccutil reset All com.runlayer.aiwatch 2>/dev/null || true

echo "AI Watch package cleanup complete."
exit 0

Windows

Phase 1 - Disable hooks

Set both registry-backed capability values to 0 while the AI Watch app and assert/ remediation are still assigned:
New-Item -Path "HKLM:\Software\Runlayer\AIWatch" -Force | Out-Null
New-ItemProperty -Path "HKLM:\Software\Runlayer\AIWatch" -Name "Enforcement" -Value 0 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path "HKLM:\Software\Runlayer\AIWatch" -Name "Sessions" -Value 0 -PropertyType DWord -Force | Out-Null
You can push those values with an Intune remediation, or redeploy the app configuration with AIWATCH_ENFORCEMENT=0 AIWATCH_SESSIONS=0. Keep the assert/ remediation assigned for at least one remediation cycle. Its detect.ps1 runs aiwatch.exe setup hooks check --mdm; Detect-only stale hooks report drift, so remediate.ps1 runs aiwatch.exe setup hooks install --mdm and removes Runlayer hook entries. To force reconciliation on a device, run as SYSTEM:
& "C:\Program Files\Runlayer\AIWatch\aiwatch.exe" setup hooks install --mdm
& "C:\Program Files\Runlayer\AIWatch\aiwatch.exe" setup hooks check --mdm
check should exit 0 once the device is compliant with Detect-only hook state. Stale Runlayer hook entries cause a non-zero exit until reconciliation removes them.

Phase 2 - Remove the package

In Intune:
  1. Remove or unassign the AI Watch app.
  2. Remove or unassign the Detect remediation pair (scan-on-detect/ or scheduled/).
  3. Remove or unassign the hook assertion remediation pair (assert/).
  4. Restart AI clients on affected devices.
Use the app uninstall command:
msiexec /x aiwatch-<version>-win-x64.msi /qn
The MSI removes C:\Program Files\Runlayer\AIWatch\ and the managed registry values under HKLM\Software\Runlayer\AIWatch. Intune remediation assignments are not MSI-owned, so remove those separately in Intune.

Legacy script-based installs

For macOS fleets that used the original script-based Detect rollout, follow Legacy macOS Detect Cleanup. That page removes the old runlayer-scan wrapper, per-user LaunchAgent, old PPPC profile, and script logs while preserving unrelated user CLI state. For custom Windows script or Scheduled Task deployments, remove the MDM script or task assignment, then remove any custom task, script, or log paths your deployment created. Package-based AI Watch does not use %ProgramData%\Runlayer\ai_watch_detect.log; current Windows package execution is driven by the installed aiwatch.exe and Intune Remediations.

Verification

macOS

Before package cleanup, verify Phase 1 hook reconciliation. This proves AI Watch is in the desired Detect-only hook state; it does not prove the package has been removed.
if /usr/local/bin/aiwatch setup hooks check --mdm; then
    echo "PASS: AI Watch hook state compliant for Detect-only cleanup phase"
else
    echo "FAIL: hook config drift remains; keep AI Watch installed and rerun reconciliation" >&2
    exit 1
fi
After package cleanup:
#!/bin/bash
set -euo pipefail

missing_path() {
    local path="$1"
    if [ -e "$path" ]; then
        echo "FAIL: expected removed path still exists: $path" >&2
        exit 1
    fi
    echo "PASS: removed $path"
}

missing_path /usr/local/bin/aiwatch
missing_path /usr/local/lib/runlayer/aiwatch
missing_path /Library/LaunchAgents/com.runlayer.aiwatch.plist
missing_path /Library/LaunchAgents/com.runlayer.aiwatch.enroll.plist
missing_path /Library/LaunchDaemons/com.runlayer.aiwatch.bootstrap.plist

if launchctl print system/com.runlayer.aiwatch.bootstrap >/dev/null 2>&1; then
    echo "FAIL: bootstrap daemon is still loaded" >&2
    exit 1
fi
echo "PASS: bootstrap daemon unloaded"

if pkgutil --pkg-info com.runlayer.aiwatch >/dev/null 2>&1; then
    echo "FAIL: package receipt still present" >&2
    exit 1
fi
echo "PASS: package receipt forgotten"

Windows

Before package removal, verify Phase 1 hook reconciliation. This proves AI Watch is in the desired Detect-only hook state; it does not prove the package has been removed.
& "C:\Program Files\Runlayer\AIWatch\aiwatch.exe" setup hooks check --mdm
if ($LASTEXITCODE -ne 0) {
  throw "Hook config drift remains; keep AI Watch installed and rerun reconciliation."
}
Write-Output "PASS: AI Watch hook state compliant for Detect-only cleanup phase"
After package removal:
$binaryPath = "C:\Program Files\Runlayer\AIWatch\aiwatch.exe"
if (Test-Path $binaryPath) {
  throw "AI Watch binary still exists at $binaryPath"
}
Write-Output "PASS: AI Watch binary removed"

$registryPath = "HKLM:\Software\Runlayer\AIWatch"
$managedValues = Get-ItemProperty -Path $registryPath `
  -Name "Host","OrgApiKey","Enforcement","Sessions" `
  -ErrorAction SilentlyContinue

if ($null -ne $managedValues) {
  throw "Managed AI Watch registry values still exist at $registryPath"
}
Write-Output "PASS: managed AI Watch registry values removed"