Skip to main content

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.

Common Authentication Errors

Detect scans use organization API keys (created in Settings → API Keys with the Detect Scan role). Auto-provisioning (hooks, sync) uses enrollment keys (created in Settings → Enrollment Keys).
HTTP StatusErrorCauseResolution
401Missing/invalid API keyKey is incorrect, revoked, or missingVerify the organization API key (Detect) or enrollment key (auto-provisioning) in your script
403ForbiddenAPI key lacks required roleEnsure the org key has the Detect Scan role
500Server errorInternal server issueContact Runlayer support

Interpreting Discovery Results

Cause: Detect classifies based on MCP config files found on disk, not actual tool calls. A user being attributed to a shadow MCP means a matching config was found on a device whose login username resolved to that user — not that they ever invoked any tool from the server.Common reasons a config gets attributed to a user who never used it:
  • Project-level config in a cloned repo. A .cursor/mcp.json, .vscode/mcp.json, .mcp.json, .codex/config.toml, or similar checked into a shared repo is discovered on every developer who clones it. The config is attributed to the OS user who ran the scan on that machine.
  • Stale or experimental config. The user added the server to a client config file once (e.g. trying it out, copy-pasting from a blog), never invoked it, and forgot it was still there.
  • Shared device. Another OS account on the same workstation configured the MCP, but the scan ran under a different OS account that resolves to this Runlayer user.
  • Username resolution mismatch. Tiered matching (email, identity attribute, local-part, name pattern) can link a device’s OS username to the wrong Runlayer user. Fix via Settings → Shadow MCPs → Unresolved Usernames and then re-analyze.
How the user (or admin) can verify the source themselves:
  1. Click the user in the Shadow page to open the audit log filtered to shadow_mcp_detected for that user.
  2. Each event includes the device hostname, device id, the MCP server’s command / args / url, and any project paths where the config was found.
  3. If a project path is listed, the discovery came from a project-level config file. Open that repo and inspect the checked-in MCP config to confirm.
  4. If no project path is listed, the discovery came from a global client config. On the listed device, inspect the relevant client config (e.g. ~/Library/Application Support/Claude/claude_desktop_config.json, ~/.cursor/mcp.json, ~/.codex/config.toml).
  5. To clear the discovery, remove the entry from the offending config file (or uninstall the project) and the next scan will drop it from the inventory.

Common Issues

Quick fixes:
  1. Check script permissions: chmod +x run-ai-watch-macos.sh
  2. Verify the script is assigned to the correct device group in your MDM
  3. Check MDM console for script execution errors
  4. Review logs at /var/log/runlayer/ai_watch_detect.log
Quick fixes:
  1. Ensure PowerShell execution policy allows the script
  2. Run Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser if needed
  3. Verify the script is assigned to the correct device group in your MDM
  4. Review logs at %ProgramData%\Runlayer\ai_watch_detect.log
Quick fixes:
  1. Check script logs for errors (see Log Locations below)
  2. Verify the API key is active and not revoked — org API key in Settings > API Keys (Detect) or enrollment key in Settings > Enrollment Keys (auto-provisioning)
  3. Confirm network connectivity from devices to your Runlayer host
  4. Check that the script is actually being executed by your MDM
  5. Verify the Runlayer API is reachable from device networks
Quick fixes:
  1. Check that uv is properly installed and in the system PATH
  2. Review verbose output with runlayer scan --verbose
  3. Ensure no firewall rules are blocking the Runlayer API
  4. Verify the organization API key has the Detect Scan role
Symptoms: The scan discovers local config, then fails while submitting results:
Submitting 9 servers from 9 configs (1 global, 8 project)...
Scan failed error='[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1017)' error_type=ConnectError
Cause: Some enterprise proxies intercept HTTPS and re-sign traffic with a private root CA. The Runlayer CLI trusts the macOS Keychain and Windows certificate store automatically, but scans can fail if that private CA is not installed in system trust.Resolution:
  1. Prefer installing the corporate root CA into the OS trust store through MDM. The CLI and MDM-deployed aiwatch binary will trust it automatically.
  2. For debugging or one-off deployments, pass a PEM bundle explicitly:
    runlayer --ca-bundle /path/to/corporate-ca.pem scan
    
  3. For scripted deployments, set RUNLAYER_CA_BUNDLE. The CLI also honors SSL_CERT_FILE and REQUESTS_CA_BUNDLE as fallbacks.
  4. Ask the security team to exempt the Runlayer tenant hostname from TLS inspection, such as *.runlayer.com or customer-managed hostnames like runlayer.dev.company.com just like they do for other security products like endpoint detection and response (EDR).
Cause: uv tool install runlayer places the binary in ~/.local/bin (macOS/Linux) or %USERPROFILE%\.local\bin (Windows), which may not be in your shell’s PATH yet.Resolution:
  1. Restart your terminal (new shells pick up the updated PATH)
  2. Or run uv tool update-shell to add ~/.local/bin to your shell profile, then exec $SHELL -l (or open a new terminal)
  3. Verify: which runlayer (macOS/Linux) or where runlayer (Windows)
