The gate every model-authored plan passes before anything runs. Orchestrates
structural validation, tool-signature and action matching, constraint checks,
output-type and workflow allow-lists, and the app's optional plan_policy
callbacks.
Everything here is deny-by-default:
- a tool call must name an allowed tool and an allowed action;
- an output proposal must use a type in
allowed_output_types; - a workflow trigger must name a workflow in
allowed_workflows; - a
plan_policy, when set, must be a loadedCyclium.Intent.PlanPolicymodule; one that is not, or that raises, denies the plan rather than failing open or crashing the episode.
No policy is needed for an actor to be bounded; the allow-lists do that. A
policy adds per-principal rules the static lists cannot express, and is a
module set in the expectation's strategy_config
(strategy_config: %{plan_policy: MyApp.Policy, ...}). A string is never
resolved to a module, so DB-defined config cannot name one.
Summary
Functions
Parse allowed_tool_signatures from a strategy config into signature structs.
Shared with the agentic loop so the gate and the preview decision see the same
signatures.
Functions
@spec evaluate(Cyclium.Intent.ActionPlan.t(), map(), map()) :: :ok | {:deny, binary()}
@spec parse_signatures(map()) :: [Cyclium.Intent.ToolSignature.t()]
Parse allowed_tool_signatures from a strategy config into signature structs.
Shared with the agentic loop so the gate and the preview decision see the same
signatures.