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

# Cursor Cloud Agents

> Send monitor-only Cursor Cloud Agent sessions to Runlayer with scoped repository or team hooks.

Cursor Cloud Agents run outside your managed endpoints, so they do not inherit
AI Watch binaries, MDM settings, or endpoint hooks. Use the Cursor Cloud hook
collector to send supported session events to Runlayer.

This integration is **monitor-only**. It cannot block tools, enforce MCP policy,
read Runlayer data, or administer your workspace. The first prompt can run before
repository hooks initialize, and Cursor Cloud does not currently emit
`sessionStart` or `sessionEnd`, so session coverage is degraded.

## 1. Create a scoped key

In Runlayer, go to **Settings → Organization API Keys**, create a key with only
the **Cursor Cloud Hooks** permission, and copy it when shown. Runlayer stores
only its hash. Creating a replacement and revoking the old key rotates access
without deleting historical sessions.

Add the value to your Cursor Cloud environment or team secret store as
`RUNLAYER_CURSOR_CLOUD_HOOK_KEY`. Do not commit it to the repository, and do not
use an AI Watch organization key or Agent Account secret.

## 2. Add the hook helper

Create `.cursor/runlayer_cloud_hook.py` in the repository. Replace the hostname
in `COLLECTOR_URL` with your Runlayer tenant hostname. Keep the full HTTPS URL
literal so repository content cannot redirect credentials to another host.

```python theme={null}
#!/usr/bin/env python3
import os
import sys
import time
import urllib.error
import urllib.request
import uuid

COLLECTOR_URL = "https://YOUR-TENANT.runlayer.com/api/v1/hooks/cursor-cloud/events"
MAX_PAYLOAD_BYTES = 256 * 1024
ALLOW = '{"permission":"allow"}'


class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None


def deliver(payload: bytes, key: str) -> None:
    delivery_id = str(uuid.uuid4())
    request = urllib.request.Request(
        COLLECTOR_URL,
        data=payload,
        method="POST",
        headers={
            "Content-Type": "application/json",
            "X-Runlayer-Delivery-ID": delivery_id,
            "x-runlayer-api-key": key,
        },
    )
    opener = urllib.request.build_opener(NoRedirect)
    for attempt, delay in enumerate((0, 0.2, 0.8)):
        if delay:
            time.sleep(delay)
        try:
            with opener.open(request, timeout=2) as response:
                if 200 <= response.status < 300:
                    return
        except urllib.error.HTTPError as error:
            if error.code < 500 and error.code != 429:
                return
            if attempt == 2:
                return
        except (urllib.error.URLError, TimeoutError):
            if attempt == 2:
                return


def main() -> int:
    try:
        payload = sys.stdin.buffer.read(MAX_PAYLOAD_BYTES + 1)
        key = os.environ.get("RUNLAYER_CURSOR_CLOUD_HOOK_KEY", "")
        if key and len(payload) <= MAX_PAYLOAD_BYTES:
            deliver(payload, key)
    except Exception:
        pass
    sys.stdout.write(ALLOW)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
```

The helper reuses one delivery ID across transient retries, never logs the key or
payload, and always returns Cursor's explicit allow response. A Runlayer outage
therefore cannot block or change a Cloud Agent run.

## 3. Register live Cloud events

Add these entries to `.cursor/hooks.json`, preserving any existing hooks:

```json theme={null}
{
  "version": 1,
  "hooks": {
    "beforeReadFile": [{ "command": "python3 .cursor/runlayer_cloud_hook.py" }],
    "beforeSubmitPrompt": [{ "command": "python3 .cursor/runlayer_cloud_hook.py" }],
    "afterAgentThought": [{ "command": "python3 .cursor/runlayer_cloud_hook.py" }],
    "preToolUse": [{ "command": "python3 .cursor/runlayer_cloud_hook.py" }],
    "postToolUse": [{ "command": "python3 .cursor/runlayer_cloud_hook.py" }],
    "afterAgentResponse": [{ "command": "python3 .cursor/runlayer_cloud_hook.py" }],
    "stop": [{ "command": "python3 .cursor/runlayer_cloud_hook.py" }]
  }
}
```

Run a follow-up prompt after the Cloud environment is ready, then open
**Sessions** in Runlayer and filter for **Cursor Cloud Agents**. If events do not
appear, confirm **Cursor** is enabled under **Settings → Agent session
monitoring**, the secret is present in the Cloud environment, and the collector
URL uses the correct tenant hostname.
