---
title: "Gateway Policies"
description: "Allow or deny each agent request with gateway plugins, and see how global and project configurations combine."
source: "Guardian Platform"
---
The Agent Gateway enforces your rules on agent traffic through plugins. A plugin is a policy check the gateway runs on each request: it looks at who is calling, which project they belong to, and what they are sending, then allows the request, denies it, or records a finding. You choose which plugins run, where they run, and whether they block or only observe.

Gateway policies are separate from the compliance policies you apply to projects in Guardian. For those, see [Policies](./policies.mdx).

## Hook stages

Each plugin runs at a hook stage, a fixed point in the life of a request. Plugins at the same stage run in a set order. Guardian shows each stage by name; configuration files use the hook ID in parentheses.

| Stage                                   | When it runs                                                                     | What typically runs there                                                                                                                      |
| --------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Request Start (`request.start`)         | As soon as a request arrives, before the gateway verifies the agent's signature  | Early checks on the raw request. Set in the global configuration only.                                                                         |
| Project Bootstrap (`project.bootstrap`) | After the gateway verifies the agent and identifies the project it is working in | Project trust and project membership checks                                                                                                    |
| Before Proxy (`proxy.pre`)              | After verification, before the request goes to the model provider                | Agent certification, authorization, verifiable credentials, OPA policy, and configuration validation. This is the main place to allow or deny. |
| After Proxy (`proxy.post`)              | When the provider's response starts, before it reaches the agent                 | Checks on the response, usually custom plugins                                                                                                 |
| Request End (`request.end`)             | After the response completes, in the background                                  | VirusTotal scan and intent monitoring. These never slow down or block the agent.                                                               |

## Observe and enforce

Every plugin entry runs in one of two modes. In a configuration file they are written `observability` and `enforcement`.

- **Observe** (`observability`): the plugin records its decision, but the request always goes through. If the plugin itself fails, the request still goes through and the error is recorded.
- **Enforce** (`enforcement`): a deny blocks the request and the agent receives an error. If the plugin itself fails, the request is blocked (fail closed).

Roll out new policy observe-first:

1. Add the plugin in observe mode.
2. Let normal agent traffic run for a while and review what the plugin would have denied in the [Audit Trail](./gateway-audit-trail.mdx).
3. Adjust the rules until the would-deny results match your intent.
4. Switch the entry to enforce mode and apply the change.

Some plugins run in observe mode only because they cannot block by design (see the catalog below).

Project membership and project trust are the exception in the other direction. Their entries must always be written with `mode = "enforcement"`; the CLI rejects anything else. To roll those two out observe-first, set `mode = "observe"` inside the plugin's own settings (`[deployment.entries.config]`), then switch it to `"enforce"` when you are ready.

## Global and project configurations

A configuration is the list of plugins that run, with each plugin's stage, order, mode, and settings. Project configurations only take effect once your administrator has enabled project context on the gateway; the global configuration applies either way. Configurations are layered:

- **Global configuration.** The organization-wide floor, set by the platform admin. It runs on every request through the gateway, whatever the project.
- **Project configuration.** An additive layer set by a project admin. It adds plugins for one project's traffic.

The effective policy for a project is the union of both layers. At each stage the global entries run first, then the project entries. A project can add checks but can never remove, disable, or reorder the global floor. A project with no configuration of its own runs under the global floor only.

Project traffic is admitted only when the effective chain contains a project membership check that counts. A project's own membership entry counts whatever its settings say. A membership entry in the global floor counts only when it can deny: its settings must leave `mode` at `"enforce"` and `membership_required` at `true`, which are the defaults when you omit them. A global entry set to `mode = "observe"` or `membership_required = false` does not count, and every project without its own entry is denied. So either put an enforcing membership entry in the global floor, or give each project its own entry (which can start in observe mode).

Every change creates a new, signed, versioned configuration, so you can see what changed and roll back. To see what is in effect for a project, open the project in Guardian and, in the project sidebar, select [Plugin Configurations](./plugin-configurations.mdx). The page shows the global and project layers, the plugins at each stage, and the configuration history. It is read-only; you change configurations with the `guardian-plugin` CLI, described in [Policy as Code](./policy-as-code.mdx).

## Built-in plugins

