Skip to main content
Memproof policies are declarative YAML files that define how the system handles every memory operation. The policy engine evaluates rules in priority order — the first matching rule wins.

Policy File Structure

Every policy file has five top-level keys:
version: 0.1.0          # Semantic version of your policy
mode: enforce            # "enforce" applies rules; "audit" logs but does not block
defaults:                # Fallback behaviors
  on_policy_miss: deny
  on_adapter_error: quarantine
  require_idempotency: true
risk_thresholds:         # Score boundaries for risk levels
  low_max: 0.30
  medium_max: 0.60
  high_max: 0.80
  critical_max: 1.00
rules: []                # Ordered list of policy rules

Rule Anatomy

Each rule is a dictionary with the following fields:
- id: approve_high_risk_mutations        # Unique identifier
  description: Require approval for high risk mutations.
  enabled: true                          # Toggle without removing
  priority: 200                          # Lower number fires first
  action: require_approval               # allow | deny | require_approval | quarantine
  reason_codes: [HIGH_RISK_MUTATION]     # Machine-readable codes for audit trail
  match: all                             # "all" = AND, "any" = OR
  when:                                  # List of conditions
    - field: operation_type
      operator: in
      value: [remember, update, forget]
    - field: risk_level
      operator: in
      value: [high, critical]
Rules are sorted by priority at load time. A rule with priority 50 is evaluated before priority 200. The first match short-circuits evaluation.

Available Fields

Conditions can reference these fields from the evaluation context:
FieldTypeExample Values
operation_typestringremember, update, forget, search, get
risk_levelstringlow, medium, high, critical
risk_scorefloat0.0 - 1.0
scope.tenant_idstring"acme-corp"
scope.project_idstring"proj-123"
scope.agent_idstring"agent-alpha"
scope.subject_idstring"user-456"
context.sourcestring"langgraph", "mcp", "api"
content.contains_piibooltrue, false
content.contains_secretbooltrue, false
content.lengthint0 - N

Condition Operators

The policy engine supports 10 operators:
OperatorDescriptionExample
eqEquals{ field: risk_level, operator: eq, value: critical }
neqNot equals{ field: context.source, operator: neq, value: api }
inValue is in list{ field: operation_type, operator: in, value: [search, get] }
ninValue not in list{ field: context.source, operator: nin, value: [langgraph, mcp] }
gtGreater than{ field: risk_score, operator: gt, value: 0.8 }
gteGreater than or equal{ field: content.length, operator: gte, value: 1000 }
ltLess than{ field: risk_score, operator: lt, value: 0.3 }
lteLess than or equal{ field: content.length, operator: lte, value: 500 }
containsSubstring match{ field: scope.tenant_id, operator: contains, value: acme }
regexRegular expression match{ field: scope.agent_id, operator: regex, value: "^agent-.*" }

Match Modes

  • all (default) — Every condition must be true (logical AND).
  • any — At least one condition must be true (logical OR).

Default Behaviors

KeyValuesPurpose
on_policy_missallow, deny, quarantine, require_approvalAction when no rule matches
on_adapter_errorquarantine, denyAction when the backend adapter fails
Setting on_policy_miss: allow means any operation not explicitly matched by a rule will be permitted. In production, deny is the safer default.

Common Patterns

Allow Trusted Reads

- id: allow_safe_search
  description: Allow read/search from trusted runtimes.
  priority: 100
  action: allow
  reason_codes: [SAFE_READ_PATH]
  match: all
  when:
    - field: operation_type
      operator: in
      value: [search, get]
    - field: context.source
      operator: in
      value: [langgraph, openai_sessions, mcp]

Block Cross-Tenant Operations

- id: deny_cross_tenant_ops
  description: Deny operations with missing tenant scope.
  priority: 50
  action: deny
  reason_codes: [CROSS_TENANT_SCOPE_MISMATCH]
  match: any
  when:
    - field: scope.tenant_id
      operator: eq
      value: ""

Require Approval for High Risk

- id: approve_high_risk
  description: Require human approval for high/critical mutations.
  priority: 200
  action: require_approval
  reason_codes: [HIGH_RISK_MUTATION]
  match: all
  when:
    - field: operation_type
      operator: in
      value: [remember, update, forget]
    - field: risk_level
      operator: in
      value: [high, critical]

Quarantine PII from Untrusted Sources

- id: quarantine_pii
  description: Quarantine writes with PII from untrusted sources.
  priority: 160
  action: quarantine
  reason_codes: [SENSITIVE_UNTRUSTED_SOURCE]
  match: all
  when:
    - field: operation_type
      operator: in
      value: [remember, update]
    - field: context.source
      operator: nin
      value: [langgraph, openai_sessions, mcp]
    - field: content.contains_pii
      operator: eq
      value: true
Start with the example policy at examples/memproof.yaml and customize it for your threat model. Keep cross-tenant denial at the lowest priority number so it fires before anything else.