> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runlayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JumpCloud (macOS + Windows)

> Deploy AI Watch to macOS and Windows via JumpCloud using the signed `.pkg` / `.msi` and JumpCloud Private Repo. Detect, endpoint modes, and Sessions ship in one package per OS.

export const overviewTrailer_0 = <>JumpCloud has no profile parameterization — upload the pre-filled <code>.mobileconfig</code> from the wizard (<strong>Settings → MDM configuration</strong>), or find-and-replace the template.</>

export const adminAccess_0 = "JumpCloud admin access with the target Macs enrolled in JumpCloud MDM and at least one Device Group for the rollout."

export const artifactsIntro_0 = undefined

export const tenantConfigFile_0 = undefined

export const tenantConfigPurpose_0 = undefined

JumpCloud deploys AI Watch to both operating systems from the same Runlayer configuration. Create one deployment in **Settings → MDM configuration → New deployment → JumpCloud**, then use the **macOS** and **Windows** tabs of the wizard for the OS-specific artifacts. Start in **Monitor** for the canary; enable Sessions, Protect, or Enforce from Runlayer once devices check in.

| Platform | JumpCloud objects                                                                             | Do not use                                                                                    |
| -------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| macOS    | One **MDM Custom Configuration Profile** policy + one **JumpCloud Private Repo** app (`.pkg`) | Separate hand-built PPPC / Login Items profiles                                               |
| Windows  | One **JumpCloud Private Repo** app (signed `.msi`)                                            | Custom MDM (OMA-URI) policies, the Intune `.intunewin` bundle, or the Intune detection script |

<Warning>
  Copy the organization API key when the wizard shows it — it is displayed once. If it was not saved, do not substitute another key: delete the unused deployment, create a new one, and update the JumpCloud profile/app with the new values.
</Warning>

## macOS

<Note>
  Migrating from the legacy script-based Detect rollout? Run [Legacy macOS Detect Cleanup](/shadow-ai/deploy/macos-cleanup-script-deployment) before rolling out the `.pkg` so the old `runlayer-scan` artifacts don't conflict with `com.runlayer.aiwatch`.
</Note>

## Overview

A signed, notarized `aiwatch` binary installs once per device via `.pkg`. Tenant config — the host and a single **organization API key** — is pushed via an MDM Configuration Profile; everything else (mode, Sessions, optional discovery, scan tuning) is managed in Runlayer settings and fetched by the device. {overviewTrailer_0}

## Capabilities

All behaviors ship in the **same** `.pkg` and a **single** deployment profile that combines the tenant config, PPPC / Full Disk Access, and Login Items payloads. The tenant-config payload supplies just the host and organization API key. Devices refresh behavior — **Monitor / Protect / Enforce** mode, **Collect session data**, optional discovery, and **Advanced scan settings** — from **Settings → AI Watch → Manage settings** during the 15-minute hook reconcile; no profile edit or re-push. AI Watch `0.29.6` or newer can also install or remove the managed Chrome and Firefox extensions from the **Browser extension** tab there.

If you need multiple tenant configurations (different host or key), deploy one copy of the profile per group (the PPPC and Login Items payloads it carries are identical across copies; only the tenant-config values differ).

Project and client-config detection is always enabled after AI Watch is installed. Before the first successful settings sync, the endpoint starts in Monitor with Sessions and optional runtime discovery disabled, so no hooks are installed. One organization API key authenticates AI Watch scans, hooks, session events, and managed updates; no enrollment keys are required.

