Policy model
A policy is a named, versioned object assigned to one or more collectors. It has two rule kinds:
- Access rules — attribute conditions on metadata (identity, device,
application, provider/model, network, time) that decide whether and
how a request is processed, before any content is inspected:
allowproceeds,denyblocks (an unsanctioned app, an unmanaged device), andmutatechanges the processing mode (force log-only, or escalate to a stricter rule set). This is attribute-based access control over AI use. - Prompt rules — content detectors from the six detection classes, each with a threshold and an action.
Actions
| Action | Effect |
|---|---|
| Log | Pass through and record. The only action a log-only collector supports. |
| Redact | Replace matched spans with a placeholder — before submission for prompts, before delivery for responses. The interaction proceeds. |
| Block | Stop the request or response; return a policy message. |
Evaluation order
- Access rules first, in author order:
denyshort-circuits to Block,mutatecaps downstream actions,allowproceeds. - Prompt rules run — local inline for Redact/Block, cloud async for depth — collecting all matches; one interaction can hit several classes.
- Resolve to one effective action: Block > Redact > Log, most
severe wins, ties broken by
priority. - Redaction is cumulative — every Redact rule contributes spans; overlapping spans are merged into one clean rewrite.
No match → the policy's default_action (log by default). A log-only
mutate caps even that — such a policy cannot Block no matter what a rule
says.
A complete example
policy:
id: pol_workforce_std
name: "Workforce - standard"
version: 7
default_action: log
access_rules:
- { id: ar_block_unsanctioned, when: { application.category: unsanctioned_ai }, effect: deny }
- { id: ar_monitor_byod, when: { device.managed: false }, effect: mutate, mode: log_only }
prompt_rules:
- { id: pr_injection, detector: prompt_injection, applies_to: [prompt],
threshold: 0.80, action: block, priority: 100 }
- { id: pr_secrets, detector: sensitive_data, subclasses: [credentials, financial, pii],
applies_to: [prompt, response], action: redact,
redaction: { placeholder: "[REDACTED:{class}]" } }
- { id: pr_malicious_url, detector: malicious_entity, applies_to: [response], action: block }
- { id: pr_topic, detector: topic, categories: [legal_advice, medical_advice],
threshold: 0.75, action: log }
- { id: pr_language, detector: language, allow: [en, es], action: block }
custom_definitions:
- { id: cd_caseid, kind: regex, pattern: "WZ-\\d{6}",
class: confidential.case_id, action: redact }
The BYOD access rule is worth reading twice: an unmanaged laptop gets watched, not policed — detections are still recorded, enforcement is withheld. Identical content produces a different verdict because policy reads the context. See demo 10.
Redaction spans
A span targets one field and carries a zero-based [start, end) character
offset over the normalized text, the detection class, and the placeholder
substituted. Spans are stored on the finding, so the console shows what
class was redacted without ever storing the raw value.
Validating and inspecting
lumen-agent policy validate --policy /etc/lumen/policy.yaml
lumen-agent policy effective --config /etc/lumen/agent.yaml
policy effective resolves the policy exactly the way the daemon does, so it
cannot report something the daemon does not run — see
Configuration.