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

# Agnes policies

> Author, edit, version, and ship the combined policies that drive POST /api/v1/analyze/.

A **combined policy** (also called an *Agnes policy*) is the JSON
document the [Agnes Analyzer](/concepts/combined-analyzer) executes. It
names which analyzers run, in what order, and what terminates the
pipeline.

This page is the *operational* reference for combined policies — CRUD,
slugs, versioning, defaults. The *semantic* reference (execution plan,
termination rules) is on
[The Agnes Analyzer](/concepts/combined-analyzer).

## Lifecycle

```mermaid theme={null}
flowchart LR
    Draft[Author / dashboard] --> Save[Save policy]
    Save --> Default[Mark as is_default?]
    Default -->|Yes| Inbound[Used when no policy_slug provided]
    Default -->|No| Slug[Referenced by slug from SDK / app]
    Save --> Audit[Audit log entry]
    Save --> Edit[Edit / clone]
    Edit --> Save
    Save --> Delete[Delete]
```

Policies are **tenant-scoped**. Two tenants can have different policies
under the same slug; an API key for tenant A can never reach tenant B's
policies.

## Where they live

* **In the dashboard** at
  [`agnes.lasscyber.com/protection/policies`](https://agnes.lasscyber.com/protection/policies).
  Schema-driven editor with full coverage of analyzer parameters,
  metric thresholds, and termination signals.
* **In code** via the SDKs — see
  [`PolicyBuilder`](/sdks/python#build-policies-in-code).
* **Via raw API** — `GET / POST / PUT / DELETE /api/v1/policies/`. See
  the auto-generated [API reference](/api-reference/overview).

## Built-in policies

Every new tenant inherits three defaults so you can call `analyze`
immediately without authoring anything:

| Slug                 | `is_default`   | Purpose                                                                                                                                |
| -------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `default-inbound`    | Yes (inbound)  | Strict guard for user prompts before they reach your LLM. Strong termination on prompt injection / safety / SDP / URL / YARA findings. |
| `default-outbound`   | Yes (outbound) | Same analyzers reordered to weight safety + SDP + URL on the way back to your user.                                                    |
| `default-permissive` | No             | Same analyzers but every termination rule is `proceed_to_next_step`. Useful for shadow rollouts.                                       |

The `is_default` flag is **per direction**: each tenant has at most one
default-inbound and one default-outbound. The `guard()` helper in both
SDKs auto-flips between them when you call `check_input` /
`check_output`.

You can clone any of these defaults into a custom policy and adjust:

<CodeGroup>
  ```python Python theme={null}
  agnes = Agnes()
  default = agnes.policies.get(slug="default-inbound")
  clone = default.copy(deep=True)
  clone.name = "Inbound (strict)"
  clone.slug = "inbound-strict"
  clone.is_default = False
  # ... tighten thresholds ...
  agnes.policies.create(clone)
  ```

  ```typescript TypeScript theme={null}
  const agnes = new Agnes();
  const def = await agnes.policies.get({ slug: "default-inbound" });
  await agnes.policies.create({
    ...def,
    name: "Inbound (strict)",
    slug: "inbound-strict",
    isDefault: false,
  });
  ```
</CodeGroup>

## Schema

The full schema lives in
[`api/models/config_schema.py`](https://github.com/lasscyber/agnes-docs/tree/main/policy-fixtures);
the auto-generated [API reference](/api-reference/overview) renders the
JSON Schema. The fields you care about most:

| Field                    | Purpose                                                                           |
| ------------------------ | --------------------------------------------------------------------------------- |
| `name`                   | Human-readable display name.                                                      |
| `slug`                   | Stable, URL-safe identifier. SDK `policy=` lookups use this.                      |
| `description`            | One-paragraph summary. Surfaced in the dashboard list.                            |
| `is_default`             | Marks this as the tenant default for its direction.                               |
| `available_analyzers`    | Array of `{ name, params }` declaring which analyzers may run.                    |
| `execution_plan`         | Array of steps, each with `type` (`sequential` / `asynchronous`) and `analyzers`. |
| `termination_conditions` | Per-analyzer rules: output match, thresholds, logical operator, on-match action.  |
| `default_telemetry`      | When `true`, sums analyzer cost into the response's aggregated metrics.           |

## Versioning

Combined policies are **not** strictly versioned today. Each `PUT`
overwrites the existing record. The pattern we recommend:

1. Treat policy *slugs* as your version handle. Ship `inbound-strict-v1`
   and `inbound-strict-v2` side by side; flip your callers when you are
   ready.
2. Use the analyzer log to monitor decisions before promoting a new
   slug to `is_default`.
3. Never edit `default-inbound` / `default-outbound` directly — clone
   them and rename the clone before changing thresholds. The defaults
   are reset to the shipped values on tenant re-provisioning.

A first-class versioning surface (immutable revisions, blue-green
rollout, a `policy_version` field on responses) is on the roadmap. If
you need it, talk to [`sales@lasscyber.com`](mailto:sales@lasscyber.com).

## Importing and exporting

The dashboard policy editor exposes **Export** and **Import** buttons
that round-trip the policy as JSON. Import preserves `name`, `slug`,
`description`, `available_analyzers`, `execution_plan`, and
`termination_conditions`; it ignores `id`, `tenant_id`, and timestamps
because those are server-managed.

The same JSON imports cleanly via `agnes.policies.create(...)` in both
SDKs.

## Permissions

Per the [role matrix](/administration/roles-and-permissions):

| Role   | Read | Create / update | Delete |
| ------ | ---- | --------------- | ------ |
| Owner  | Yes  | Yes             | Yes    |
| Admin  | Yes  | Yes             | Yes    |
| Member | Yes  | Yes             | Yes    |
| Viewer | Yes  | No              | No     |

Members can create and delete policies — combined policies are
considered first-class application configuration, not admin
infrastructure.

## Common patterns

* **One inbound policy per product surface.** A consumer chatbot, an
  internal copilot, and a compliance-controlled workflow probably want
  three different inbound policies, even if they share most analyzers.
* **Outbound policies should be stricter on safety + SDP, looser on
  prompt injection.** The classifier overfires on quoted user text in
  outputs.
* **Use `default-permissive` for shadow rollouts.** Run the policy you
  intend to ship in `proceed_to_next_step` mode for a week; review the
  analysis log; promote.

## Next

* [The Agnes Analyzer](/concepts/combined-analyzer) — execution plan
  and termination rules.
* [API reference](/api-reference/overview) — `GET/POST/PUT/DELETE /api/v1/policies/`.
* [Sandbox mode](/testing/sandbox-mode) — exercise policies in CI
  without billing.