| Capability                               | Configuration                                    | What it does                                                                                                                                                                                                                                                                                             |
| ---------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Detect**                               | Always on                                        | Discovers AI clients, shadow MCP servers, skills, and plugins from project and client configuration files                                                                                                                                                                                                |
| **Running processes**                    | `DetectProcesses` / `AIWATCH_DETECT_PROCESSES`   | Discovers AI tooling and configured MCP servers from running processes and listening sockets                                                                                                                                                                                                             |
| **Containers and WSL**                   | `DetectContainers` / `AIWATCH_DETECT_CONTAINERS` | Performs read-only MCP config, skill, and agent-definition discovery inside running Docker, Podman, or nerdctl containers through a Docker-CLI-compatible CLI or local Engine API socket; on Linux, also scans k3s through root-only `k3s crictl`; on Windows, also scans bounded WSL home project trees |
| **Monitor**                              | `Mode=monitor` / `AIWATCH_MODE=monitor`          | Reports endpoint hook activity without applying scanner or governance decisions                                                                                                                                                                                                                          |
| **Protect**                              | `Mode=protect` / `AIWATCH_MODE=protect`          | Applies scanner-configured Block and Mask decisions plus fail-open, allow-unless-denied MCP source governance; explicit denylist matches are blocked                                                                                                                                                     |
| **Enforce**                              | `Mode=enforce` / `AIWATCH_MODE=enforce`          | Applies scanner and local policy decisions to non-MCP tools plus fail-closed, deny-by-default MCP source governance; managed MCP calls scan at the gateway                                                                                                                                               |
| **Sessions**                             | `Sessions` / `AIWATCH_SESSIONS`                  | Installs the full event hook set for [Sessions](/platform-sessions) telemetry                                                                                                                                                                                                                            |
| **Track MCP tool usage without content** | `MCPUsageMetadata` (Monitor mode, Sessions off)  | Installs one lightweight MCP pre-call hook per supported client that reports only the client, tool name, MCP server name, and device/user identity — never request arguments, responses, session content, or transcripts                                                                                 |

* **Running-process and container discovery** are disabled until the synced settings enable them.
* **Monitor** is the default mode.
* **Sessions and hooks fail closed before settings sync.** A successful settings sync or an explicit legacy MDM `Sessions=true` / Protect / Enforce setting enables them.
* **Sessions coverage follows the client surface.** Installing the full hook set does not make a client emit events it does not support. Cursor's classic IDE and Agents Window load the endpoint hook config, while Cursor CLI emits a subset. Cursor Cloud Agents require the separate [repository/team hook collector](/shadow-ai/cursor-cloud-agents); it is monitor-only and does not inherit endpoint configuration.

Hooks are installed whenever Mode is Protect/Enforce, Sessions is enabled, or **Track MCP tool usage without content** is enabled; otherwise AI Watch removes stale Runlayer hooks while preserving third-party hooks.

<Note>
  **Legacy fleets only:** on AI Watch builds that predate settings sync, push the native keys manually and pair them — Monitor with `Enforcement=false`, Protect and Enforce with `Enforcement=true`. A valid `Mode` value overrides the legacy `Enforcement` boolean.
</Note>

On macOS and Windows, admins can change Mode, Sessions, process/container discovery, project depth, and project timeout from **Settings → AI Watch → Manage settings**. Devices fetch the complete settings snapshot during the privileged hook reconcile, which runs every 15 minutes, without an MDM policy update. On macOS with AI Watch `0.29.6` or newer, the same settings page can install or remove the managed Chrome and Firefox extensions and configure their mode and Sessions behavior without an MDM profile update. The tenant host, organization API key, and CPU/memory limits remain MDM-owned.

**Advanced scan tuning (optional).** Detect scans walk each user's home directory to a bounded depth within a per-scan time budget, and keep CPU and memory use within configurable caps. The defaults fit most fleets — override them only if scans miss deeply-nested project configs (raise depth), run out of time on very large home directories (raise timeout), or you want a smaller footprint on constrained hosts (lower the CPU / memory caps).

| Setting               | Configuration                               | Default                | Range             |
| --------------------- | ------------------------------------------- | ---------------------- | ----------------- |
| **Project depth**     | `ProjectDepth`                              | `7`                    | `1`–`20`          |
| **Project timeout**   | `ProjectTimeout`                            | `60`s                  | `1`–`300`s        |
| **CPU cores**         | `CpuCores` / `AIWATCH_CPU_CORES`            | half the logical cores | `1`–logical cores |
| **Max CPU percent**   | `MaxCpuPercent` / `AIWATCH_MAX_CPU_PERCENT` | `50`                   | `5`–`100`         |
| **Memory limit (MB)** | `MemoryLimitMb` / `AIWATCH_MEMORY_LIMIT_MB` | `1024`                 | `512`–`8192`      |

