Guides

Policies

Declarative governance rules evaluated on every inference request.

Overview

Policies are declarative governance rules evaluated against every inference request passing through the Monago Gateway. Each policy is written in JSON DSL with the core fields: name, when (conditions), effect (allow / deny / log_only / redact / require_approval / require_hitl), and priority. The policy engine is the foundational governance component of Monago.

Why the policy engine matters in a regulated context:

  • Runtime enforcement — the policy engine blocks rule-violating requests before they reach upstream AI.
  • Auditable decisions — every policy decision produces an audit chain entry, so regulators can audit both the governance rules and the actual decisions.
  • Ready-to-use templates — common patterns such as PII protection, model allowlist, token budget, time restriction, prompt injection scoring, and premium model approval gate.
  • Multi-dimensional matching — conditions can reference user.team, user.role, request.model, estimated tokens, data classification, and additional fields.

Audience for this page: tenant administrators or workspace_admin users who define and maintain governance rules.

Concepts

TermDefinition
Policy ruleA persistent container storing a policy. It holds multiple versions; one version is active at a time.
Policy versionA snapshot of the policy definition. Versioning enables audit and rollback.
Policy DSLA JSON schema with name, when, effect, priority, and optional framework_mapping.
EffectThe action taken when the condition matches.
PriorityAn integer from 0 to 100. When multiple policies match, the highest priority wins.
Framework mappingOptional — links a policy to a framework clause to feed the compliance posture.
Workspace scopeA policy can be workspace-bound or tenant-wide.
TemplateA pre-built policy that an administrator can instantiate.

Policy anatomy

An example policy blocking external LLM for confidential finance data:

{
  "name": "Finance Team External LLM Restriction",
  "description": "Block external LLM untuk data finance klasifikasi confidential/restricted.",
  "when": {
    "operator": "and",
    "conditions": [
      {"field": "user.team", "operator": "in", "value": ["finance", "treasury"]},
      {"field": "request.model_provider", "operator": "equals", "value": "external"},
      {"field": "context.data_classification", "operator": "in", "value": ["confidential", "restricted"]}
    ]
  },
  "effect": {
    "type": "deny",
    "deny_reason_code": "FINANCE_EXTERNAL_LLM_CONFIDENTIAL",
    "deny_user_message": "Data finance klasifikasi confidential/restricted tidak boleh diproses via external LLM."
  },
  "priority": 90,
  "framework_mapping": [
    {"framework": "ISO_42001", "clause": "A.7.4"}
  ]
}

When a request comes from a user on the finance team with classification confidential to an external provider, the policy engine returns deny with a reason code and a user-facing message. The audit row records the decision with the policy version and matched conditions.

Setup

Prerequisites

  • The admin role on the tenant (or workspace_admin for a workspace-bound policy).
  • A clear governance use case (model usage, team restrictions, cost caps, and so on).
  • Familiarity with the JSON DSL structure, or pick a template.
TemplateUse case
PII redaction defaultRedact sensitive identifiers in the request body before forwarding to the provider
Finance external LLM restrictionBlock external LLM for confidential / restricted finance data
Model allowlist by teamAllow specific models only for specific teams
Token budget cap per userBlock requests once the daily cumulative tokens per user exceed the cap
Time-of-day restrictionAllow requests only during business hours
Premium model approval gateTrigger HITL approval for requests to a premium model

Open Policies

Select Policies from the sidebar.

Create policy

Click Create policy in the top-right.

Pick a template

From the Template (optional) dropdown.

Edit metadata

Adjust name, slug, and description to suit the organisation's context.

Tweak the DSL

Adjust when.conditions or effect.deny_user_message in the JSON editor.

Submit

Click Create policy.

The first version is automatically active after creation.

Create a custom policy (no template)

Pick custom

Create policyCreate custom (no template).

Edit the DSL

Edit the JSON in the editor: name, when, effect, priority.

Submit

The backend validates the payload; error detail surfaces when the DSL is invalid.

Conditions (when)

Fields: user.id, user.email, user.role, user.team, request.model, request.model_provider, request.estimated_tokens, request.action, context.data_classification, context.workspace_id, context.tenant_id.

