Skip to content

Govern

Content safety, alerting, the audit trail, reporting, and the admin sign-in log. This is how you keep the gateway honest and prove it.


Guardrails

Where: Govern ▸ Guardrails · Who: everyone views; MANAGE_GATEWAY to manage · Editions: all (regex); Pro AI for remote AI-classifier detectors

Guardrails Policies Detectors Test PII SECRET TOXICITY competitor-names PII Request (prompt) REDACT mask: TOKEN (reversible) Response (reply) FLAG Fail posture fail-closed: on Detectors feeding this category email-regex presidio:EMAIL_ADDRESS · Pro AI
Guardrails ▸ Policies. Pick a category (left, with posture dots), set its inbound and outbound action, mask strategy, and fail posture (right), and see which detectors feed it.

Guardrails screen content in both directions: the prompt on the way in, and the model's reply on the way out. They are per-org with nothing seeded; a fresh org starts empty and the apply recommended button plants a sensible starter set through the normal create calls.

Three building blocks:

  • Category is a named bucket of sensitive content, like PII, SECRET, or a custom competitor-names. It is a free key you define, not a fixed list. A category can be marked an indicator (an IOC like an IP/domain/hash) so its matched value is kept on events for threat intel.
  • Detector is what finds the content. A REGEX detector runs in-process (a pattern plus a validator, like a Luhn check for card numbers). A REMOTE detector calls an out-of-band AI classifier: a document guard (Llama Guard / Granite / ShieldGemma: one call returns a safe/unsafe verdict) or a span analyzer (Presidio: entity offsets you can redact). Remote detectors need the Pro AI sidecars.
  • Policy maps a category to an action for a scope and direction: ALLOW, FLAG (record only), REDACT (mask the match), or BLOCK. Redaction has strategies (MASK, HASH, reversible TOKEN, PARTIAL), and each policy has a fail-closed posture (block the call if a detector cannot finish, rather than proceed with partial findings).

How a screening decision is made

Detectors find spans; the policy for the most specific scope that covers the matched category decides what happens. The actions escalate, and REDACT carries a strategy:

flowchart LR
    TXT["Text (prompt or reply)"] --> DET["Detectors for the org<br/>(regex in-process · remote AI classifier)"]
    DET -->|"no match"| PASS["Pass through"]
    DET -->|"match → category"| POL["Resolve policy<br/>(most-specific scope, this direction)"]
    POL --> ALLOW["ALLOW → pass"]
    POL --> FLAG["FLAG → pass + record"]
    POL --> REDACT["REDACT → mask the span<br/>MASK · HASH · TOKEN · PARTIAL"]
    POL --> BLOCK["BLOCK → stop the call"]
    REDACT -. "reversible TOKEN" .-> RESTORE["restored for the client at the end"]
Strategy Effect Use when
MASK Replace with a fixed mask (e.g. ****) You never need the value back
HASH Replace with a stable hash You want to correlate occurrences without the value
TOKEN Reversible placeholder, restored for the client The model needs coherent text but the value must not reach the vendor
PARTIAL Keep part (e.g. last 4 digits) A human needs to recognise it

Fail-open vs fail-closed

If a detector cannot finish scanning (for example a remote classifier times out), a fail-closed policy blocks the call rather than letting unscanned content through; a fail-open policy proceeds. Set this per policy by sensitivity: fail-closed for SECRET, perhaps fail-open for a low-stakes category.

The three tabs

  • Policies (category-centric). Pick a category and set its request and response actions, the mask strategy, and the fail-closed posture. You see the detectors feeding it and a posture dot per category.
  • Detectors (the catalogue). Enable, edit, or delete detectors. REGEX today; REMOTE for the AI classifiers.
  • Test (a dry run). A no-model pipeline that screens a prompt you type, lets you edit the model's hypothetical reply to inject what it might say, and re-screens it as the response, showing the reversible-redaction round-trip restored at the end. Nothing is sent to a model.

Tool-call arguments are never redacted

Redacting the arguments of a tool/function call would break the tool. Guardrails detect and flag or block tool-call content and surface it to the operator, but never mutate it. Plan policies accordingly.

Where guardrails run in the request

Request screening happens before routing; response screening happens after the vendor replies, including inline on streams (a match spanning two chunks is carried over, and a block stops the stream). It runs on /v1/chat/completions, /v1/responses, and /v1/messages. Internals: guardrails.


Notifications

Where: Govern ▸ Notifications · Who: members view; MANAGE_GATEWAY to manage · Editions: all

