# AI policies

An AI policy is the set of AI controls one scope sets for itself: which models and modalities may run, whether the Layer agent and each subagent may run, the spend above which the agent asks before a job, and the parameter values a generation on a model starts from. The `AI Policies` endpoints let a workspace’s admins read and change them from a script, the same as **Settings > AI Controls** in the app. The same operations are on the [management MCP server](/docs/mcp/management).

## Scopes and precedence

A policy is attached to one scope, and holds only what that scope sets itself. Everything else is inherited from the less specific scopes, in this order:

1. the **workspace** (and, for a workspace under another, the workspaces above it)
2. a **project** in it, for work done in that project
3. the **groups** the member belongs to
4. the **member**: a user, service account or API key

The most specific scope that sets a value wins. Where a member’s groups disagree, the most permissive value wins: belonging to a stricter group never takes away what another group grants. Model defaults are the exception: groups that disagree on a default cancel out, and the member inherits it from the less specific scopes.

A workspace or project can **lock** a value. A locked value holds for every scope below the one that set it, which cannot override it. Group and member policies cannot lock.

Note

A workspace policy works on every plan. Project, group and member policies are part of the Enterprise plan: below it, writing most controls at those scopes returns `402` `AI_POLICY_REQUIRES_ENTERPRISE`. The NSFW tolerance is set by workspaces and projects at every plan, and a project can only make it stricter.

## The controls

Every value is a setting, `{ "value": …, "locked": false }`. Maps hold one setting per key, so each model, modality or subagent is inherited, overridden and locked on its own.

| Control                          | Value                                               | What it does                                                                                      |
| -------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| agent\_enabled                   | boolean                                             | The Layer agent as a whole.                                                                       |
| agents                           | map of principal id to boolean                      | Each subagent, by the principal it acts as.                                                       |
| agent\_confirm\_above\_cu        | number                                              | The Creative Units above which the agent asks before running a job.                               |
| modalities                       | map of modality to boolean                          | IMAGE, VIDEO, THREE\_D, AUDIO, TEXT on or off.                                                    |
| new\_models\_enabled             | boolean                                             | Whether a model models does not name may run: true makes models a deny list, false an allow list. |
| models                           | map of base model id to boolean                     | Each base model on or off.                                                                        |
| model\_defaults                  | map of base model id to a map of parameter to value | The parameter values a generation on the model starts from.                                       |
| nsfw\_tolerance                  | 1 to 6                                              | How much NSFW content generations may produce: 1 is the strictest. Workspaces and projects only.  |
| reference\_set\_sharing\_enabled | boolean                                             | Whether the workspace’s reference sets may be shared beyond it. Workspaces only.                  |
| workflow\_sharing\_enabled       | boolean                                             | Whether the workspace’s workflows may be shared beyond it. Workspaces only.                       |

Three more controls appear in reads and are kept when a policy is replaced or cleared:

| Control         | Value                                                                      | What it does                                                                                                                                                                                                                                                                |
| --------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| usage\_caps     | map of daily, weekly or monthly to {cu\_limit, mode, warn\_threshold\_pct} | The Creative Units each member may spend in the workspace per period. mode is warn or block; a null value lifts a cap set above. Set it with a patch, which takes the billing admin permission as well; a group’s cap can also be set with the group usage-limit endpoints. |
| guardrails      | map of rule id to boolean                                                  | Input guardrail rules, written by their own feature. A patch that names it is refused.                                                                                                                                                                                      |
| output\_scoring | map of rule id to boolean                                                  | Output scoring rules, written by their own feature. A patch that names it is refused.                                                                                                                                                                                       |

## Read a scope’s policy

Each scope has its policy at its own path:

| Scope     | Path                                                             |
| --------- | ---------------------------------------------------------------- |
| Workspace | /v2/workspaces/{workspace\_id}/ai-policy                         |
| Project   | /v2/workspaces/{workspace\_id}/projects/{project\_id}/ai-policy  |
| Group     | /v2/workspaces/{workspace\_id}/groups/{group\_id}/ai-policy      |
| Member    | /v2/workspaces/{workspace\_id}/members/{principal\_id}/ai-policy |

```bash
curl https://api.app.layer.ai/api/v2/workspaces/$WORKSPACE_ID/groups/$GROUP_ID/ai-policy \
  -H "Authorization: Bearer $LAYER_TOKEN"
```

The response holds the `policy` the scope sets itself and what it `inherited` from the less specific scopes, each inherited value with the `source` scope that set it and whether that scope locked it. A value with no source is the platform default. A scope that sets nothing returns an empty `policy`.

