---
title: "Replace a workspace's guardrail rules"
method: PUT
path: "/workspaces/{workspace_id}/guardrails/rules"
tags: ["Guardrail"]
---

# Replace a workspace's guardrail rules

`PUT /workspaces/{workspace_id}/guardrails/rules`

## Request

- Base URL: `https://api.mabl.com`
- URL: `https://api.mabl.com/workspaces/{workspace_id}/guardrails/rules`
- Auth: one of:
  - HTTP basic
  - API key in header `Authorization`

Replaces the workspace's guardrail rules with the given list, which becomes the whole list, and sets their mode when the body names one. If-Match must carry the revision last read; a stale revision is refused with 412 so concurrent edits are not lost. Workspace rules only restrict agents: an ALLOW never overrides a block mabl or the workspace's account applies, so leaving an action without a rule is how it is allowed. Only a workspace owner or a mabl global admin may change guardrails; API keys and agents never may.

## Path parameters

- `workspace_id` string, required

## Headers

- `If-Match` string

## Request body

- GuardrailRulesUpdate: The complete list of rules a workspace's guardrails are replaced with, and optionally their mode.
  - `mode` 'ENFORCE' | 'PREVIEW': Whether a rule set's effects reach agents. ENFORCE applies every rule in the set wherever the workspace enforces guardrails; PREVIEW evaluates and logs every rule without ever changing what the agent gets.
  - `rules` GuardrailRuleInput[], required: Every rule the workspace keeps, at most 200; a stored rule left out is deleted, and an empty list removes them all.
    - `id` string: The id of the existing rule this entry keeps, preserving its creation; absent for a new rule.
    - `target` GuardrailRuleTarget, required: The action, group of actions or scope a rule applies to.
      - `type` 'ACTION' | 'GROUP' | 'SCOPE', required: The kind of thing a rule applies to. ACTION is one action such as Delete::Flow, GROUP a catalog group of actions such as destructive, SCOPE every action under a permission scope such as write:flows.
      - `id` string, required: The id of the action (e.g. Delete::Flow), group (e.g. destructive) or scope (e.g. write:flows), as the catalog lists it.
    - `effect` 'ALLOW' | 'ASK' | 'BLOCK', required: What happens when the rule matches: ALLOW lets the action run, ASK requires a person's approval, BLOCK refuses it with the rule's reason, or with a mabl-written one naming the rule's target when the rule has none. The strictest matching rule wins, so an ALLOW never overrides another rule's or mabl's refusal.
    - `condition` GuardrailCondition: When a rule applies. Either a test, which sets attribute, op and values and nothing else, or a combination, which sets exactly one of all or any and nothing else. Combinations nest at most four deep. Example: {attribute: context.branch, op: eq, values: [master]}.
      - `attribute` string: The request attribute a test checks: action.id, action.verb, action.resource, action.scope, principal.root, agent.caller, context.branch or resource.id. agent.caller is external for a coding agent connected over MCP or the CLI and mabl for mabl's own agents.
      - `op` 'eq' | 'neq' | 'in' | 'not_in' | 'prefix' | 'exists': How a condition tests its attribute against its values. eq and neq compare with the one value, in and not_in with any of the values, prefix checks whether the attribute starts with any of the values, and exists checks whether the request carries the attribute at all and takes no values.
      - `values` string[]: What a test compares the attribute with; absent for exists, exactly one for eq and neq.
      - `all` GuardrailCondition[]: A combination that holds when every one of its conditions holds; never empty.
      - `any` GuardrailCondition[]: A combination that holds when at least one of its conditions holds; never empty.
    - `reason` string: Why the rule exists, shown to the agent and person it refuses, at most 500 characters. When absent, a refusal says the workspace's guardrails block the rule's target.

## Response `200`

The workspace's guardrails after the update, carrying the new revision.