Notifications deliver governance alerts off the same event stream, per-org, over three channel types. Four tabs:

  • Channels. Create email, webhook (HMAC-signed, SSRF-safe), or in-app channels, each with a test-send; the list is paginated. An in-app channel targets org-wide (a broadcast to everyone's bell) or a chosen set of members / teams / projects, and delivers to the bell and/or email.
  • Routing. Per-scope, most-specific-first rules that map an event category to a target. A rule can fan out to an audience (a role group) and several channels at once - each becomes its own line under the trigger, toggle-able and removable on its own. The severity control adapts to the category: a min-threshold for SIEM/detection events, fixed labelled choices (e.g. All reports / Only failures) for the dedicated ones. The list is paginated by rule. Apply recommended plants a starter set.
  • Delivery log. What was sent, to which channel, and whether it succeeded.
  • Preferences. Noise controls: a dedupe cooldown and a quiet-hours window with a timezone. CRITICAL always sends regardless.

Email needs an SMTP server

Email channels send through the org's mail server, configured in Settings ▸ Mail server; its Test button sends to your signed-in email, so you confirm delivery end to end. Webhooks need no external mail, and an in-app channel only needs it when its email delivery is switched on. Internals: notifications.


Audit & usage

Where: Govern ▸ Audit & usage · Who: members view (scoped to their org) · Editions: all

This is the durable record of every call, and the spend rollups built from it. Two things on the page:

  • Calls. A filterable, paged audit table: time range, model, and outcome. Each row is one completion attempt, with its tokens and (if the deployment was priced) its cost.
  • Spend by model. A bar chart of cost / tokens / calls grouped by model.

How to query it

The page is a face over the analytics read API; you can hit the same endpoints directly:

Endpoint Returns
GET /admin/usage/calls Filterable audit rows (time / model / outcome)
GET /admin/usage/spend Cost, tokens, calls grouped by model
GET /admin/usage/spend-series The same per time bucket (hour / day / week / month)
GET /admin/usage/activity Call/token density by hour-of-day × day (the heatmaps)

All of them are org-scoped and accept an optional team/project filter, so the read narrows to the selected scope. A member is forced to their own org; the platform admin may pass a scope. This same data feeds the budget explorer trends and the rate limits activity tab.

Where the audit trail physically lives (it follows the tier)

On Core / Base, the system of record is the Postgres audit_event table, month-partitioned, with opt-in retention (aim.retention.audit-months, default keep-forever). On Pro (SIEM on), OpenSearch becomes the audit system of record and these reads are served from it, with longer retention and snapshot archival. The page and its API are identical either way. Internals: analytics.


Reports

Where: Govern ▸ Reports · Who: VIEW_REPORTS to view; MANAGE_REPORTS (operator and up) to author / schedule / run · Editions: all

Reports + New report Weekly cost digest password PDF · Mondays 08:00 Last generated 2h ago Download Guardrail findings CSV · daily Generating… Board pack PDF · monthly Never generated
Reports. Each definition is a card showing format, schedule, and live run status (Last generated / Generating / Never generated). The lock badge marks a password-protected download.

Reports turn the usage data into shareable artifacts: branded PDF, CSV, JSON, or HTML, on demand or on a schedule. A report has a definition (saved spec) and produces runs (generated artifacts, stored with a TTL).

Anatomy of a report definition

  • A dataset (what to summarise): usage / spend by model, activity, guardrail findings, and similar curated datasets. You pick from a typed catalogue, not raw SQL.
  • A scope and time window (org / team / project; this period vs last).
  • A format (PDF / CSV / JSON / HTML), an optional schedule (cron-like), and a delivery mode: link only (the secure default - a finished report notifies with just a dashboard link, no data leaves) or attach the file (email attaches it, a JSON webhook posts it). Delivery routes through Notifications; the link opens the Generated tab to download.
  • An optional password that protects the downloaded artifact itself: a native-password PDF, a self-decrypting HTML page, or a .gpg file for CSV/JSON. (Separately, every stored artifact is always encrypted at rest by the object store; the password is the extra, recipient-facing layer.)

You pick the dataset from a typed catalogue, never raw SQL, so a report definition is portable across the Postgres and OpenSearch backends unchanged:

Dataset Summarises Typical format
Spend by model Cost / tokens / calls grouped by model, with period-over-period deltas PDF / CSV
Usage over time The same per time bucket (hour / day / week / month) PDF / CSV
Activity Request density by hour and day PDF
Guardrail findings Categories flagged / redacted / blocked CSV / JSON

How a report is produced

flowchart LR
    DEF["Definition (saved spec)"] -->|"Run now / schedule"| Q["Query the usage data<br/>(typed dataset + filter + group-by)"]
    Q --> R["Render<br/>PDF · CSV · JSON · HTML"]
    R --> SEAL["Seal if a password is set<br/>(PDF pw · self-decrypting HTML · .gpg)"]
    SEAL --> STORE["Object store (encrypted at rest)<br/>+ a report_run row, with TTL"]
    STORE --> DL["Gated download / delivery"]

A scheduled definition fires on its cron; an on-demand one fires on Run now. Either way it produces a run (the artifact plus its metadata), which is what you download.

Example: a weekly cost report, emailed as a PDF

  1. New report → name it "Weekly cost digest."
  2. Dataset: spend by model. Scope: your org. Window: last 7 days, with period-over-period deltas on the KPI tiles.
  3. Format: PDF (branded with your org logo and accent colour).
  4. Schedule: every Monday 08:00. Delivery: attach the file so the PDF rides the email (leave it on link only to send just a dashboard link instead). Recipients are whoever your Notifications routing sends the report category to.
  5. Optionally set a password, so the emailed PDF needs it to open.
  6. Save. Hit Run now to generate one immediately; the card shows "Generating…", then "Last generated …" when ready, with a Download action.
# The same, via the API:
curl -X POST https://your-gateway/admin/reports/definitions \
  -H "Content-Type: application/json" --data @report.json
# then trigger a run:
curl -X POST https://your-gateway/admin/reports/definitions/{id}/run

Storage, TTL, and the artifact

Generated bytes live in the object store (filesystem on Core, S3-compatible on Pro/Distributed), not the database, with a TTL (default one day) and per-org ceilings. Downloads stream through the gated controller, so tenant isolation holds. Internals: reports and object store.


Sign-in activity

Where: Govern ▸ Sign-in activity · Who: VIEW_SECURITY · Editions: all

A filterable, paged log of admin sign-ins: successes and failures, with actor search. This is where you spot failed or suspicious access to the admin plane (brute-force attempts, logins from unexpected actors). It reads GET /admin/auth-events. It complements SIEM, which covers the data-plane and governance event stream.


Next: Investigate → (SIEM, UEBA, SOAR), or Settings & Profile →.