Skip to content

Cedar Policy Authoring Guide

This guide covers how to write Cedar policies for Lucid. Cedar is the unified policy language for all enforcement decisions -- it replaces LPL, OPA/Rego, and block_on_* flags.

How Cedar Works in Lucid

  1. ClaimsAuditors observe AI traffic and produce typed claims (e.g., toxic_content = 0.42)
  2. The Gateway collects all claims into a ClaimsContext
  3. The Gateway evaluates your Cedar policy against the context
  4. The policy produces an allow or deny decision
  5. The decision is recorded in the Evidence and AI Passport

You write Cedar policies that reference claim names. The Gateway does the rest.

Cedar Syntax Primer

Cedar policies are either permit or forbid statements:

// Allow a request
permit(principal, action, resource)
when { <conditions> };

// Deny a request
forbid(principal, action, resource)
when { <conditions> };

Cedar uses deny-overrides: if any forbid matches, the request is denied regardless of permit rules.

Principals, Actions, and Resources

In Lucid's Cedar schema:

Concept What It Represents Examples
Principal Who is making the request User::"user-123", Agent::"legal-bot", APIKey::"key-abc"
Action What operation is being performed Action::"invoke", Action::"access_data"
Resource The target agent or service Agent::"my-agent", Service::"compliance-api"
Context Claims and metadata context.claims.*, context.phase, context.trace_id

Accessing Claims in Conditions

Claim names from auditors are available under context.claims:

// Auditor produces: toxic_content = 0.42
// Cedar accesses:   context.claims.toxic_content

forbid(principal, action == Action::"invoke", resource)
when { context.claims.toxic_content > 0.8 };

Common Policy Patterns

Block on Threshold

// Block toxic content
forbid(principal, action == Action::"invoke", resource)
when { context.claims.toxic_content > 0.7 };

Block on Boolean Detection

// Block injection attempts
forbid(principal, action == Action::"invoke", resource)
when { context.claims.secret_leaked == true };

Block with Confidence Check

// Only block if injection risk is very high
forbid(principal, action == Action::"invoke", resource)
when { context.claims.injection_risk > 0.9 };

Block Unless Authorized

// Block PII access unless the agent is authorized for PII
forbid(principal, action == Action::"invoke", resource)
when { context.claims.pii_count > 0 }
unless { resource.pii_authorized == true };

Allow Specific Principals

// Only admin users bypass toxicity checks
permit(principal in Group::"admins", action == Action::"invoke", resource);

// Everyone else is subject to toxicity checks
forbid(principal, action == Action::"invoke", resource)
when { context.claims.toxic_content > 0.5 };

Geo-Fencing

// Block if not in allowed region
forbid(principal, action == Action::"invoke", resource)
when { !("EU" in context.claims.detected_regions) };

Multi-Claim Combinations

// Block if BOTH injection risk AND toxicity are high
forbid(principal, action == Action::"invoke", resource)
when {
    context.claims.injection_risk > 0.7 &&
    context.claims.toxic_content > 0.5
};

Response-Phase Policies

Response-phase claims use the same syntax:

// Block responses that contain hallucinations
forbid(principal, action == Action::"invoke", resource)
when {
    context.phase == "response" &&
    context.claims.hallucination_score > 0.6
};

Decision Annotations

Annotate policies to control enforcement behavior beyond simple allow/deny:

Warn Instead of Block

// Flag but don't block moderate toxicity
@annotation("decision", "warn")
forbid(principal, action == Action::"invoke", resource)
when {
    context.claims.toxic_content > 0.5 &&
    context.claims.toxic_content <= 0.8
};

Escalate to Human

// Require human approval for high PII exposure
@annotation("decision", "escalate")
forbid(principal, action == Action::"invoke", resource)
when { context.claims.pii_count > 5 };

Shadow Mode (Test Without Enforcing)

// Test a new rule without affecting traffic
@annotation("decision", "shadow")
forbid(principal, action == Action::"invoke", resource)
when { context.claims.new_experimental_score > 0.9 };
Annotation Behavior
deny (default) Block the request
warn Allow but flag in passport
escalate Block and create approval request
shadow Evaluate and log, but do not enforce
log Silent logging only