All are integers. Project depth and timeout are delivered by the Runlayer settings sync on macOS and Windows; native MDM values remain a legacy fallback. CPU and memory caps remain MDM-owned (`<integer>` on macOS, matching `AIWATCH_*` MSI properties on Windows). Omit them to keep the defaults. Values outside the range are clamped; non-integer or non-positive values are ignored. The CPU / memory caps are best-effort: the scan is throttled to stay within the configured CPU budget and aborts if it exceeds the memory ceiling.

## Prerequisites

* {adminAccess_0}
* Devices running **macOS 14 (Sonoma) or newer**. The packaged binary does not load on macOS 13 or older; for those devices, use the [manual CLI path](/shadow-ai/detect#manual-installation) instead.
* Devices enrolled via **UAMDM** (User-Approved MDM) or **DEP/ADE**. TCC payloads are ignored on manually-enrolled MDM.
* A single **organization API key** with the **Shadow AI Scan** role. Don't create one by hand — the setup wizard in **Settings → MDM configuration** mints it when you create the configuration and pre-fills it into the downloaded profile. Only a wizard-minted key links devices to the configuration card. The same key authenticates scanning, enforcement, sessions, and managed updates.
* Your Runlayer tenant host URL (e.g. `https://your-instance.runlayer.com`).

<Note>
  The macOS package supports Apple Silicon (`arm64`). For Intel Macs or other
  architectures, use the [manual CLI path](/shadow-ai/detect#manual-installation)
  or contact your Runlayer account team.
</Note>

## Artifacts

{artifactsIntro_0 ?? <>Download every artifact directly from the setup wizard in <strong>Settings → MDM configuration</strong> (<strong>Add new</strong>, or <strong>View deployment setup</strong> on an existing configuration):</>}

| File                                                                     | Purpose                                                                                                                                                                                                                                                    |
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `aiwatch-<version>-macos-arm64.pkg`                                      | Signed + notarized installer (single `aiwatch` binary + scan LaunchAgent + hook bootstrap + hourly root update daemon). The wizard serves the version selected by your Client Updates policy                                                               |
| <code>{tenantConfigFile_0 ?? "com.runlayer.aiwatch.mobileconfig"}</code> | {tenantConfigPurpose_0 ?? "Single deployment profile: bootstrap tenant config (host + org API key), Full Disk Access / TCC grants, and macOS 13+ Login Items pre-approval in one file (downloads pre-filled from the wizard, or hand-edit the template)."} |

Automatic updates are always on. The updater installs the version selected by your Client Updates policy; pin a version there to control what devices run.

<Warning>
  **Deploy the Configuration Profile before the `.pkg`.** The profile must land in `/Library/Managed Preferences/` and TCC before the bundled LaunchAgent's first scan tick — otherwise `aiwatch` logs `host not configured` and TCC denies project-config reads until the next MDM sync.
</Warning>

<Note>
  **Migrating from the split profiles?** Earlier releases shipped three separate profiles (`com.runlayer.aiwatch.config.mobileconfig`, `com.runlayer.aiwatch.pppc.mobileconfig`, `com.runlayer.aiwatch.loginitems.mobileconfig`). The merged profile uses a new profile identifier, so it does **not** supersede them automatically — unscope/remove the three legacy profiles when you scope the merged one to avoid duplicate payloads.
</Note>

## Deployment

<Steps>
  <Step title="Get the deployment profile">
    Download `com.runlayer.aiwatch.mobileconfig` pre-filled from the setup wizard's **macOS** tab — it already carries your tenant host and org API key, plus the PPPC / Full Disk Access and Login Items payloads.

    If you hand-edit the template instead, open it in a text editor and replace the two tenant placeholders:

    | Placeholder                | Replace with                              |
    | -------------------------- | ----------------------------------------- |
    | `REPLACE_WITH_TENANT_HOST` | e.g. `https://your-instance.runlayer.com` |
    | `REPLACE_WITH_ORG_API_KEY` | the actual `rl_org_...` secret            |
  </Step>

  <Step title="Upload the Configuration Profile as a policy">
    1. **Device Management → Policy Management → Add New**.
    2. Select **Device Policy → macOS**.
    3. Find **MDM Custom Configuration Profile** and select **Configure**.
    4. Name the policy (for example `Runlayer AI Watch – macOS profile`) and upload `com.runlayer.aiwatch.mobileconfig` under **Settings**.
    5. Assign the target **Device Groups** and save.
    6. On the policy **Status** tab, confirm each Mac returns exit status `0`.

    Deploy this profile before or alongside the package so the first scan already has Full Disk Access. The bundled PPPC + Login Items payloads are pre-pinned to Developer ID team `AF2M8HC7A2` — no edits required.
  </Step>

  <Step title="Upload the .pkg to the Private Repo">
    1. **Device Management → Software Management → Apple**.
    2. **Add New → JumpCloud Private Repo**.
    3. Name the app `Runlayer AI Watch` and upload `aiwatch-<version>-macos-arm64.pkg`. Wait for JumpCloud validation to finish.
    4. Assign the same Device Groups as the profile.
    5. Choose forced installation rather than self-service, then save.
    6. Confirm the app status is successful on the test Mac.

    If Runlayer offers separate packages per architecture, create one app entry per architecture and scope each to the matching Device Group.
  </Step>
</Steps>

After deployment, change Mode, Sessions, optional process/container discovery, project depth, or project timeout from **Settings → AI Watch → Manage settings**; connected devices refresh them on their next hook reconcile, within about 15 minutes. On AI Watch `0.29.6` or newer, open the **Browser extension** tab and turn on **Install browser extension** to install managed Chrome and Firefox without changing or re-deploying the profile. To rotate the API key or change resource limits or identity overrides, edit and re-deploy `com.runlayer.aiwatch.mobileconfig`. No `.pkg` reinstall. Keep each Apple `PayloadVersion` at `1`.

## Verification

On a test Mac after installation and configuration:

```bash theme={null}
# 1. .pkg installed (binary + scan agent + hook daemon agent + bootstrap + updater)?
test -x /usr/local/bin/aiwatch && \
  test -f /Library/LaunchAgents/com.runlayer.aiwatch.plist && \
  test -f /Library/LaunchAgents/com.runlayer.aiwatch.daemon.plist && \
  test -f /Library/LaunchDaemons/com.runlayer.aiwatch.bootstrap.plist && \
  test -f /Library/LaunchDaemons/com.runlayer.aiwatch.update.plist && \
  echo "binary + scan agent + daemon agent + bootstrap + updater OK"

# 2. Signature + notarization?
pkgutil --check-signature /path/to/aiwatch-<version>-macos-arm64.pkg
codesign -dv --verbose=4 /usr/local/lib/runlayer/aiwatch/aiwatch
# Expect: Authority=Developer ID Application: Anysource Inc. (AF2M8HC7A2)
#         Identifier=com.runlayer.aiwatch

# 3. Managed or local Test Device preferences configured (host + org API key)?
defaults read /Library/Managed\ Preferences/com.runlayer.aiwatch.plist 2>/dev/null || true
defaults read /Library/Preferences/com.runlayer.aiwatch.plist 2>/dev/null || true

# 4. Scan agent loaded for the console user?
launchctl print "gui/$(id -u)/com.runlayer.aiwatch"

# 4b. Hook daemon running for the console user?
/usr/local/bin/aiwatch daemon status

# 5. Hourly update daemon loaded in the system domain?
sudo launchctl print system/com.runlayer.aiwatch.update

# 6. Background item registered (macOS 13+)?
sfltool dumpbtm | grep -i runlayer

# 7. Full Disk Access activity visible to TCC?
sudo log show --predicate 'subsystem == "com.apple.TCC"' --last 5m | grep -i aiwatch

# 8. Trigger an immediate scan
/usr/local/bin/aiwatch scan

# 9. (Protect, Enforce, or Sessions) Confirm hooks are installed for the console user
sudo /usr/local/bin/aiwatch setup hooks check --mdm
# Expect: exit 0 (compliant). Exit 1 = hook configs drifted (the next bootstrap tick rewrites them).

# 10. View process activity; update failures also appear as a non-zero
# last exit code in the launchctl output from step 5.
log show --predicate 'process == "aiwatch"' --last 1h
# Tail in real time:
log stream --predicate 'process == "aiwatch"'
```

In the Runlayer dashboard, navigate to **Shadow AI → Devices** and confirm the test Mac appears.

## Common post-deploy issues

<AccordionGroup>
  <Accordion title="Users see 'Background Item Added' after install">
    On a manual test-device install, this one-time macOS 13+ notification is expected because no MDM Login Items profile pre-approves the scan LaunchAgent.

    On a managed deployment, confirm `com.runlayer.aiwatch.mobileconfig` (which carries the Login Items payload) is scoped to the same device group as the `.pkg`, then force an MDM sync and check:

    ```bash theme={null}
    sfltool dumpbtm | grep -i runlayer
    ```

    Expect the Runlayer item to show `enabled allowed visible`.
  </Accordion>

  <Accordion title="Gatekeeper blocks the package">
    Verify you are deploying the official signed and notarized release artifact:

    ```bash theme={null}
    pkgutil --check-signature /path/to/aiwatch-<version>-macos-arm64.pkg
    spctl --assess --type install -vv /path/to/aiwatch-<version>-macos-arm64.pkg
    ```

    Expected: a Developer ID Installer signature for Anysource Inc. and `source=Notarized Developer ID`.
  </Accordion>

  <Accordion title="Full Disk Access is enabled but TCC still denies access">
    For a manual install, confirm `/usr/local/lib/runlayer/aiwatch/aiwatch` is enabled under **System Settings → Privacy & Security → Full Disk Access**. For MDM, the PPPC profile pins Full Disk Access to identifier `com.runlayer.aiwatch` and Developer ID team `AF2M8HC7A2`.

    Confirm the installed binary matches:

    ```bash theme={null}
    codesign -dv --verbose=4 /usr/local/lib/runlayer/aiwatch/aiwatch
    ```

    Expected: `Authority=Developer ID Application: Anysource Inc. (AF2M8HC7A2)` and `Identifier=com.runlayer.aiwatch`. Custom or ad-hoc signed builds will not satisfy the PPPC CodeRequirement.
  </Accordion>
</AccordionGroup>

## Customize scan schedule (optional)

The bundled LaunchAgent ships with a 15-minute `StartInterval`. Most tenants don't need to change it, and the interval is an operational tuning knob, not a security control — Detect coverage comes from the scan itself, not its cadence. On a managed fleet, push the script below via your MDM's recurring-script mechanism (Jamf Policy, Kandji Custom Script, SimpleMDM Script, etc.). On a manual test Mac, run it directly with administrator access:

```bash theme={null}
#!/bin/bash
set -euo pipefail
PLIST=/Library/LaunchAgents/com.runlayer.aiwatch.plist
INTERVAL=1800   # 30 min — edit per tenant
/usr/libexec/PlistBuddy -c "Set :StartInterval ${INTERVAL}" "$PLIST"

CONSOLE_UID=$(stat -f %u /dev/console 2>/dev/null || echo "")
if [ -n "$CONSOLE_UID" ] && [ "$CONSOLE_UID" != "0" ]; then
    launchctl bootout "gui/${CONSOLE_UID}/com.runlayer.aiwatch" 2>/dev/null || true
    launchctl bootstrap "gui/${CONSOLE_UID}" "$PLIST" 2>/dev/null || true
fi
```

<Note>
  The next `.pkg` upgrade resets `StartInterval` to the bundled default — the override script must run on a recurring schedule, or be re-applied after each upgrade.
</Note>

## Upgrade

The root `com.runlayer.aiwatch.update` LaunchDaemon checks hourly and installs the signed + notarized `.pkg` at the version selected by your Runlayer tenant. An MDM Custom App push or another manual `installer` run remains a fallback, but the next hourly tick will restore the selected version. To hold a manually pushed version, pin it in Client Updates first.

Upgrades replace the previous `/usr/local/lib/runlayer/aiwatch/` install cleanly, so obsolete modules and version metadata cannot survive an upgrade or rollback. The separate Runlayer CLI installation is preserved. Mid-scan upgrades are safe — a running scan finishes on the old version, and the next LaunchAgent tick picks up the new one.

MDM Configuration Profiles are unchanged across version upgrades. Preferences written manually under `com.runlayer.aiwatch` also remain in place.

<Warning>
  If you've overridden `StartInterval` via Custom Script, the upgrade resets it to the bundled default. Re-apply the override script on a recurring schedule.
</Warning>

## Uninstall

For full package and hook cleanup guidance, see [Remove AI Watch](/shadow-ai/deploy/remove).

## Troubleshooting

For deployment diagnostics and common macOS package issues, see [Troubleshooting](/shadow-ai/troubleshooting).

## Windows

AI Watch deploys to Windows as a signed MSI installed once per device. The MSI writes only bootstrap credentials to `HKLM\Software\Runlayer\AIWatch` and registers device-local SYSTEM Scheduled Tasks for scans, hook reconciliation, and managed updates. Mode, Sessions, discovery, and scan tuning come from the Runlayer settings sync after the first successful check-in.

### Prerequisites

* JumpCloud admin access with the target devices enrolled and a Windows Device Group for the rollout.
* Devices running Windows 10 1809+ / 11, 64-bit. Windows Home and S mode are not supported.
* The organization API key minted by the wizard (`rl_org_...`).

### Artifact

Download the signed `aiwatch-<version>-win-x64.msi` from the wizard's **Windows** tab. JumpCloud deploys the MSI directly.

<Warning>
  Do **not** upload the Intune `.intunewin` bundle or `detect-install.ps1`, and do **not** create a Windows Custom MDM (OMA-URI) policy. Those are Intune-only mechanisms; JumpCloud's Private Repo runs `msiexec /i` for you.
</Warning>

<Steps>
  <Step title="Create the Windows app">
    1. **Device Management → Software Management → Windows**.
    2. **Add New → JumpCloud Private Repo**.
    3. Name the app `Runlayer AI Watch`, upload the signed MSI, and wait for validation.
  </Step>

  <Step title="Set the Command Line Options">
    Under **Deployment Configurations → Command Line Options**, paste the value rendered by the wizard. JumpCloud already implies `msiexec /i <uploaded MSI>`, so the value contains only switches and MSI properties — no executable and no filename:

    ```text theme={null}
    /qn /norestart AIWATCH_HOST="https://<tenant>.runlayer.com" AIWATCH_ORG_API_KEY="<organization-api-key>"
    ```

    | Property              | Required | Effect                                                                                                 |
    | --------------------- | -------- | ------------------------------------------------------------------------------------------------------ |
    | `AIWATCH_HOST`        | **Yes**  | Tenant host URL                                                                                        |
    | `AIWATCH_ORG_API_KEY` | **Yes**  | The `rl_org_...` secret used for Detect scans, endpoint hooks, Sessions telemetry, and managed updates |

    Only these two properties are required. Mode, Sessions, discovery settings, and scan tuning come from the Runlayer deployment configuration after the first sync; see [Intune (Windows) → Install properties](/shadow-ai/deploy/intune#install-properties) for the optional MDM-owned resource caps and identity overrides the MSI also accepts.
  </Step>

  <Step title="Assign and install">
    1. Assign the Windows Device Group.
    2. Choose forced installation, then save.
    3. Confirm JumpCloud reports the application as installed.

    The MSI runs in system context and registers the scheduled tasks itself. No user administrator rights, working directory, OMA-URI policy, or extra remediation script is required.
  </Step>
</Steps>

### What the MSI creates

All three tasks live in a hidden `\Runlayer` Task Scheduler folder and run as SYSTEM:

| Task            | Purpose                                                                               | Schedule                                           |
| --------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------- |
| `AIWatchScan`   | `aiwatch.exe scan --all-users` — scans every real user profile                        | Boot, any-user logon, every 15 min                 |
| `AIWatchHooks`  | Fetches settings and reconciles supported client hooks (Protect / Enforce / Sessions) | Boot + every 15 min                                |
| `AIWatchUpdate` | Checks the Runlayer Client Updates policy and installs the selected MSI               | First run about an hour after install, then hourly |

The `RunlayerAIWatch` Windows service keeps the hook daemon running per user session. It may sit idle in Monitor with Sessions off; its idleness is not, by itself, an install failure.

### Verification

Run from an elevated 64-bit PowerShell session:

```powershell theme={null}
$exe = "$env:ProgramFiles\Runlayer\AIWatch\aiwatch.exe"
& $exe --version

# Bootstrap Host present and an org key written? (do not print the key itself)
$cfg = Get-ItemProperty "HKLM:\Software\Runlayer\AIWatch"
[pscustomobject]@{
  Host = $cfg.Host
  HasOrgApiKey = -not [string]::IsNullOrWhiteSpace($cfg.OrgApiKey)
}

# All three tasks registered?
Get-ScheduledTask -TaskPath "\Runlayer\" | Format-Table TaskName, State

"AIWatchScan","AIWatchHooks","AIWatchUpdate" | ForEach-Object {
  Get-ScheduledTaskInfo -TaskPath "\Runlayer\" -TaskName $_ |
    Select-Object TaskName, LastRunTime, LastTaskResult, NextRunTime
}

# (Protect, Enforce, or Sessions) hook configs current? Expect exit 0.
& $exe setup hooks check --mdm
```

Do not include the registry `OrgApiKey` value in screenshots or support tickets.

Then open **Shadow AI → Devices** in Runlayer and confirm the device appears and its last-seen timestamp advances. A JumpCloud "installed" result proves delivery, not backend check-in — allow up to 15 minutes for the first scheduled scan.

### Updates

Managed updates are on by default: `AIWatchUpdate` checks the Client Updates policy hourly and installs the selected MSI as SYSTEM. Use JumpCloud to bootstrap or repair the package and Runlayer Client Updates for ongoing version selection. Devices on an MSI that predates `AIWatchUpdate` need one ordinary JumpCloud package push before automatic updates take over.

For full package, scheduled-task, and hook cleanup, see [Remove AI Watch](/shadow-ai/deploy/remove).

## Troubleshooting

<AccordionGroup>
  <Accordion title="Device does not appear in Runlayer after 15 minutes">
    * Confirm the device is in the assigned JumpCloud Device Group and the profile + package (macOS) or MSI (Windows) succeeded.
    * Confirm the host is the correct tenant and an org key is present (macOS: `defaults read /Library/Managed\ Preferences/com.runlayer.aiwatch.plist`; Windows: the `HasOrgApiKey` check above) without exposing the key.
    * Confirm outbound HTTPS to your tenant host.
    * Trigger a scan manually — macOS: `sudo /usr/local/bin/aiwatch scan`; Windows: `Start-ScheduledTask -TaskPath "\Runlayer\" -TaskName "AIWatchScan"`.
    * Review logs — macOS: `~/.runlayer/logs` and `launchctl print`; Windows: `C:\ProgramData\Runlayer\Logs\scheduled-task.log`.
  </Accordion>

  <Accordion title="Windows tasks are missing">
    Repair or redeploy the MSI from JumpCloud with the same two required properties. Task registration gates on `OrgApiKey`, so a missing property leaves no `\Runlayer` tasks. Do not add an OMA-URI policy to compensate.
  </Accordion>

  <Accordion title="macOS scan misses protected folders">
    Confirm the consolidated profile policy shows exit status `0` and the Mac is UAMDM or ADE enrolled. Package installation alone cannot grant Full Disk Access.
  </Accordion>

  <Accordion title="Hooks show drift or are absent">
    Confirm the deployment actually requires hooks: Protect, Enforce, Sessions, or MCP-usage metadata. Hook reconciliation runs on the `AIWatchHooks` task (Windows) or the bootstrap daemon (macOS); restart already-running AI clients after reconciliation so they reload hook configuration.
  </Accordion>
</AccordionGroup>

For general deployment diagnostics, see [Troubleshooting](/shadow-ai/troubleshooting).
