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

# Policy rules

> Scope AI Watch mode, Sessions, browser controls, detection phases and scan bounds to a team, group, user or device through the policy-rules API

By default every device on an AI Watch deployment receives the settings you pick under **Manage settings** on the deployment card. **Policy rules** let you narrow those settings to a team, group, user or single machine without creating another deployment: pilot Enforce with one team, turn Sessions off for a user, or lock down a specific laptop.

Policy rules are managed through the `/api/v1/ai-watch/policy-rules` API. Calls require the **Manage MDM configuration** capability (`manage_mdm_config`) — the same one that manages deployments.

## Scopes and precedence

Each rule has a `scope`, a `subject_id`, and a full `settings` object. Rules exist per deployment kind (`deployment_kind`: `ai_watch`, the default, or `cli`).

| Scope | `subject_id` | Wins when |
| - | - | - |
| `device` | The AI Watch device id (`device_id` on the devices list) | Always — a device rule overrides everything below for that machine, whoever is signed in |
| `user` | A user id | A user seen on the machine has a rule |
| `team` / `group` | A team or group id | The user has no user rule; **all** matching team and group rules merge to the strictest value per setting |
| `organization` | none | Nothing narrower applies |

Resolution runs top-down and stops at the first tier that has a match: **device > user > team/group > organization**. A user rule fully replaces the team/group tier — it is not merged with it. A device whose user cannot be resolved, or whose user is deactivated, receives the organization root.

### Shared machines

Policy is resolved per user on each machine, and the machine receives the **strictest merge across everyone who has used it in the last 30 days**: if one of two recent users is on an Enforce rule, the machine runs Enforce for both. A user who has not touched the machine for 30 days stops contributing. A `device` rule skips this merge entirely and applies to the machine regardless of who is signed in. `GET /ai-watch/policy-rules/check?device_id=…` shows exactly what a machine receives; `?user_id=…` shows what a user's own tier resolves to.

<Note>
  The **organization root is read-only** through this API. It is derived from the deployment settings of your organization keys (the strictest across your deployments for that kind); edit it with **Manage settings** on the deployment card. `PATCH` or `DELETE` on the root returns `409`, and `POST` with `scope: "organization"` returns `422`. `POST` before any deployment exists for the kind returns `409 missing_org_root`.
</Note>

### Strictest merge

When several team or group rules apply to one user, each setting resolves to its strictest value:

* `mode`: `enforce` > `protect` > `monitor`.
* Booleans (`sessions`, `browser_extension_enabled`, `detect_*`, `remove_uv_tool`): on if any rule turns it on.

<Note>
  `sessions` and `browser_sessions` are enforced by the device: `/config` delivers the resolved value and the agent stops collecting. The server-side ingest gate is per deployment kind, not per device, so while any rule of the kind has Sessions on, the backend still accepts session content from a device whose own rule turns it off. Treat a per-user or per-device Sessions off as a client control, not a server boundary (tracked in ENG-7000).
</Note>

* `project_depth`, `project_timeout`: the largest value.
* `browser_mode` / `browser_sessions`: `null` means "follow `mode` / `sessions`", so each rule contributes the browser value it actually delivers before the strictest is taken.

The same merge produces the organization root from your deployments.

## Settings payload

`settings` carries the full policy; on `PATCH`, sending `settings` replaces the whole object so an explicit `"browser_mode": null` is distinguishable from an untouched field.

```json theme={null}
{
  "mode": "enforce",
  "sessions": true,
  "browser_mode": null,
  "browser_sessions": null,
  "browser_extension_enabled": false,
  "detect_processes": false,
  "detect_containers": false,
  "detect_disguised_skills": false,
  "project_depth": 7,
  "project_timeout": 60,
  "remove_uv_tool": false
}
```

`mode` is required. Every other field defaults to the value shown: `sessions: true`, `browser_mode` / `browser_sessions` `null` (follow `mode` / `sessions`), `browser_extension_enabled` and every `detect_*` flag `false`, `project_depth: 7`, `project_timeout: 60`, `remove_uv_tool: false`. `project_depth` is clamped to `1`–`20` and `project_timeout` to `1`–`300`, matching the [scan tuning bounds](/shadow-ai/deploy#package-configuration).

## Endpoints

| Method | Path | Purpose |
| - | - | - |
| `GET` | `/ai-watch/policy-rules?deployment_kind=ai_watch` | Rules grouped as `organization`, `collections` (team/group), `users`, `devices`, each with `member_count` and `device_count` (devices the rule contributes to, not only those it is the source for) |
| `GET` | `/ai-watch/policy-rules/check?user_id=…` or `?device_id=…` | Preview the resolved policy: `tier`, `settings`, `source_rule`, `merged_rules` |
| `POST` | `/ai-watch/policy-rules` | Create a rule; one active rule per `(deployment_kind, scope, subject_id)`, duplicates return `409` |
| `PATCH` | `/ai-watch/policy-rules/{rule_id}` | Change `name`, `description` or `settings` |
| `DELETE` | `/ai-watch/policy-rules/{rule_id}` | Delete; affected devices fall back to the next tier |

Create a rule that puts one team in Enforce with Sessions on:

```bash theme={null}
curl -X POST "$RUNLAYER_HOST/api/v1/ai-watch/policy-rules" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "team",
    "subject_id": "<team-id>",
    "name": "Security team — Enforce",
    "settings": { "mode": "enforce", "sessions": true }
  }'
```

Fields not sent in `settings` take the defaults listed above, so this rule also turns every detection phase off for that team; send the full object when you mean to keep the deployment's values.

## How devices pick up a rule

Devices resolve their policy on check-in and apply it on their next settings sync, which runs every 15 minutes. Editing a rule's `settings` lands on the next sync of every device already on that rule; creating or deleting a rule re-resolves the devices it can reach. Each device on the **Devices** list shows its `effective_policy`: the rule it resolved to (`source_rule`) and every rule that contributed (`merged_rule_ids`). Filter the list by `policy_rule_ids` to see which devices a rule reaches; like `device_count`, it covers devices seen in the last 30 days.

Every rule change and every device that moves between rules is written to the [audit log](/platform-audit-logs) (`ai_watch_policy_rule_created` / `_updated` / `_deleted`, `ai_watch_effective_policy_changed`).

## Related Resources

<CardGroup cols={2}>
  <Card title="Deploy AI Watch" icon="download" href="/shadow-ai/deploy">
    Create deployments and manage the organization-wide settings
  </Card>

  <Card title="Endpoint modes" icon="shield" href="/shadow-ai/enforce">
    What Monitor, Protect and Enforce do on the device
  </Card>

  <Card title="Enforce policy" icon="list-check" href="/shadow-ai/enforce/policy">
    Allowlists and built-in tool blocks applied in Enforce
  </Card>

  <Card title="Browser extension" icon="globe" href="/shadow-ai/browser-extension">
    Browser mode and Sessions behavior delivered by these settings
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.