Detection Rules vs Response Rules

Cedar policies are the Response Rules — they define what happens when claims fire. The Detection Rules (auditor settings) control what claims are produced and at what sensitivity. Both can be configured together via auditor presets (Starter, Balanced, Strict) that provide coherent bundles of settings and policies.

Auditor settings also support enforcement modes (floor, ceiling, exact, superset, unlocked) that control how parent scope constraints are inherited. See the Policy as Code guide for details.

Policy Scoping

Organization Policies

Org policies are security baselines that cannot be overridden:

@annotation("scope", "org")
@annotation("id", "org-baseline-injection")
forbid(principal, action == Action::"invoke", resource)
when { context.claims.injection_risk > 0.7 };

Workspace Policies

Workspace policies add restrictions for a group of agents:

@annotation("scope", "workspace")
@annotation("workspace_id", "ws-customer-support")
forbid(principal, action == Action::"invoke", resource)
when { context.claims.toxic_content > 0.3 };

Agent Policies

Agent-specific policies for individual agents:

@annotation("scope", "agent")
@annotation("agent_id", "agent-legal-reviewer")
forbid(principal, action == Action::"invoke", resource)
when { context.claims.location_confidence >= 0.9 };

Scoping Rules

  • Org forbid rules apply everywhere and cannot be removed
  • Workspace forbid rules add to org rules
  • Agent forbid rules add to org + workspace rules
  • A lower-scope permit cannot override a higher-scope forbid

Compliance Annotations

Map policies to regulatory controls:

@annotation("compliance_framework", "GDPR")
@annotation("control_id", "Art.5(1)(c)")
@annotation("description", "Data minimization - block unnecessary PII exposure")
forbid(principal, action == Action::"invoke", resource)
when { context.claims.pii_found == true }
unless { resource.pii_authorized == true };

These annotations are surfaced in the Observer UI for compliance reporting.

Testing Policies

CLI Testing

# Validate syntax
lucid policy validate policy.cedar

# Test against sample claims
lucid policy test policy.cedar --claims-file test-claims.json --expect deny

# Preview changes before deploying
lucid policy diff policy.cedar --scope agent --scope-id agent-abc123

Sample Claims File

{
  "principal": "User::\"user-123\"",
  "action": "Action::\"invoke\"",
  "resource": "Agent::\"my-agent\"",
  "context": {
    "phase": "request",
    "claims": {
      "toxic_content": 0.9,
      "injection_risk": 0.1,
      "pii_found": true,
      "pii_count": 1,
      "detected_regions": ["US"]
    }
  }
}

Deploying Policies

Via CLI

# Push to an agent
lucid policy push policy.cedar --scope agent --scope-id agent-abc123

# Push to a workspace
lucid policy push workspace-policy.cedar --scope workspace --scope-id ws-123

# Push org baseline
lucid policy push org-baseline.cedar --scope org

Via Observer UI

Use the three-tab policy editor (IFTTT, Visual, Cedar) in the Observer. See the Policy Editor Guide.

Via YAML

Include Cedar policies in your agent definition:

apiVersion: lucid.io/v1alpha1
kind: LucidAgent
metadata:
  name: my-agent
spec:
  model:
    id: meta-llama/Llama-3.3-70B
  policy:
    cedar: |
      forbid(principal, action == Action::"invoke", resource)
      when { context.claims.injection_risk > 0.7 };

      forbid(principal, action == Action::"invoke", resource)
      when { context.claims.toxic_content > 0.7 };

      permit(principal, action == Action::"invoke", resource);

Best Practices

  1. Start with deny-all, permit explicitly: Begin with no default permit and add specific allows.
  2. Use shadow mode for new policies: Test new rules with @annotation("decision", "shadow") before enforcing.
  3. Keep org policies minimal: Org-level rules should be absolute security baselines only.
  4. Reference specific claims: Avoid broad conditions; reference the exact claim names from the auditor vocabulary.
  5. Add compliance annotations: Map every security rule to a regulatory control for audit trails.
  6. Version control your .cedar files: Treat policies like code -- review, test, and version them.