0013 — Policy engine guards real-world side effects¶
- Status: Accepted
- Date: 2026-05-15
- Deciders: @sinidious
Context¶
CAESAR will, sooner or later, be asked to do something it shouldn't. Unlock the front door at 3 AM. Crank the thermostat to a setting the HVAC can't sustain. Disable a smoke detector. Send a payment.
We need a layer that says "no" — and says it for reasons we can read, review, and version — between the agents and the HA Bridge. Hard-coding refusals in agent code is brittle, hides the policy across a dozen files, and ties policy changes to code releases.
Decision¶
CAESAR has a Policy Engine that sits between agent-decided actions and the HA Bridge. Properties:
- Declarative rules, loaded from YAML files in a configured directory. Operators write rules; the engine evaluates.
- Rule shape: predicate (which actions does this rule apply to?)
- condition (when does it apply?) + verdict (allow / deny / require-confirm).
- Default deny for action types not whitelisted by any rule. Read-only operations (state queries) are allow-by-default.
- Every evaluation is audit-logged, including which rule fired.
- Dry-run mode for new rules: log the verdict, don't enforce, for a configurable window.
Initial rule examples (sketched, not authoritative):
- name: no-unlock-after-midnight-when-away
actions: ["lock.unlock"]
when: time.between("00:00", "06:00") and presence.away
verdict: deny
- name: confirm-bulk-light-changes
actions: ["light.turn_on", "light.turn_off"]
when: action.scope == "all"
verdict: require_confirm
Alternatives considered¶
- Hard-coded checks in each Legion worker — duplication, drift, and changes require code releases.
- HA automations as the policy layer — works, but moves policy outside CAESAR's audit log and outside the Policy Engine's language. We may also express policies as HA automations, but CAESAR's own choices must go through this engine.
- OPA / Rego — a heavyweight, well-trodden policy engine. Worth reconsidering for v1.0; rejected initially because YAML rules are enough for the action shapes we have, and OPA is a hefty dependency for a single-host service.
Consequences¶
Positive¶
- Operators can change policy without a release.
- Audit log shows why something was allowed or denied.
- New action types fail closed by default.
Negative¶
- We carry policy as code complexity from day one, even before there are interesting policies to write.
- Rules can conflict; the engine needs deterministic precedence rules. Documented when implemented.
Neutral¶
- We will likely outgrow YAML predicates eventually. The interface between agent and engine (action descriptor) is designed to make swapping to OPA/Rego later a tractable change.