Move an existing rule between tiers — `platform`, `organization`, or `assistant` — without losing the rule's ID, attachments, or audit history. Idempotency-aware: re-issuing the same target scope returns 409 instead of silently succeeding.

The same contract applies to behaviour templates, skins, and skills (see `Related resources` at the bottom).

## Path parameters

**`org_id`** string required

The organization ID.

**`rule_id`** string required

The ID of the rule to move.

## Body parameters

**`target_scope`** string required

The tier the rule should be moved to. One of `platform`, `organization`, or `assistant`. Must differ from the rule's current scope.

**`expected_version`** integer optional

Optimistic-lock guard. When supplied, the request fails with 409 `SCOPE_MOVE_VERSION_CONFLICT` if the rule's current `version` doesn't match. Omit to force the move regardless of concurrent edits.

**`target_assistant_id`** string optional

Optional convenience for `target_scope='assistant'`. Tier and attachments are decoupled — a rule at `scope='assistant'` may carry 0, 1, or N attachments. When `target_assistant_id` is supplied on an assistant-tier move, the BE additionally creates one attachment to that assistant so the move + first attach happen in a single round-trip. Omit to retier without creating any attachment. Ignored on the skin and skill paths (those resources don't carry direct attachments).

## Cascade rules

| Target scope | Effect on existing attachments |
|  --- | --- |
| `platform` | All attachments are detached (platform rules apply unconditionally and per-entity bindings are meaningless). |
| `organization` | All attachments retained — they continue to apply within the same org universe. |
| `assistant` | All attachments retained. If `target_assistant_id` is supplied and no attachment to that assistant exists yet, one is created. |


The detached attachment list is returned in `detached_attachments` so the FE can surface a toast like "moved Rule X to Assistant Y; detached 3 other attachments."

## Authorization

| Target scope | Capability required |
|  --- | --- |
| `platform` | `manage_platform_rules` (Aitronos-internal admin only) |
| `organization` | `manage_rules` |
| `assistant` | `manage_rules` |


Platform-tier rules cannot be moved out of platform — fork instead. Attempting `platform → anything` returns 422 `SCOPE_MOVE_FROM_PLATFORM_FORBIDDEN`.

## Errors

| Status | Error code | Why |
|  --- | --- | --- |
| 401 | (auth) | Authentication missing/invalid |
| 403 | `INSUFFICIENT_PERMISSIONS` | Caller lacks the target-scope capability |
| 404 | `RULE_NOT_FOUND` | Rule does not exist or belongs to another org |
| 409 | `SCOPE_MOVE_NO_OP` | `target_scope` equals current scope |
| 409 | `SCOPE_MOVE_VERSION_CONFLICT` | `expected_version` mismatch |
| 422 | `SCOPE_MOVE_FROM_PLATFORM_FORBIDDEN` | Source scope is `platform` |


## Returns


```json
{
  "rule": {
    "id": "rule_abc123",
    "name": "Professional Communication",
    "scope": "assistant",
    "version": 4
  },
  "detached_attachments": [
    { "id": "ratt_xyz789", "entity_type": "organization", "entity_id": "org_abc123", "reason": "unreachable_at_target_scope" }
  ],
  "from_scope": "organization",
  "to_scope": "assistant"
}
```

`rule.id` and `rule.name` are preserved. `rule.version` is incremented. The audit log records a `scope_moved` row with `{from, to, target_assistant_id, detached_attachment_ids}`.

Request

```bash cURL
curl -X POST https://api.aitronos.com/v1/organizations/org_abc123/rules/rule_abc123/move-scope \
  -H "X-API-Key: $FREDDY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target_scope": "assistant",
    "target_assistant_id": "asst_xyz789"
  }'
```


```python Python SDK
from aitronos import Aitronos

client = Aitronos(api_key="your-api-key")

result = client.rule_operations.move_rule_scope(
    org_id="org_abc123",
    rule_id="rule_abc123",
    target_scope="assistant",
    target_assistant_id="asst_xyz789",
)
print(result.rule.id, "now at scope", result.to_scope)
```


```python Python
import requests

response = requests.post(
    "https://api.aitronos.com/v1/organizations/org_abc123/rules/rule_abc123/move-scope",
    headers={"X-API-Key": "your-api-key", "Content-Type": "application/json"},
    json={
        "target_scope": "assistant",
        "target_assistant_id": "asst_xyz789",
    },
)
print(response.json())
```


```javascript JavaScript
const response = await fetch(
  'https://api.aitronos.com/v1/organizations/org_abc123/rules/rule_abc123/move-scope',
  {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.FREDDY_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      target_scope: 'assistant',
      target_assistant_id: 'asst_xyz789',
    }),
  }
);
const data = await response.json();
console.log(data);
```

Response

```json 200 OK
{
  "rule": {
    "id": "rule_abc123",
    "name": "Professional Communication",
    "scope": "assistant",
    "organization_id": "org_abc123",
    "version": 4,
    "...": "..."
  },
  "detached_attachments": [
    {
      "id": "ratt_xyz789",
      "entity_type": "organization",
      "entity_id": "org_abc123",
      "reason": "unreachable_at_target_scope"
    }
  ],
  "from_scope": "organization",
  "to_scope": "assistant"
}
```


```json 409 SCOPE_MOVE_NO_OP
{
  "success": false,
  "error": {
    "code": "SCOPE_MOVE_NO_OP",
    "message": "The resource is already at that scope. Specify a different target scope to move it.",
    "system_message": "target_scope equals current scope — no-op rejected to keep moves explicit.",
    "type": "client_error",
    "status": 409,
    "details": { "rule_id": "rule_abc123", "current_scope": "organization", "target_scope": "organization" },
    "trace_id": "...",
    "timestamp": "..."
  }
}
```


```json 422 SCOPE_MOVE_FROM_PLATFORM_FORBIDDEN
{
  "success": false,
  "error": {
    "code": "SCOPE_MOVE_FROM_PLATFORM_FORBIDDEN",
    "message": "Platform-tier resources cannot be moved out of the platform tier — fork instead.",
    "system_message": "Source scope is 'platform'; platform-tier rows are immutable in scope.",
    "type": "validation_error",
    "status": 422,
    "details": { "rule_id": "rule_abc123", "current_scope": "platform", "target_scope": "organization" },
    "trace_id": "...",
    "timestamp": "..."
  }
}
```

## Related resources

- [Move skin-template scope](/assets/move-scope.9d5a3bc2a9f5006f69cc946000b053928ce25e0a3a2222cd41368df91dca1f4b.d010c46b.md)
- [Move skin scope](/docs/api-reference/skins/move-scope)
- [Move skill scope](/docs/api-reference/skills/move-scope)
- [Update rule](/docs/api-reference/rules/update-a-rule)
- [Duplicate rule](/docs/api-reference/rules/duplicate)