Operators: equals, not_equals, in, not_in, contains, greater_than, less_than, regex_match.

Combinators: and, or. Nested groups are supported for complex expressions.

Effects

EffectBehaviour
allowThe request is forwarded to the provider
denyThe request is blocked; the response is 403 with deny_reason_code and the user message
log_onlyThe request continues; the audit row is enriched without enforcement
redactSensitive content is replaced with a placeholder before forwarding
require_approvalThe request is held; the administrator is notified for approval
require_hitlThe request is held; a human-in-the-loop reviewer is notified
escalateThe request continues but is flagged for post-hoc review

Usage

Policy list

The Policies page lists every policy rule at the tenant + workspace scope. An empty-state quickstart appears when the tenant does not yet have any policies.

Policy detail and decision log

Click a row to open the detail page (/policies/{id}):

  • Metadata: name, slug, description, framework mapping, priority.
  • JSON viewer for the active version.
  • Recent decisions table (20 entries): action, status, matched conditions, user, model, timestamp.
  • Create new version and Revoke buttons (admin).

Create a new version (edit a policy)

Policies are versioned — every change produces a new version.

Detail page

Click Create new version.

Editor pre-filled

The editor is pre-filled with the active version's JSON.

Submit

The new version is automatically active; the previous version is retained for audit and is immutable.

Priority and conflict resolution

When multiple policies match a single request:

Sort

The engine sorts descending by priority.

First match wins

Subsequent matches are skipped.

Tiebreaker

For equal priorities, the tie is broken by created_at ascending.

Recommended priority bands:

  • 0-30: log_only or observational policies.
  • 40-60: standard governance.
  • 70-90: strict governance.
  • 91-100: emergency override.

NER integration for redaction

A policy with the redact effect can optionally invoke contextual NER for entities that do not match the regional pattern layer. Configuration sits under effect.redact_config.

Compliance mapping

Per-clause mapping detail and the evidence package are delivered in a separate procurement document — contact support@monago.io.

Troubleshooting

"Invalid policy DSL format"

The backend rejects the payload with a detailed error message. Common causes: missing or wrongly shaped condition fields, a typo on the operator, or an effect type outside the allowed enum. Resolution: copy from the closest template and adjust where needed.

A policy matches but the gateway request still succeeds

Check the policy status — if it is disabled or archived, the engine skips it. Re-activate through the UI or create a new version.

Multiple policies match and the wrong one wins

Priority resolution: highest wins. Check the priority of every matching candidate on the detail page. Reorder by creating a new version with the priority adjusted.

"Policy not found" when updating a version

The policy may have been archived by another administrator. Refresh the list page.

Redaction does not trigger despite a redact policy

  • Verify the effect is redact (not log_only).
  • Verify that effect.redact_config is active.
  • When the contextual NER layer is unavailable, detection still runs on the regional pattern layer; the audit log records which layer is active per request.

FAQ

Are policy decisions real-time or async?

Real-time. Every inference request is evaluated synchronously before being forwarded to the provider. Latency overhead is minimal because resolution is cached per tenant.

Can a policy use custom fields beyond the built-in set?

The pilot scope only supports the built-in fields (see the list in Setup). Custom fields via an extension mechanism are on the development roadmap.

Is there a limit on the number of policies per tenant?

There is no hard limit during the pilot. Recommendation: keep the count manageable (typically 10 to 30 per tenant) so audit and decision tracing remain straightforward.

How do I test a policy before deploying to production?

Use workspace separation: deploy first to a staging workspace, test with a sample workload, then replicate to the production workspace. Dry-run evaluation against a sample request (without enforcement) is on the development roadmap.

What happens if I delete an active policy?

Soft archive (status becomes archived). The audit chain and decision history are retained.

Can workspace_admin create policies?

Yes — limited to the workspace they manage (workspace-bound policies). Tenant-wide policies can only be created by tenant administrators.

What is the difference between log_only and allow?

allow is an explicit permit with no audit enrichment. log_only is a permit with audit log tagging using the policy match metadata for compliance reporting.

  • BYOK — provider credentials (target of model_provider matching).
  • Workspaces — workspace scope for policy isolation.
  • Risk — policy decisions feed risk signals.
  • Compliance — framework mapping aggregate.