Symptoms: No audit log entries appear for shadow MCP tool calls. In enforcement mode, calls may be denied with “Runlayer credentials are not configured.”Cause: The AI client may not have runlayer on PATH at hook runtime. On macOS, GUI clients launched from the Dock or Spotlight inherit an environment that often does not include ~/.local/bin; terminal clients such as Claude Code and Codex need the shell PATH to include the Runlayer CLI.Resolution:
  1. Install the CLI with uv tool install runlayer (not uvx runlayer ...) so the binary is permanently on disk
  2. Verify from a terminal launched the same way your editor launches: command -v runlayer
  3. On macOS, if the editor still can’t find the CLI, set the PATH for GUI apps:
    sudo launchctl config user path "$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    
    Then log out and log back in, or reboot
  4. Alternatively, restart Cursor, Claude Code, or Codex from a terminal where runlayer is on PATH
Check which runlayer binary the hook script will find at runtime:
command -v runlayer && echo "runlayer found" || echo "runlayer NOT found"
command -v uvx && echo "uvx found (fallback)" || echo "uvx NOT found"
The hook script tries runlayer first, then falls back to uvx. If neither is found, enforcement hooks deny all calls and observational hooks silently exit.
Symptoms: Scan completes successfully but doesn’t find MCP servers you know exist in directories like Desktop, Documents, or Application Support.Cause: macOS TCC (Transparency, Consent, and Control) is blocking access to protected directories.Resolution:
  1. Deploy the PPPC profile to grant Full Disk Access to the wrapper binary
  2. Ensure devices are enrolled via User-Approved MDM or Automated Device Enrollment
  3. Verify the profile is installed: profiles show -type configuration | grep runlayer
  4. Verify the wrapper binary is installed and signed correctly:
    ls -la /usr/local/bin/runlayer-scan
    codesign -dv /usr/local/bin/runlayer-scan
    
  5. Re-run the scan after the PPPC profile is applied
Quick fixes:
  1. Check LaunchAgent logs: cat /tmp/runlayer-scan.stderr.log
  2. Verify the LaunchAgent is loaded: launchctl list | grep runlayer
  3. Check the main log: cat /var/log/runlayer/ai_watch_detect.log
  4. Verify the wrapper binary exists and is signed:
    ls -la /usr/local/bin/runlayer-scan
    codesign -dv /usr/local/bin/runlayer-scan
    
  5. Test the wrapper binary: /usr/local/bin/runlayer-scan --dry-run
  6. Try manually triggering: launchctl kickstart -kp gui/$(id -u)/com.runlayer.scan
Cause: The script detected that the LaunchAgent may not have transitioned to a running state after being triggered. This can happen due to timing issues or if the LaunchAgent failed to start.Quick fixes:
  1. Check if the scan actually ran by reviewing the logs:
    cat /tmp/runlayer-scan.stdout.log
    cat /tmp/runlayer-scan.stderr.log
    
  2. Verify the LaunchAgent is properly loaded: launchctl list | grep runlayer
  3. Check system load — high CPU usage can delay process startup
  4. Manually trigger the scan to test: launchctl kickstart -kp gui/$(id -u)/com.runlayer.scan
  5. If the issue persists, check Console.app for launchd errors related to com.runlayer.scan

Log Locations

PlatformFeatureLog Location
macOSDetect/var/log/runlayer/ai_watch_detect.log
macOSEnforce/var/log/runlayer/ai_watch_enforce.log
macOS (fallback)Detect/tmp/runlayer-ai_watch_detect.log
macOS (fallback)Enforce/tmp/runlayer-ai_watch_enforce.log
macOSAuto-provisioning/var/log/runlayer/auto_provisioning.log
macOSLaunchAgent/tmp/runlayer-scan.stdout.log, /tmp/runlayer-scan.stderr.log
WindowsDetect%ProgramData%\Runlayer\ai_watch_detect.log
WindowsAuto-provisioning%ProgramData%\Runlayer\auto_provisioning.log
WindowsIntuneC:\ProgramData\Microsoft\IntuneManagementExtension\Logs

Exit Codes

CodeMeaning
0Success
1General failure (no user logged in, missing config)
2Network failure
3Installation failure

Verifying PPPC Profile Deployment (macOS)

After deploying the PPPC profile, verify it’s installed on target devices:
# List installed configuration profiles
profiles show -type configuration | grep -i runlayer

# Check if Full Disk Access is granted (requires admin)
sudo sqlite3 "/Library/Application Support/com.apple.TCC/TCC.db" \
  "SELECT client, auth_value FROM access WHERE service='kTCCServiceSystemPolicyAllFiles';"

Verifying Wrapper Binary (macOS)

Verify the wrapper binary is properly installed and signed:
# Check wrapper binary is installed
ls -la /usr/local/bin/runlayer-scan

# Verify the signature and identifier
codesign -dv /usr/local/bin/runlayer-scan

# Test the wrapper binary (dry run)
/usr/local/bin/runlayer-scan --dry-run
The signature should show Identifier=com.runlayer.scan which matches the PPPC profile.

Getting Help

If you continue to experience issues:
  1. Collect the relevant log files from the affected device
  2. Note the HTTP status codes and error messages
  3. Contact Runlayer support with the collected information