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
| Term | Definition |
|---|---|
| Policy rule | A persistent container storing a policy. It holds multiple versions; one version is active at a time. |
| Policy version | A snapshot of the policy definition. Versioning enables audit and rollback. |
| Policy DSL | A JSON schema with name, when, effect, priority, and optional framework_mapping. |
| Effect | The action taken when the condition matches. |
| Priority | An integer from 0 to 100. When multiple policies match, the highest priority wins. |
| Framework mapping | Optional — links a policy to a framework clause to feed the compliance posture. |
| Workspace scope | A policy can be workspace-bound or tenant-wide. |
| Template | A 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.
Create a policy from a template (recommended)
| Template | Use case |
|---|---|
| PII redaction default | Redact sensitive identifiers in the request body before forwarding to the provider |
| Finance external LLM restriction | Block external LLM for confidential / restricted finance data |
| Model allowlist by team | Allow specific models only for specific teams |
| Token budget cap per user | Block requests once the daily cumulative tokens per user exceed the cap |
| Time-of-day restriction | Allow requests only during business hours |
| Premium model approval gate | Trigger 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 policy → Create 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
| Effect | Behaviour |
|---|---|
allow | The request is forwarded to the provider |
deny | The request is blocked; the response is 403 with deny_reason_code and the user message |
log_only | The request continues; the audit row is enriched without enforcement |
redact | Sensitive content is replaced with a placeholder before forwarding |
require_approval | The request is held; the administrator is notified for approval |
require_hitl | The request is held; a human-in-the-loop reviewer is notified |
escalate | The 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(notlog_only). - Verify that
effect.redact_configis 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.
Related
- BYOK — provider credentials (target of
model_providermatching). - Workspaces — workspace scope for policy isolation.
- Risk — policy decisions feed risk signals.
- Compliance — framework mapping aggregate.