- WorkspaceGuardrails: A workspace's guardrail rules with what is needed to render and edit them.
  - `workspace_id` string: The id of the workspace the guardrails belong to.
  - `revision` integer: The revision of the workspace's rules, 0 before they were first saved; send it as If-Match to replace them.
  - `mode` 'ENFORCE' | 'PREVIEW': Whether a rule set's effects reach agents. ENFORCE applies every rule in the set wherever the workspace enforces guardrails; PREVIEW evaluates and logs every rule without ever changing what the agent gets.
  - `enforcement_enabled` boolean: Whether this workspace enforces guardrails. When false, a refusal is only logged and the agent request goes on.
  - `rules` GuardrailRule[]: The workspace's rules, oldest first by created_time and then by id.
    - `id` string, required: The rule's id, stable across edits.
    - `kind` 'RULE', required: How the rule is decided. RULE matches on the action and the request's attributes; it is the only kind a rule can have.
    - `target` GuardrailRuleTarget, required: The action, group of actions or scope a rule applies to.
      - `type` 'ACTION' | 'GROUP' | 'SCOPE', required: The kind of thing a rule applies to. ACTION is one action such as Delete::Flow, GROUP a catalog group of actions such as destructive, SCOPE every action under a permission scope such as write:flows.
      - `id` string, required: The id of the action (e.g. Delete::Flow), group (e.g. destructive) or scope (e.g. write:flows), as the catalog lists it.
    - `effect` 'ALLOW' | 'ASK' | 'BLOCK', required: What happens when the rule matches: ALLOW lets the action run, ASK requires a person's approval, BLOCK refuses it with the rule's reason, or with a mabl-written one naming the rule's target when the rule has none. The strictest matching rule wins, so an ALLOW never overrides another rule's or mabl's refusal.
    - `condition` GuardrailCondition: When a rule applies. Either a test, which sets attribute, op and values and nothing else, or a combination, which sets exactly one of all or any and nothing else. Combinations nest at most four deep. Example: {attribute: context.branch, op: eq, values: [master]}.
      - `attribute` string: The request attribute a test checks: action.id, action.verb, action.resource, action.scope, principal.root, agent.caller, context.branch or resource.id. agent.caller is external for a coding agent connected over MCP or the CLI and mabl for mabl's own agents.
      - `op` 'eq' | 'neq' | 'in' | 'not_in' | 'prefix' | 'exists': How a condition tests its attribute against its values. eq and neq compare with the one value, in and not_in with any of the values, prefix checks whether the attribute starts with any of the values, and exists checks whether the request carries the attribute at all and takes no values.
      - `values` string[]: What a test compares the attribute with; absent for exists, exactly one for eq and neq.
      - `all` GuardrailCondition[]: A combination that holds when every one of its conditions holds; never empty.
      - `any` GuardrailCondition[]: A combination that holds when at least one of its conditions holds; never empty.
    - `reason` string: Why the rule exists, shown to the agent and person it refuses; absent when none was written.
    - `created_by_id` string: The id of the user who created the rule.
    - `created_time` integer: When the rule was created, in epoch milliseconds.
    - `last_updated_by_id` string: The id of the user who last changed the rule.
    - `last_updated_time` integer: When the rule was last changed, in epoch milliseconds.
  - `catalog` GuardrailCatalog: Everything a workspace rule can target.
    - `actions` GuardrailCatalogAction[]: The actions a rule can target.
      - `id` string: The action's id, which a rule targets, e.g. Delete::Flow.
      - `name` string: The action's display name, e.g. Delete flow.
      - `description` string: A sentence describing what the action does, e.g. Delete a flow.
      - `verb` string: What the action does to its resource, e.g. Delete.
      - `resource` string: The kind of entity the action acts on, e.g. Flow.
      - `scope` string: The permission scope the action sits under, e.g. write:flows.
      - `groups` string[]: The ids of the catalog groups the action belongs to, e.g. all, delete, destructive.
      - `risk_group` 'READ' | 'CHANGE' | 'COSTLY' | 'DESTRUCTIVE': How much an action can change. READ only reads, CHANGE creates or edits, COSTLY runs work that consumes credits or capacity, DESTRUCTIVE deletes, merges or restores.
    - `groups` GuardrailCatalogGroup[]: The groups of actions a rule can target.
      - `id` string: The group's id, which a rule targets, e.g. destructive.
      - `name` string: The group's display name, e.g. Destructive.
      - `description` string: A sentence describing which actions the group holds.
  - `agent_type_ceilings` AgentTypeGuardrailCeiling[]: For each agent type, what mabl lets it do and never lets it do; read-only.
    - `agent_type` 'test_authoring' | 'flow_authoring' | 'test_creation_planning' | 'test_planning' | 'agent_review' | 'app_summary' | 'test_run_analysis' | 'test_recovery' | 'runtime_recovery_summary_agent' | 'plan_run_analysis' | 'deployment_analysis' | 'workspace_results_analysis' | 'results_auto_analysis' | 'workspace_assistant' | 'app_modeling' | 'app_modeling_run' | 'file_assertion' | 'test_impact' | 'test_impact_shadow' | 'repair_notes' | 'external_agent' | 'exploratory_qa'
    - `may` string[]: What the agent type may do, one line per verb listing its resources, e.g. Edit, flow, test.
    - `never` string[]: What mabl never lets the agent type do, one sentence each.

## Other responses

- `400`: A rule is invalid. The message names the rule by its index, e.g. rules[0]: no action Delete::Nothing in the guardrail catalog.
- `401`: The request carries no valid credential.
- `403`: The caller is not the workspace's owner or a mabl global admin. API keys and agents are always refused.
- `412`: If-Match does not name the current revision of the rules; read them again and reapply the edit.
- `428`: If-Match was not sent.
- `default`: Unknown error

## Changes

- **2026-10-19** `b602223aa51f`: 6 info
  - added the optional property `guardrail/allOf[#/components/schemas/GuardrailRefusal]/approval` to the response with the `400` status
  - added the optional property `guardrail/allOf[#/components/schemas/GuardrailRefusal]/approval` to the response with the `401` status
  - added the optional property `guardrail/allOf[#/components/schemas/GuardrailRefusal]/approval` to the response with the `403` status
  - added the optional property `guardrail/allOf[#/components/schemas/GuardrailRefusal]/approval` to the response with the `412` status
  - …2 more
- **2026-10-17** `91ff383fb7f9`: 1 warning
  - added the new `external_agent` enum value to the `agent_type_ceilings/items/agent_type/allOf[#/components/schemas/AgentType]/` response property for the response status `200`
- **2026-10-16** `ea5e6f26b08d`: 1 warning
  - added the new `exploratory_qa` enum value to the `agent_type_ceilings/items/agent_type/allOf[#/components/schemas/AgentType]/` response property for the response status `200`
- **2026-10-15** `4e32d22292af`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/mabl/apis/mabl-api/changes/workspaces/:workspace_id/guardrails/rules/put.md)

---

[API](https://skmtc.dev/mabl/apis/mabl-api.md) · [All operations](https://skmtc.dev/mabl/apis/mabl-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mabl/apis/mabl-api/revisions/b602223aa51f?raw)
