> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mnemom.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy Engine

> Governance-as-code: capability mappings, forbidden rules, and enforcement modes, all declared in the alignment card's capabilities + enforcement sections

<Note>
  The Policy Engine is the always-on part of **[CLPI](/concepts/clpi)** — Mnemom's governance layer built on top of alignment cards, which also covers violation reclassification/trust recovery and fleet intelligence (most of which are separately-entitled capabilities).
</Note>

The policy engine translates [Alignment Card](/concepts/alignment-cards) declarations into enforceable rules over concrete tools. An alignment card says an agent may perform `web_fetch`. The `capabilities` section of the same card says `web_fetch` means `mcp__browser__navigate` and `mcp__browser__click` — but not `mcp__filesystem__delete`. The card declares intent. The `enforcement` section enforces it.

<Note>
  **Policy is part of the alignment card, not a separate artifact.** The `capabilities`, `enforcement`, and per-capability `forbidden` rules live as sections of the unified card. There is no standalone policy YAML file, no `PUT /v1/agents/:id/policy` endpoint, and no `mnemom policy` CLI group. Use `mnemom card evaluate` + `PUT /v1/alignment/agent/{id}` instead. See the [policy management guide](/guides/policy-management) for the customer workflow.
</Note>

<Note>
  The policy engine does **not** have its own on/off/enforce switch. It checks tool usage against the card's `capabilities` + `enforcement` sections, but whether a violation is logged or blocked is decided by the card's top-level `autonomy_mode` (the same switch documented in [Enforcement Modes](/gateway/enforcement)) — `off` skips policy evaluation entirely, `observe` and `nudge` both log without blocking, and `enforce` blocks on `critical`/`high` violations. There's a separate, genuinely independent switch — `integrity_mode` — for the values/conscience (AIP) pipeline, but there is no third, policy-specific mode field on the card. A legacy `enforcement.mode` (or `default_mode`) key is accepted on input for backward compatibility but is dropped during composition and has no effect on a canonical card — `autonomy_mode` is authoritative.
</Note>

## How the engine reads the card

The policy engine reads three sections of the canonical (composed) alignment card:

| Section | Purpose |
| - | - |
| `capabilities` | Bridge card-level semantic actions (`web_fetch`, `read_file`) to concrete tool glob patterns (`mcp__browser__*`) |
| `enforcement.forbidden_tools` | Tools that are always blocked, regardless of mappings |
| `enforcement` (top-level knobs) | Fallback behavior for unmatched tools — `allow_unmapped_tools`, `grace_period_hours` |
| `autonomy_mode` (card top-level) | Whether an evaluated violation is skipped, logged, or blocked — see [Enforcement modes](#enforcement-modes) below |

Two optional card sections extend the model:

| Section | Purpose |
| - | - |
| `autonomy.escalation_triggers` | Conditions that trigger escalation regardless of individual tool verdicts |
| `autonomy.max_autonomous_value` | Currency-denominated ceiling on autonomous actions |

The full normative schema for these sections is at [/specifications/alignment-card-schema](/specifications/alignment-card-schema).

### Example excerpt of a card's policy sections

```yaml theme={null}
# ... (values, principal, autonomy sections omitted) ...

capabilities:
  web_browsing:
    description: "Browser-based research and navigation"
    tools:
      - "mcp__browser__*"
    required_actions:
      - web_fetch
      - web_search

  file_reading:
    tools:
      - "mcp__filesystem__read*"
      - "mcp__filesystem__list*"
    required_actions:
      - read_file

enforcement:
  mode: warn                      # off | warn | enforce
  allow_unmapped_tools: false     # true = allow, false = deny (no card-level "warn" state)
  grace_period_hours: 24
  forbidden_tools:
    - pattern: "mcp__filesystem__delete*"
      reason: "File deletion not permitted"
      severity: critical
    - pattern: "mcp__shell__*"
      reason: "Shell execution not permitted"
      severity: high
```

## Three evaluation contexts

The same `capabilities` + `enforcement` sections are evaluated at three stages, each with different inputs and consequences.

<Tabs>
  <Tab title="CI/CD (Static)">
    ### CI/CD evaluation

    Static evaluation runs in pipelines before deployment. It validates the card against the unified schema and evaluates its policy sections against a declared tool list.

    **Commands:**

    ```bash theme={null}
    # Validate the card (schema + structure)
    mnemom card validate card.yaml

    # Evaluate the card's policy against a tool list
    mnemom card evaluate card.yaml --tools mcp__browser__navigate,mcp__slack__post_message
    ```

    **What it checks:**

    * Card YAML conforms to the unified schema (capability glob validity, enforcement-mode enums, forbidden-rule structure).
    * Capability `required_actions` reference actions that exist in `autonomy.bounded_actions`.
    * Each tool in the `--tools` list matches a capability, hits a forbidden rule, or falls through to the `allow_unmapped_tools` default.
    * Coverage report identifies card actions with no backing capability mapping.

    **Use case:** pre-deploy gates. See the [CI/CD policy gates guide](/guides/ci-cd-policy-gates) for GitHub Actions + GitLab CI templates.
  </Tab>

  <Tab title="Gateway (Live)">
    ### Gateway evaluation

    Live evaluation runs in real-time as requests pass through the Mnemom gateway. The policy engine extracts tool names from the request body, checks each tool against the agent's canonical card, and returns a verdict.

    **How it works:**

    1. Request arrives at the gateway.
    2. Gateway reads the canonical alignment card (cached, 5-min TTL).
    3. Each tool in the request is checked against `enforcement.forbidden_tools` first.
    4. Remaining tools are matched against `capabilities[*].tools` globs.
    5. Unmatched tools fall through to `enforcement.allow_unmapped_tools`.
    6. A verdict is returned via the `X-Policy-Verdict` response header.

    **Verdict headers:**

    | Header Value | Meaning |
    | - | - |
    | `X-Policy-Verdict: pass` | All tools passed policy checks |
    | `X-Policy-Verdict: warn` | One or more tools triggered warnings (logged, not blocked) |
    | `X-Policy-Verdict: fail` | One or more tools violated policy (blocked in enforce mode) |

    **Enforcement interaction:** the card's top-level `autonomy_mode` determines the gateway response (`observe` and `nudge` both resolve to the `warn` row below):

    | `autonomy_mode` | `pass` | `warn` | `fail` |
    | - | - | - | - |
    | `off` | No evaluation | No evaluation | No evaluation |
    | `observe` / `nudge` | Allow | Allow + log | Allow + log |
    | `enforce` | Allow | Allow + log | Gated same-turn on both transports: HTTP 403 (non-streaming); gated before delivery (streaming, adds latency) |
  </Tab>

  <Tab title="Observer (Post)">
    ### Observer evaluation

    Post-action evaluation runs after an action completes. It analyzes what actually happened against what the card expected.

    **What it detects:**

    * **card\_gap violations** — tools the agent used successfully but that are not represented in any capability mapping. These are tools that should be in the card but are not.
    * **Frequency anomalies** — tools used at rates that exceed expected patterns.
    * **New tool discovery** — tools appearing for the first time, subject to grace-period handling.

    **Feeds into reclassification:** observer findings feed the reclassification pipeline at `POST /v1/agents/{id}/reclassify`. A `card_gap` detection is a candidate for reclassification + an amendment to the card's `capabilities` section — see [Trust Recovery](/guides/trust-recovery).

    **Feeds into proving:** when the gateway's policy evaluation detects `card_gap` signals alongside a `boundary_violation`, [ZK proving is deferred](/protocols/aip/verifiable-verdicts#deferred-proofs) instead of immediately dispatched to GPUs. This prevents stale alignment cards from driving up proving costs during rapid iteration.
  </Tab>
</Tabs>

## Capability mapping

Capability mappings are the core of the card's policy sections. They bridge the gap between what the card declares (abstract actions like `web_fetch`) and what agents actually invoke (concrete tool names like `mcp__browser__navigate`).

### Structure

Each capability has a name, a list of tool glob patterns, and a list of card actions it satisfies:

```yaml theme={null}
capabilities:
  web_browsing:
    tools:
      - "mcp__browser__navigate"
      - "mcp__browser__click"
      - "mcp__browser__screenshot"
    required_actions:
      - web_fetch
      - web_search

  database_read:
    tools:
      - "mcp__postgres__query"
      - "mcp__postgres__list_tables"
    required_actions:
      - read_data
```

### Glob patterns

Tool patterns support standard glob syntax for flexible matching:

| Pattern | Matches |
| - | - |
| `mcp__browser__*` | All browser tools (`navigate`, `click`, `screenshot`, etc.) |
| `mcp__filesystem__read*` | `read_file`, `read_directory`, `read_metadata` |
| `mcp__*__list*` | Any MCP server's list operations |
| `custom_tool_v?` | `custom_tool_v1`, `custom_tool_v2`, etc. |

<Tip>
  Start with broad globs during initial card development, then tighten them as you understand which specific tools your agent uses. A mapping like `mcp__browser__*` is fine for week one. By month two, enumerate the specific tools.
</Tip>

### How matching works

When the policy engine evaluates a tool, it follows this order:

1. **Forbidden check:** does the tool match any `enforcement.forbidden_tools[].pattern`? If yes, the tool is a violation regardless of capability mappings.
2. **Capability match:** does the tool match any `capabilities[*].tools` glob? If yes, the tool is allowed and mapped to the corresponding card actions.
3. **Default fallback:** if neither forbidden nor mapped, apply `enforcement.allow_unmapped_tools`.

A tool can match multiple capabilities. This isn't an error — it means the tool satisfies multiple card actions (e.g., a file-read tool satisfying both `read_file` and `read_source_code`).

## Enforcement modes

Policy evaluation always runs against the card's `capabilities` + `enforcement` sections, but what happens to a violation is governed by the card's top-level `autonomy_mode` — there is no separate policy-specific mode field on a canonical card:

<CardGroup cols={3}>
  <Card title="autonomy_mode: observe / nudge" icon="triangle-exclamation">
    Violations are evaluated and logged but never block the request. `X-Policy-Verdict: warn` header returned. **`observe` and `nudge` map to the same policy behavior** — CLPI does not yet render a distinct nudge annotation for policy violations.
  </Card>

  <Card title="autonomy_mode: enforce" icon="ban">
    `critical`/`high` violations block the request, same-turn on both transports. `X-Policy-Verdict: fail` header returned. HTTP 403 for non-streaming requests; streaming responses are gated before delivery (which adds latency). Lower-severity violations still only warn.
  </Card>

  <Card title="autonomy_mode: off" icon="power-off">
    Skip policy evaluation entirely. No `X-Policy-Verdict` header. No performance overhead.
  </Card>
</CardGroup>

<Note>
  A card that predates this cutover may still carry a legacy `enforcement.mode` (or `default_mode`) field. It is read only as a fallback when `autonomy_mode` is absent from the canonical card, and it is never emitted on a newly composed canonical card — set `autonomy_mode` instead.
</Note>

### Relationship to the other master switches

| System | Master switch | What it checks | Verdict source |
| - | - | - | - |
| **Action-policing alignment + policy enforcement** | `autonomy_mode` (alignment card, top-level) | Tool calls against the bounded-action envelope **and** against the card's `capabilities`/`enforcement` policy sections | CLPI tool-use policy + observer trace verification |
| **Values-policing alignment** | `integrity_mode` (alignment card, top-level) | Agent behavior against card values + conscience | AIP integrity checkpoints + drift detection |
| **Content screening** | `mode` (protection card, top-level) | Content on each enabled surface — inbound message, tool results carried by the same request, tool calls, outbound response | [Safe House](/concepts/safe-house) front door + back door |

There are two genuinely independent card-level master switches — `autonomy_mode` and `integrity_mode` — plus the protection card's own `mode`. Policy enforcement is not a third independent switch: it shares `autonomy_mode` with action-policing alignment, so the two always move together. Both `autonomy_mode`-driven checks and the `integrity_mode` check are surfaced in the [conscience timeline](/gateway/enforcement) and [observability exports](/guides/observability).

The policy engine polices *tool calls* — what the agent asks to run. It does not police what a tool hands back. That is the protection card's job, and it happens in the same request: the front door screens each `tool_result` the request carries and withholds or decorates it before the body is forwarded, rather than leaving it for a later turn. See [When the front door runs](/concepts/safe-house#when-the-front-door-runs).

## Forbidden rules

`enforcement.forbidden_tools` defines tools that must never be used, regardless of capability mappings. They're always checked first in the evaluation pipeline.

```yaml theme={null}
enforcement:
  forbidden_tools:
    - pattern: "mcp__filesystem__delete*"
      reason: "File deletion not permitted"
      severity: critical
    - pattern: "mcp__shell__*"
      reason: "Shell execution not permitted"
      severity: high
    - pattern: "mcp__*__drop_table"
      reason: "Table deletion not permitted"
      severity: critical
    - pattern: "mcp__email__send_bulk*"
      reason: "Bulk email sending restricted"
      severity: medium
```

Each rule has three fields:

| Field | Type | Description |
| - | - | - |
| `pattern` | string (glob) | Tool name pattern to match |
| `reason` | string | Human-readable explanation for auditing |
| `severity` | enum | `critical`, `high`, `medium`, or `low` |

<Note>
  Policy `enforcement.forbidden_tools` rules complement alignment card `autonomy.forbidden_actions`. Card forbidden actions declare intent ("this agent must never delete files"). Policy forbidden rules enforce that intent at the tool level ("block all tools matching `mcp__filesystem__delete*`"). Both are checked — card-level by alignment enforcement, tool-level by policy enforcement.
</Note>

## Unmapped tool handling

When a tool does not match any capability or forbidden rule, `enforcement.allow_unmapped_tools` determines what happens. It is a boolean, not a three-state field — the card itself can only say "let it through" or "deny it":

```yaml theme={null}
enforcement:
  allow_unmapped_tools: false     # default: false (deny)
  grace_period_hours: 24
```

Severity for an unmapped-tool denial is derived, not configured: a denied unmapped tool is always logged at `high` severity (it's a hard violation); an allowed one is `low` (informational only). There's no card field to change this.

### Unmapped tool actions

| `allow_unmapped_tools` | Resulting action | Behavior |
| - | - | - |
| `false` (or the field omitted) | `deny` | Treat the unmapped tool as a violation (severity `high`). Blocked in enforce mode. **This is the default** — an omitted field resolves to `deny`, not `allow`. |
| `true` | `allow` | Silently permit the tool (severity `low`, informational only). No violation raised. |

### Choosing the right default

<Tabs>
  <Tab title="Early development">
    Set `allow_unmapped_tools: true` while tool sets are still evolving, to avoid noise from a constantly changing tool inventory.
  </Tab>

  <Tab title="Mature / production card">
    Leave `allow_unmapped_tools` at its default (`false`/deny) once the card is stable. Every tool the agent uses should be explicitly mapped in `capabilities` or explicitly listed in `forbidden_tools`.
  </Tab>
</Tabs>

## Grace period

New tools appear when agents gain new MCP server connections or when tool providers add capabilities. The grace period prevents these newly discovered tools from immediately becoming violations.

```yaml theme={null}
enforcement:
  grace_period_hours: 24
```

**How it works:**

1. The policy engine tracks when each tool is first seen via `tool_first_seen` records.
2. When an unmapped or forbidden tool is encountered, the engine checks how long ago it was first seen.
3. If the tool was first seen within the grace period window, the violation is **downgraded to a warning** (the verdict drops from `fail` to `warn`), and the request proceeds. Under enforce mode, this means the request is **not blocked**.
4. After the grace period expires, the tool falls back to the configured `allow_unmapped_tools` result (or its forbidden severity, for forbidden-pattern matches).

The window is per-(agent, tool): each agent's first observation of each tool starts its own clock. The clock cannot be back-dated.

This gives operators time to amend the card's `capabilities` section after adding new tools or MCP servers, without immediately triggering violations in enforce mode.

<Warning>
  **Security implication.** With the default 24h grace, brand-new tools — including ones introduced by an attacker via prompt injection, MCP server compromise, or tool-name overlap — get a 24-hour pass on enforce mode. Mature agents with stable tool inventories aren't exposed; agents that add tools dynamically, run untrusted MCP servers, or accept tool definitions from user input absolutely are.

  If your threat model includes adversarial tool introduction, set `grace_period_hours: 0` on the alignment card to disable the grace path entirely. There is no API to back-date a `tool_first_seen` record, so `0` is the only way to make enforce strict from the moment a card is published. See [Enforcement § Grace period](/gateway/enforcement#grace-period-read-this-before-enabling-enforce).
</Warning>

| Use case | Recommended `grace_period_hours` |
| - | - |
| Adversarial threat model (untrusted user input, untrusted MCP servers, agents accepting tool defs from users) | **`0`** |
| Test harness / CI matrix | `0` |
| Production with stable tool inventory + mature card | `0` (no operational benefit when the tool list is stable) |
| Production with frequent tool additions, trusted operators | `24` (default) |
| Slow-cadence operational teams | `48`–`168` |

## Composition across scopes

In organizations with multiple agents, the `capabilities` and `enforcement` sections compose from platform → org → agent scopes per [card composition](/concepts/card-composition) rules. These are merged at storage time, not request time: every gateway read hits the pre-composed canonical card.

### Merge rules

| Section | Merge strategy | Effect |
| - | - | - |
| `capabilities` | Union | Agent can add new capabilities but cannot remove platform, org, or team capabilities |
| `enforcement.forbidden_tools` | Union (then exemptions applied) | Platform, org, team, and agent forbidden rules are all enforced; agent cannot subtract |
| `autonomy_mode` | Strictest wins (`enforce` > `nudge` > `observe` > `off`) | Governs policy enforcement *and* action-policing alignment together; agent can tighten, not loosen |
| `enforcement.allow_unmapped_tools` | Strictest wins — `false` (deny) beats `true` (allow) at any scope | Agent can strengthen (`true` → `false`) but cannot weaken a `false` set upstream |
| `enforcement.grace_period_hours` | Min across scopes | The shortest grace window set at any scope wins |
| `autonomy.escalation_triggers` | Union | Triggers from every scope are evaluated |

### Strengthening enforcement

Upstream scopes act as a floor; a downstream scope can only move in the stricter direction:

```
true  → false                          (allow_unmapped_tools; false = deny)
off → observe/nudge → enforce          (autonomy_mode)
```

If the org sets `allow_unmapped_tools: true`, an agent can override it to `false` (stricter, i.e. deny) but cannot force a `false` set upstream back to `true`.

### Transaction guardrails

Transaction-scoped cards can further restrict the composed enforcement via intersection semantics. A transaction guardrail can only narrow what's permitted — never expand it.

```yaml theme={null}
# Transaction-level override: restrict to read-only tools for this operation
transaction_guardrails:
  allowed_capabilities:
    - file_reading
    - database_read
  # All other capabilities are denied for this transaction
```

## Coverage report

Every `mnemom card evaluate` run produces a coverage report that quantifies how well the card's `capabilities` section maps to its `autonomy.bounded_actions`. This identifies gaps between what the card declares and what the policy actually covers.

### Coverage metrics

| Metric | Description |
| - | - |
| `total_card_actions` | Number of actions declared in the card's `autonomy.bounded_actions` |
| `mapped_card_actions` | Number of card actions covered by at least one capability |
| `unmapped_card_actions` | Card actions with no corresponding capability |
| `coverage_pct` | `mapped_card_actions / total_card_actions * 100` |

### Example output

```json theme={null}
{
  "coverage": {
    "total_card_actions": 8,
    "mapped_card_actions": 6,
    "unmapped_card_actions": 2,
    "coverage_pct": 75.0,
    "unmapped_actions": [
      "send_notification",
      "generate_report"
    ],
    "mapped_actions": {
      "web_fetch": ["web_browsing"],
      "web_search": ["web_browsing"],
      "read_file": ["file_reading"],
      "read_data": ["database_read"],
      "write_data": ["database_write"],
      "compare": ["data_analysis"]
    }
  }
}
```

<Warning>
  A coverage percentage below 100% means some card actions have no backing capability mapping. Tools implementing those actions will fall through to `enforcement.allow_unmapped_tools`. Aim for 100% coverage in production cards.
</Warning>

### Using coverage in CI/CD

```bash theme={null}
# Evaluate a card and fail if any card action is unmapped (sub-100% coverage)
mnemom card evaluate \
  card.yaml \
  --tools mcp__browser__navigate,mcp__filesystem__read_file \
  --strict

# Exit code 1 on warnings (any unmapped action) as well as failures
```

`card evaluate` always prints the coverage percentage and lists unmapped actions. Coverage gating is binary: without `--strict` only hard policy violations exit non-zero; with `--strict` any unmapped action (i.e. coverage below 100%) is treated as a warning that also exits `1`. This integrates naturally into pre-deploy gates: a card change that introduces an unmapped action blocks the merge. See [CI/CD policy gates](/guides/ci-cd-policy-gates) for the full pipeline template.

## Putting it together

Here's the full alignment card for a research agent that can browse the web and read files but cannot delete anything or execute shell commands:

```yaml theme={null}
card_version: unified/2026-04-15
card_id: ac-research-agent-v2
agent_id: mnm-your-agent-id
issued_at: "2026-03-04T00:00:00Z"
autonomy_mode: enforce   # governs both bounded-action policing and the policy sections below

principal:
  type: human
  relationship: delegated_authority

values:
  declared: [transparency, harm_prevention, accuracy]

autonomy:
  bounded_actions:
    - inference
    - web_fetch
    - web_search
    - read_file
    - search
  forbidden_actions:
    - delete_files
    - execute_shell
    - exfiltrate_data

capabilities:
  web_browsing:
    description: "Browser-based research and navigation"
    tools:
      - "mcp__browser__navigate"
      - "mcp__browser__click"
      - "mcp__browser__screenshot"
      - "mcp__browser__evaluate_script"
    required_actions: [web_fetch, web_search]

  file_reading:
    tools:
      - "mcp__filesystem__read_file"
      - "mcp__filesystem__list_directory"
    required_actions: [read_file]

  search:
    tools:
      - "mcp__search__query"
      - "mcp__search__suggest"
    required_actions: [search]

enforcement:
  allow_unmapped_tools: false
  grace_period_hours: 24
  forbidden_tools:
    - pattern: "mcp__filesystem__delete*"
      reason: "File deletion not permitted for research agents"
      severity: critical
    - pattern: "mcp__filesystem__write*"
      reason: "File writing not permitted for research agents"
      severity: high
    - pattern: "mcp__shell__*"
      reason: "Shell execution never permitted"
      severity: critical

audit:
  trace_format: ap-trace-v1
  retention_days: 90
```

## Limitations

* Policy evaluation adds latency to gateway requests (typically under 5 ms for cards with fewer than 100 capability patterns).
* Glob patterns match tool names only, not tool arguments. A tool can be permitted by policy but still violate alignment constraints based on how it's called.
* Grace periods are tracked per-agent, not per-card-version. Updating a card doesn't reset grace-period timers for previously seen tools.
* Coverage reports require a valid `autonomy.bounded_actions` list. Agents with an empty envelope get a coverage report with 0% coverage (no denominator).

## Policy engine and AEGIS Managed Rules

The Policy Engine is the always-on layer of **[CLPI](/concepts/clpi)**; AEGIS [Managed Rules](/concepts/managed-rules) are a separate (but composable) layer. When a Managed Rule promotes, the gateway loads it via a tiered, multi-layer read substrate with independent fallback tiers. The policy engine still enforces card-defined capability mappings; the Managed Rule adds detection thresholds that screen the inputs and outputs the policy engine then allows or denies. Both compose through the same [cards composition primitive](/concepts/aegis) — the recipe (detection content) and the rule (control-plane state) flow into the cards cascade Platform → Org → Team → Agent under strictest-wins composition.

## See also

* [AEGIS Managed Rules](/concepts/managed-rules) — the signed detection rule set that composes with policy
* [Alignment Card Schema](/specifications/alignment-card-schema) — normative schema for the unified alignment card (including capabilities + enforcement sections)
* [Policy Management Guide](/guides/policy-management) — step-by-step guide to authoring and deploying the `capabilities` + `enforcement` sections
* [CI/CD Policy Gates](/guides/ci-cd-policy-gates) — `mnemom card evaluate` in GitHub Actions and GitLab CI
* [Card Lifecycle](/concepts/card-lifecycle) — how alignment cards evolve and interact with policy
* [Card Composition](/concepts/card-composition) — how platform / org / agent scopes merge
* [Enforcement Modes](/gateway/enforcement) — the full `autonomy_mode` / `integrity_mode` verdict ladder, including how policy enforcement fits in


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