## Change it

1. **Patch** to change only what you name. The body is a [JSON merge patch](https://www.rfc-editor.org/rfc/rfc7396) of the policy: a control or key you name is set, one you name as `null` is removed so the scope inherits it again, and anything you leave out stays as it is. A setting is replaced whole, value and lock.  
```bash  
curl -X PATCH https://api.app.layer.ai/api/v2/workspaces/$WORKSPACE_ID/ai-policy \
  -H "Authorization: Bearer $LAYER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{  
    "models": { "flux-2-pro": { "value": false, "locked": true }, "flux-2-dev": null },  
    "model_defaults": { "flux-2-dev": { "inference_steps": { "value": 30 } } }  
  }'  
```  
This turns FLUX.2 Pro off for the whole workspace and locks it, returns FLUX.2 Dev to what the workspace inherits, and starts every FLUX.2 Dev generation at 30 steps, leaving every other control alone. Patches to one scope apply one after another, so two admins changing different models never undo each other.  
A member’s monthly cap is raised the same way:  
```bash  
curl -X PATCH https://api.app.layer.ai/api/v2/workspaces/$WORKSPACE_ID/members/$PRINCIPAL_ID/ai-policy \
  -H "Authorization: Bearer $LAYER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "usage_caps": { "monthly": { "value": { "cu_limit": 1000, "mode": "block", "warn_threshold_pct": 80 } } } }'  
```
2. **Replace** with `PUT` to set the whole policy at once. Anything the body leaves out is inherited, except guardrails, output scoring and usage caps, which are kept. Read the policy first and send it back with your change, or prefer a patch.
3. **Clear** with `DELETE` to remove every control the scope sets, so it inherits them. Guardrails, output scoring and usage caps are kept. It answers `204`.

A patch or replacement that sets nothing removes the policy, as a clear does. A patch that changes nothing writes nothing.

## List a workspace’s policies

`GET /v2/workspaces/{workspace_id}/ai-policies` lists every policy stored in the workspace, oldest first, each with its `scope`, its `policy`, and when and by whom it was last written. Filter by scope with `kind=workspace`, `project`, `group` or `member`, and page with `cursor` as on the other list endpoints.

## Read the policy in force

`GET /v2/workspaces/{workspace_id}/effective-ai-policy` resolves every scope’s policy into the controls in force for a member’s work, each value with the scope that set it. Name a `project_id` for work in a project, and a `principal_id` for another member; without one it resolves for the caller.

```bash
curl "https://api.app.layer.ai/api/v2/workspaces/$WORKSPACE_ID/effective-ai-policy?project_id=$PROJECT_ID" \
  -H "Authorization: Bearer $LAYER_TOKEN"
```

The maps hold only what some policy names. A model, modality or subagent they leave out takes the platform default: allowed, unless `new_models_enabled` is `false`, in which case a model only runs when `models` turns it on.

## Permissions

Reading or changing a policy takes the role that edits it in the app: the **settings admin** permission in the workspace, or for a project’s policy, the permission to edit its content policy. The list endpoint takes settings admin. Any member may read the policy in force for their own work; reading another member’s takes settings admin.

An access token needs the `workspace:read` scope to read and `workspace:write` to change a policy.

## Errors

| Status | Code                                | When                                                                                |
| ------ | ----------------------------------- | ----------------------------------------------------------------------------------- |
| 402    | AI\_POLICY\_REQUIRES\_ENTERPRISE    | A control the scope can only set on the Enterprise plan.                            |
| 404    | AI\_POLICY\_SCOPE\_NOT\_FOUND       | The project, group or member is not live in the workspace.                          |
| 422    | AI\_POLICY\_LOCK\_NOT\_ALLOWED      | A group or member policy that locks a setting.                                      |
| 422    | AI\_POLICY\_CONTROL\_NOT\_AT\_SCOPE | A control the scope kind cannot set, such as sharing on a project.                  |
| 422    | AI\_POLICY\_MIRROR\_GROUP           | A group that mirrors another workspace’s group: set the policy on the source group. |
| 422    | AI\_POLICY\_INVALID\_MODEL\_DEFAULT | A parameter the model cannot default, or a value it does not accept.                |
| 422    | INVALID\_LIMIT                      | A usage cap that is not positive, or above 10,000,000 Creative Units.               |
| 422    | INVALID\_WARN\_THRESHOLD            | A usage cap whose warn\_threshold\_pct is outside 1 to 100.                         |
