# Policy rules reference

> Write workspace policy rules for AI sessions: the seven actions, allow, ask and deny, resource globs, trust postures, log-only mode, and a worked example.

Source: https://aicodeops.dev/docs/policy-engine · Last updated: 2026-10-18

A workspace policy decides what AI sessions may do on their own, what needs a person's approval, and what they may never do. This page is the reference for writing rules. For how approvals work once a rule asks for one, see [Approvals and policies](https://aicodeops.dev/docs/approvals-and-policies).

Policies govern sessions only. What a person may do is set by their [role](https://aicodeops.dev/docs/roles-and-permissions).

## Open the policy

Open **Secure → Policies**. The page shows:

- **Enforcement**: **Enforced** or **Log only**.
- **Rules in effect**, **Trust posture** and **Version**.
- **Rules**: each rule's ID, action, resource and decision.
- **How rules apply**: the actions and what each one matches.
- **Recent decisions**: the latest denials, holds and log-only outcomes, with **View session**.

The page is shown to roles with the policy-manage permission: owners, admins and security admins by default.

## Rule format

Rules are a JSON array. Each rule has these fields:

| Field         | Required | What it is                                                         |
| ------------- | -------- | ------------------------------------------------------------------ |
| `id`          | Yes      | 1–64 characters: letters, digits, `.`, `_`, `:` or `-`. Unique.    |
| `action`      | Yes      | One of the actions below, or `*` for every action.                 |
| `decision`    | Yes      | `allow`, `ask` (needs an approval) or `deny`.                      |
| `resource`    | No       | A glob matched against what the action touches. Omitted means all. |
| `description` | No       | Up to 500 characters, shown under the rule's ID.                   |
| `enabled`     | No       | `false` keeps the rule but stops it applying.                      |

A policy can hold up to 200 rules.

## Actions

| Action              | Label                | Resource it matches        | When it is checked                                 | Decisions        |
| ------------------- | -------------------- | -------------------------- | -------------------------------------------------- | ---------------- |
| `workflow.dispatch` | Start a session      | workflow ID                | When a session starts                              | allow, ask, deny |
| `agent.dispatch`    | Run an agent step    | agent ID, e.g. `builder`   | When a session starts, for every agent it will run | allow, ask, deny |
| `mcp.invoke`        | Call an MCP tool     | `server/tool`              | When a session starts, for each connected MCP tool | allow, deny      |
| `shell.command`     | Run the test command | the command                | Before the session runs your tests                 | allow, deny      |
| `diff.apply`        | Change a file        | file path, e.g. `infra/**` | When the pull request is opened, for every file    | allow, ask, deny |
| `github.push`       | Open a pull request  | `owner/repo`               | When the pull request is opened                    | allow, ask, deny |
| `release.deploy`    | Deploy automatically | environment name           | Before an automatic deploy after a merge           | allow, deny      |

Some actions can't wait for a person, so they can't use `ask`. The editor refuses an `ask` on them. A stored `ask` on one of them is enforced as `deny`.

What each decision does:

- **Session start** (`workflow.dispatch`, `agent.dispatch`): `deny` refuses the session. `ask` holds it until someone approves it under **Review & Gate → Approvals**; rejecting or letting it expire cancels it.
- **MCP tools**: a tool that isn't allowed is never offered to the agents.
- **Pull request** (`github.push`, `diff.apply`): `deny` refuses the pull request. `ask` requires an approved review of the change. The session still runs and proposes its change; the rule decides whether it can land.
- **Automatic deploy**: anything but `allow` stops the deploy. It is recorded as a blocked deployment so you can see it didn't go out.

## How rules are evaluated

1. Every enabled rule whose `action` matches (or is `*`) and whose `resource` matches is considered.
2. The strictest decision wins: `deny` beats `ask`, and `ask` beats `allow`. Rule order doesn't matter.
3. If no rule matches, the trust posture decides.

### Resource globs

- `**` matches anything, including `/`.
- `*` matches any run of characters. For file paths, `server/tool` and `owner/repo`, it stops at `/`.
- `?` matches one character.
- No `resource`, `*` or `**` matches everything.

So `src/*.ts` matches `src/app.ts` but not `src/lib/app.ts`; use `src/**` for the whole folder.

## Trust posture

The posture applies when no rule matches.

| Posture             | Default decisions                                                                                          |
| ------------------- | ---------------------------------------------------------------------------------------------------------- |
| `trusted`           | Everything is allowed.                                                                                     |
| `limited` (default) | As trusted, but opening a pull request is `ask`.                                                           |
| `none`              | `deny` for MCP tools, the test command, file changes, pull requests and automatic deploys, unless allowed. |

Every session that changes code also gets a review request under **Review & Gate → Approvals**. The posture adds to that; it doesn't remove it.

## Example

This policy holds dependency upgrades for approval, asks for a review of any change to infrastructure files, blocks automatic deploys to production and keeps one MCP tool away from the agents:

```json
[
  {
    "id": "approve-dependency-refresh",
    "action": "workflow.dispatch",
    "resource": "dependency-refresh",
    "decision": "ask",
    "description": "A person approves before a dependency upgrade session starts"
  },
  { "id": "review-infra-changes", "action": "diff.apply", "resource": "infra/**", "decision": "ask" },
  { "id": "no-production-deploys", "action": "release.deploy", "resource": "production", "decision": "deny" },
  { "id": "no-repo-deletes", "action": "mcp.invoke", "resource": "github/delete_*", "decision": "deny" }
]
```

## Edit the policy

1. Open **Secure → Policies** and choose **Edit rules**.
2. Pick a **Trust posture**.
3. Edit the rules in the JSON box. An example is shown under it.
4. Choose **Save (version → N)**.

If a rule has a problem, nothing is saved and every problem is listed, for example `Rule 2: decision — "mcp.invoke" cannot wait for an approval; use allow or deny`. If someone else saved first, you see "Policy conflict" and the page loads their version; make your change again.

Each save creates a new version and a `policy.updated` entry in the [audit log](https://aicodeops.dev/docs/audit-logs).

## Log-only mode

Choose **Switch to log only** to stop enforcing without deleting rules. Every decision is still computed and recorded, shown as "logged" under **Recent decisions**, but nothing is blocked or held. Choose **Enforce** to turn it back on. Use log-only mode while you tune a new policy.

Only decisions other than a plain allow are recorded.

## Next steps

- [Approvals and policies](https://aicodeops.dev/docs/approvals-and-policies)
- [Roles and permissions](https://aicodeops.dev/docs/roles-and-permissions)
- [MCP servers](https://aicodeops.dev/docs/mcp-servers)

## Frequently asked questions

### Does the order of my rules matter?

No. Every matching rule is considered and the strictest decision wins, so adding a rule can never loosen an earlier one.

### Do policies limit what people can do?

No. Policies govern what AI sessions may do. What a person may do is set by their role.

### Can I test a policy without blocking anyone?

Yes. Choose Switch to log only. Rules are still evaluated and every decision is recorded, but nothing is blocked or held.