The gateway ships with these plugins. They do nothing until a configuration includes them, and a configuration can include one only after a platform admin has registered its definition (see [Register a built-in plugin](#register-a-built-in-plugin)). Each plugin's settings are listed under [Built-in plugin settings](#built-in-plugin-settings).

| Plugin                                                   | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         | Mode                                                |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- |
| Project Membership (`builtin.project_membership`)        | Checks that the agent holds a valid membership credential for the project: trusted issuer, status, expiry, revocation, and role. Only this check can establish which project a request belongs to.                                                                                                                                                                                                                                                                                                                                                                                   | Enforce, with an observe option in its own settings |
| Project Trust (`builtin.project_trust`)                  | Checks that the project itself holds valid compliance evidence from a trusted issuer before membership is evaluated. Global configuration only.                                                                                                                                                                                                                                                                                                                                                                                                                                      | Enforce, with an observe option in its own settings |
| Agent Certification (`builtin.agent_certification`)      | Checks that the agent holds a current certification from a trusted issuer under the program versions you require, that the instance sending the request runs the configuration it was certified with, and that the agent still holds the certified operating profile. It refuses a request that offers a tool or MCP server, or reaches a host, that the certified operating profile excludes. A request whose agent isn't verified is always refused, even when certification isn't required. Set `max_status_age_seconds`: by default a stored check is honored however old it is. | Enforce or observe                                  |
| Authorization (`builtin.authorization`)                  | Allows or denies requests with ordered rules that match on provider, operation, method, gateway or upstream path, and agent ID.                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Enforce or observe                                  |
| Verifiable Credentials (`builtin.verifiable_credential`) | Verifies the agent's credential: signature, trusted issuer, that it was issued to this agent, and validity dates.                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | Enforce or observe                                  |
| OPA Policy (`builtin.opa_rego`)                          | Evaluates your own Rego policy against the request. See [OPA/Rego Policies](./opa-rego-policies.mdx).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Enforce or observe                                  |
| Configuration Validation (`builtin.config_validation`)   | Checks the agent's reported configuration files and permissions against rules, and flags violations on the exchange. See [Agent Configuration](./agent-configuration.mdx).                                                                                                                                                                                                                                                                                                                                                                                                           | Observe only. It never blocks a request.            |
| VirusTotal Scan (`builtin.vtscan`)                       | Hashes the agent's skill files and looks each one up on VirusTotal for known malware. A file VirusTotal has never seen is uploaded to VirusTotal for analysis.                                                                                                                                                                                                                                                                                                                                                                                                                       | Observe only, runs after the request                |
| Intent Monitoring (`builtin.intent_monitor`)             | Sends the user's messages and the agent's latest tool call to a model you choose, which judges whether the action matches what the user asked for, and flags drift.                                                                                                                                                                                                                                                                                                                                                                                                                  | Observe only, runs after the request                |

Plugins that run after the request, such as the VirusTotal scan and the intent monitor, record their results as plugin events rather than in the exchange's plugin activity. Read them through the [Control Plane API](../../reference/control-plane/api-reference/) with `GET /v1/agents/{agentId}/plugin-events`, and add `plugin_id` to see one plugin, for example `?plugin_id=builtin.intent_monitor`. Each intent monitor evaluation records whether the agent's action was `aligned` with the user's request, with a `confidence` score. Organization Owners and the users bound to the agent can read these events.

### Register a built-in plugin

A configuration that names a built-in plugin is rejected until the plugin's definition is registered with the Control Plane. A platform admin registers each built-in once by running `guardian-plugin publish` ([install it](./policy-as-code.mdx#install-the-cli)) against a `guardian.plugin.toml` that names it:

```toml
[package]
plugin_id = "builtin.authorization"
name = "authorization"
version = "v1.0.0"

[control_plane]
base_url = "https://control-plane.example.com/api"   # your Control Plane URL

[definition]
runtime = "premade"
supported_hooks = ["proxy.pre"]
```

For a built-in, publish skips the build and upload and only registers the definition, so it is safe to run again. `guardian-plugin init --template opa-rego` and `--template vtscan` write a ready manifest for those two plugins.

## Custom plugins

When the built-in plugins and OPA/Rego cannot express a rule, you can write your own plugin in Rust with the Guardian plugin SDK and compile it to WebAssembly for the `wasm32-wasip1` target. A minimal plugin that allows every request looks like this:

```rust
use guardian_plugin_sdk::{export_plugin, Decision, Request};

fn handle(_request: Request) -> Decision {
    Decision::allow()
}

export_plugin!(handle);
```

You publish the compiled plugin with `guardian-plugin publish`. The gateway only loads signed plugins, and `guardian-plugin` does not sign the artifact itself: the Control Plane signs it on upload with its [publisher signer](../control-plane/configuration.mdx#chart-values). Until your administrator configures one, publishing fails with a missing-signature error. After that, you enable a custom plugin through a configuration exactly like a built-in one, in `observability` or `enforcement` mode, at global or project scope. Publishing needs a platform admin. [Policy as Code](./policy-as-code.mdx#custom-plugin-packages) shows the manifest and build steps.

Beyond the request details the gateway passes in, a plugin can use these host capabilities:

| Capability          | What it allows                                                                             | Grant settings                                                                                                     |
| ------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| `cid.resolve`       | Read content by CID from the gateway's store, such as the agent's configuration snapshot   | `max_bytes`                                                                                                        |
| `request.body.read` | Read the full request body                                                                 | `max_bytes`                                                                                                        |
| `http.request`      | Make outbound HTTP or HTTPS requests                                                       | `allowed_url_prefixes`, `allowed_methods`, `timeout_ms`, `max_request_bytes`, `max_response_bytes`, `max_inflight` |
| `agent.badge.write` | Publish checks on the calling agent, shown in the [Agent Inventory](./agent-inventory.mdx) | `allowed_keys`                                                                                                     |

A capability must be both requested and granted. List it in the plugin definition's `required_capabilities`, then grant it, with all of its settings, on each configuration entry that runs the plugin. A configuration that leaves out a required grant is rejected, and the gateway refuses any capability the entry was not granted.

## Who manages what

| Task                                                                           | Who                                                                    |
| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| Set the global configuration (the organization floor), including project trust | Platform admin (in Guardian, an Organization Owner)                    |
| Register built-in plugins and publish custom plugins                           | Platform admin                                                         |
| Store plugin secrets, such as API keys                                         | Platform admin                                                         |
| Add a project configuration on top of the floor                                | Project admin for that project (a Project Owner or Organization Owner) |
| View the plugins in effect for a project                                       | Anyone who can view the project                                        |

See [Roles and Permissions](./roles-and-permissions.mdx) for how roles are assigned.

## Built-in plugin settings

Each entry's settings go in its `[deployment.entries.config]` table. Unknown keys are rejected. Where a plugin needs a capability, the entry must also grant it (see [Custom plugins](#custom-plugins) for the grant settings).

A setting marked as a secret takes a reference rather than the value itself, such as `vt_api_key = { kind = "secret_ref", name = "virustotal_api_key" }`. A platform admin stores the value under the plugin ID and that name with `POST /v1/plugins/secrets` (see [Policy as Code](./policy-as-code.mdx#plugin-api)). Guardian never shows a stored secret's value.

### Project Membership

| Setting                  | Type                                                   | Default        | Meaning                                           |
| ------------------------ | ------------------------------------------------------ | -------------- | ------------------------------------------------- |
| `trusted_issuers`        | List of `did:key` values, required                     | —              | Issuers whose membership credentials are accepted |
| `membership_required`    | Boolean                                                | `true`         | Refuse a request without a valid membership       |
| `accepted_statuses`      | List of `valid`, `expired`, `not_yet_valid`, `revoked` | `["valid"]`    | Credential statuses that pass                     |
| `enforce_expiration`     | Boolean                                                | `true`         | Check the credential's expiry                     |
| `enforce_revocation`     | Boolean                                                | `true`         | Check the credential's revocation status          |
| `max_status_age_seconds` | Integer                                                | `0` (no limit) | Oldest stored status check accepted               |
| `allowed_roles`          | List of strings                                        | Any role       | Every role the agent holds must be on this list   |
| `required_roles`         | List of strings                                        | None           | Roles the agent must hold                         |
| `mode`                   | `observe` or `enforce`                                 | `enforce`      | `observe` records the decision without denying    |

### Project Trust

| Setting                  | Type                                                   | Default        | Meaning                                                   |
| ------------------------ | ------------------------------------------------------ | -------------- | --------------------------------------------------------- |
| `trusted_issuers`        | List of `did:key` values, required                     | —              | Issuers whose project compliance credentials are accepted |
| `trust_required`         | Boolean                                                | `true`         | Refuse a project without valid compliance evidence        |
| `required_policy_cids`   | List of `urn:cid` values                               | Any policy     | Policies the evidence must cover                          |
| `policy_match`           | `any` or `all`                                         | `any`          | Whether one or every required policy must be covered      |
| `accepted_statuses`      | List of `valid`, `expired`, `not_yet_valid`, `revoked` | `["valid"]`    | Credential statuses that pass                             |
| `enforce_expiration`     | Boolean                                                | `true`         | Check the credential's expiry                             |
| `enforce_revocation`     | Boolean                                                | `true`         | Check the credential's revocation status                  |
| `max_status_age_seconds` | Integer                                                | `0` (no limit) | Oldest stored status check accepted                       |
| `mode`                   | `observe` or `enforce`                                 | `enforce`      | `observe` records the decision without denying            |

### Agent Certification

For what a certification covers, how agents earn one, and a rollout example, see [Agent Certifications](./agent-certifications.mdx#enforcing-certification-at-the-agent-gateway).

Needs the `request.body.read` grant with `max_bytes` of at least `33554432` (32 MiB, the gateway's default request body limit), and an `agent.badge.write` grant whose `allowed_keys` include `operating_profile`. A configuration without them is rejected. If your gateway's request body limit is raised, raise `max_bytes` to match: a request larger than the grant can't be checked, and is refused.

| Setting                       | Type                                                   | Default        | Meaning                                                                                                                                                      |
| ----------------------------- | ------------------------------------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `trusted_issuers`             | List of `did:key` values, required                     | —              | Issuers whose certifications are accepted                                                                                                                    |
| `certification_required`      | Boolean                                                | `true`         | Refuse an agent with no certification under a required program. `false` admits it, and records rather than refuses a request its certification doesn't cover |
| `required_program_cids`       | List of `urn:cid` values                               | Any program    | Program versions the certification must be under                                                                                                             |
| `program_match`               | `any` or `all`                                         | `any`          | Whether one or every required program must be covered                                                                                                        |
| `accepted_statuses`           | List of `valid`, `expired`, `not_yet_valid`, `revoked` | `["valid"]`    | Certification statuses that pass                                                                                                                             |
| `enforce_expiration`          | Boolean                                                | `true`         | Check the certification's expiry                                                                                                                             |
| `enforce_revocation`          | Boolean                                                | `true`         | Check the certification's revocation status                                                                                                                  |
| `require_configuration_match` | Boolean                                                | `true`         | Refuse a request from an instance that doesn't run the certified configuration, or from an agent that no longer holds the certified operating profile        |
| `max_status_age_seconds`      | Integer                                                | `0` (no limit) | Oldest stored status and operating-profile check accepted                                                                                                    |
| `enforce_profile_exclusions`  | Boolean                                                | `true`         | Refuse a request that offers what the certified operating profile excludes. `false` records it without refusing                                              |

Each instance of an agent signs its requests with its own key, and the plugin judges every request by the configuration its own state gives. A request from an instance running a configuration its certification doesn't name is refused with `agent_certification_configuration_mismatch`, and one whose state gives no configuration at all with `agent_certification_configuration_unknown`. The agent's other instances keep working. The refused instance shows a Configuration not certified badge until an entry that requires a certification admits its next request, when the entry's `agent.badge.write` grant allows the `configuration` badge. When the gateway can't read the configuration just then, the request is refused with `agent_certification_configuration_unavailable` and status 503, and can be retried. The operating profile is the agent's, declared for every instance, so it is checked for the whole agent, as the Control Plane last found it.

With `certification_required = false`, a certification that doesn't cover a request counts as none on that entry. The request is admitted as one from an agent without a certification would be, held to no operating profile, so the tools, MCP servers and hosts the certification's profile excludes aren't refused there. To have them enforced, require a certification. The plugin records why the certification didn't cover the request in its `agent_certification.configuration_reason` tag: a different configuration or operating profile, a state that gives none, a configuration it can't read just then, or an operating-profile check older than `max_status_age_seconds`. Guardian shows it in the exchange detail's **Plugin Activity** as **Treated as Uncertified**, with the reason. Such an entry never sets or clears the configuration badge, and an admission it holds to no profile leaves the operating-profile badge as it is. A certification that is revoked, expired, not yet valid or from an untrusted issuer is still refused.

Once it admits an agent, the plugin holds each request to the operating profiles named by every certification that admits it. With `require_configuration_match = false`, a certification of a configuration the agent no longer runs can still admit it, and its profile's exclusions then apply as well. That only ever adds restrictions.

Each request is checked like this:

- A model request is checked by the tools it offers, in Anthropic Messages and Message Batches, OpenAI Chat Completions and Responses, and Codex on the ChatGPT backend. A request to any other endpoint whose body names tools is refused, because its tools can't be read. So is a request offering a model provider's MCP connector that lists no allowed tools, when the profile excludes tools: list the connector's allowed tools.
- A relay request is checked by its destination host, and by the tools its body offers when the destination's path is one of those formats. A relay body that names tools in another format is refused.
- A model request is also checked by its upstream host. A `host:` rule without a port matches the host on any port. Rules match hosts as requests name them, so while a profile excludes hosts, a relay request that names its destination by an IP address the profile has no rule for is refused with `agent_certification_host_unverifiable`. Reach such hosts by name, or name the address in the profile.
- An OpenAI batch is refused when the profile excludes tools: its requests are in an input file the gateway doesn't read.

A request that offers a tool or MCP server, or reaches a host, that one of the profiles excludes is refused with `agent_certification_profile_excluded`, naming what matched and the profile rule. The agent then shows an Operating profile breach badge until a model request that an entry holds to the profile offers tools and none of them is excluded. A request that can't be checked is refused too: with `agent_certification_profile_unavailable` when the profile isn't one of the agent's versions, `agent_certification_profile_unreadable` when it no longer parses or matches its CID, and `agent_certification_tools_unreadable` when the request's tools can't be read in full. With `enforce_profile_exclusions = false`, those requests are admitted and the plugin records what it would have refused in its tags. Tools the profile doesn't declare are never refused; the agent's [Operating Profile](./operating-profiles.mdx#checking-a-profile-against-activity) page reports them.

Certify a configuration that doesn't offer what the profile excludes. Claude Code offers its built-in tools on every request, so deny an excluded one under `permissions` in its settings, such as `"deny": ["WebFetch"]`, and send the agent one request before the assessment pins the configuration, so the configuration it pins includes the rule. The settings files are part of the configuration, so a deny rule added after certification makes a new configuration that the certification doesn't name.

**Upgrading.** Upgrade in this order: the gateway, whose migrations add the tables and columns the Control Plane reads; then the Control Plane; then publish every `builtin.agent_certification` entry again with both grants; then run `guardian-plugin publish` for the plugin, which registers its new setting; then the Governance Service and Guardian. Entries written before profile enforcement lack its grants. The upgraded gateway logs a configuration warning for each one, and admits the requests whose tools it can't check against a profile, recording why, until the entry is published again with the grants. Host exclusions still apply to those entries. Set `enforce_profile_exclusions` only once every gateway is upgraded: an older gateway can't read the setting, so the entry fails every request it checks. Remove the setting before rolling a gateway back, and roll the Control Plane back with it: an older gateway can't read the checks the upgraded Control Plane stores, so it refuses every certified agent with `agent_certification_configuration_unknown` while `require_configuration_match` is on. To mark refused instances, publish the entry with `allowed_keys = ["operating_profile", "configuration"]`; an entry that allows only `operating_profile` publishes no configuration badge.

### Authorization

| Setting               | Type              | Default                                  | Meaning                                               |
| --------------------- | ----------------- | ---------------------------------------- | ----------------------------------------------------- |
| `default_effect`      | `allow` or `deny` | `allow`                                  | Decision when no rule matches                         |
| `default_status_code` | Integer           | `403`                                    | Status the agent receives on a default deny           |
| `default_code`        | String            | `policy_denied`                          | Error code on a default deny                          |
| `default_message`     | String            | `request denied by authorization policy` | Error message on a default deny                       |
| `rules`               | List of rules     | None                                     | Checked in order; the first rule that matches decides |

Each rule takes a required `effect` (`allow` or `deny`), an optional `id` recorded on the exchange, and optional `status_code`, `code`, and `message` for a deny. Its `match` table can set `provider`, `operation`, `method`, `gateway_path`, `upstream_path`, and `agent_id`, each as `{ operator = "exact" | "prefix", value = "..." }`. Every field you set must match; a rule with no `match` matches every request. `provider`, `operation`, and `method` compare without regard to case.

### Verifiable Credentials

Needs the `cid.resolve` grant.

| Setting           | Type                               | Default                  | Meaning                                               |
| ----------------- | ---------------------------------- | ------------------------ | ----------------------------------------------------- |
| `trusted_issuers` | List of `did:key` values, required | —                        | Issuers whose credentials are accepted                |
| `required`        | Boolean                            | `true`                   | Refuse a request that carries no credential           |
| `header_name`     | String                             | `X-Viper-Credential-CID` | Request header that carries the credential CID        |
| `subject_source`  | `request_signer_did`               | `request_signer_did`     | The credential must be issued to the request's signer |

### OPA Policy

| Setting            | Type             | Default | Meaning                                                        |
| ------------------ | ---------------- | ------- | -------------------------------------------------------------- |
| `entrypoint`       | String, required | —       | The `data.*` rule that returns the decision                    |
| `default_decision` | Decision         | Allow   | Decision used when the entrypoint produces no result           |
| `input_options`    | Table            | Off     | `include_body`, `include_resolved_cid`, and `cid_header_names` |

The CLI fills `modules` and `data` from the entry's `[deployment.entries.opa]` files. See [OPA/Rego Policies](./opa-rego-policies.mdx) for the input, the decision, and the grants each option needs.

### Configuration Validation

Needs the `cid.resolve` grant. The plugin checks against your organization's configuration validation rules (see [Agent Configuration](./agent-configuration.mdx)); the entry's own `rules` apply only when the gateway cannot read those.

| Setting            | Type          | Default             | Meaning                                                  |
| ------------------ | ------------- | ------------------- | -------------------------------------------------------- |
| `state_cid_header` | String        | `X-Viper-State-CID` | Request header that carries the agent's state record CID |
| `rules`            | List of rules | None                | Fallback rules, in the same shape as the organization's  |

### VirusTotal Scan

Needs the `cid.resolve` grant and an `http.request` grant that allows `GET` and `POST` to `https://www.virustotal.com`. Files are sent to VirusTotal only when it has no result for their hash, but those uploads leave your environment, so enable this plugin only for skills you can share with VirusTotal. `guardian-plugin init --template vtscan` writes an entry with these grants.

| Setting                 | Type             | Default             | Meaning                                                  |
| ----------------------- | ---------------- | ------------------- | -------------------------------------------------------- |
| `vt_api_key`            | Secret, required | —                   | Your VirusTotal API key                                  |
| `state_cid_header`      | String           | `X-Viper-State-CID` | Request header that carries the agent's state record CID |
| `rate_limit_per_minute` | Integer          | `4`                 | VirusTotal API calls per minute                          |
| `scan_timeout_hours`    | Integer          | `24`                | Accepted, but not used by the gateway in this release    |

### Intent Monitoring

Needs the `request.body.read` grant and an `http.request` grant that allows `POST` to `llm_url`. Each evaluation sends the user's messages from the request and the agent's latest tool call, with its details, to `llm_url`, so choose a model endpoint that is approved for that content.

| Setting       | Type          | Default        | Meaning                                        |
| ------------- | ------------- | -------------- | ---------------------------------------------- |
| `llm_url`     | URL, required | —              | An OpenAI-compatible chat completions endpoint |
| `llm_model`   | String        | `gpt-5.4-mini` | Model name sent with each evaluation           |
| `llm_api_key` | Secret        | None           | Sent as a bearer token to `llm_url`            |

## Related

- [Policy as Code](./policy-as-code.mdx) — validate, plan, and apply configurations with `guardian-plugin`
- [OPA/Rego Policies](./opa-rego-policies.mdx) — write your own allow and deny rules
- [Plugin Configurations](./plugin-configurations.mdx) — see the plugins in effect for a project
- [Audit Trail](./gateway-audit-trail.mdx) — review what a plugin would have denied before you enforce it
- [Associated Agents](./associated-agents.mdx) — link an agent to a project so project configurations apply to it
- [Gateway Basics](./gateway-how-it-works.mdx) — where plugins run in one request's path