Skip to main content
The Controls Engine is an in-process policy engine for AI applications. It evaluates structured Controls before or after an LLM call or tool call, then returns an allow, deny, or steer decision. You can also record policy matches without blocking execution. A Control follows this evaluation flow:
  • A Step represents an LLM call or tool call.
  • A Scope determines whether the Control applies to that Step.
  • A Selector chooses the input, output, or context value to inspect.
  • An Evaluator checks the selected value.
  • An Action determines what happens when the condition matches.

Choose an Interface

VijilDome and Dome are separate interfaces. VijilDome evaluates declarative Controls and returns EvaluationResult objects. Dome runs content Guardrails and returns scan results. A Control can still invoke a Dome Detector through the dome: Evaluator prefix.

Install the Controls Engine

The base package includes Python policies, JSON and TOML loading, and the regex and list evaluators:
Install the controls extra to load YAML policies:
Install the controls-full extra to add YAML, JSON Schema, CEL, and RE2 support:
Some Dome Detectors require their own optional dependencies. See Detection Methods before you reference a Detector from a Control.

Protect a Tool Call

Define a policy as a list of Control dictionaries, then pass it to VijilDome:
In enforcement mode, guard_tool_call() raises ControlViolationError before your application invokes the tool. Call the tool only after the Guard method returns successfully:

Protect LLM Inputs And Outputs

Use the input Guard method before you call the model and the output Guard method before you return its response:
The asynchronous methods have the same policy behavior:

Write a Control

Each Control contains the policy metadata, applicability rules, matching logic, and action.

Scope a Control

Use scope to limit evaluation before the engine runs the condition: Omit a scope field to match all values for that field. A Control without a scope applies to every Step and stage.

Select a Value

Selectors use dot notation against the Step: If a selector path is missing, the condition does not match.

Combine Conditions

A leaf condition contains one selector and one evaluator. Use and, or, and not to compose multiple conditions:
Composite children run concurrently by default. Set early_exit: true on an and or or node to evaluate its children sequentially and stop after the first decisive result.

Choose an Evaluator

For example, run a prompt-injection Detector against every LLM input:
See the Controls API Reference for every evaluator option and default.

Choose an Action

Include steering_context whenever you use steer:
Control how evaluator failures affect the decision with on_error:
fail_closed is the default and treats a raised evaluator error as a match. fail_open treats it as a non-match. This setting applies to evaluators that raise an error; an evaluator can instead return a non-matching result with error metadata.

Use Shadow Mode

Set enforce=False to evaluate a policy without interrupting application execution:
Shadow mode logs deny and steer decisions and returns their EvaluationResult. The agent_id value is an optional identifier stored and exposed by the VijilDome instance. It does not establish workload identity. Use Trust Runtime when you need identity-bound enforcement.
EvaluationResult.permitted is False only for deny. A steer result remains permitted and carries correction guidance in steering_context. An observe match appears in matches and does not change the aggregate action. If no deny or steer Control triggers, the aggregate action is allow.

Protect a Function

Use @control() to evaluate a function before and after execution. The following policy only applies to the pre stage, so it can block the function before it runs:
The decorator supports synchronous and asynchronous functions. For tool Steps, it maps bound function arguments to an input dictionary. For LLM Steps, it first looks for common parameter names such as input, message, query, text, or prompt. Use explicit mappers when your function arguments or return value need another shape:
You can also share a configured engine through the instance decorator:

Load a Policy From a File

Pass a JSON, YAML, or TOML path anywhere a policy is accepted:
JSON and YAML files can contain either a list of Controls or a top-level controls key:
Use an array of controls tables for native TOML policies:
The loader also accepts established Dome TOML files with a [guardrail] section and translates their Guards into Controls.

Use the Engine Directly

Use ControlEngine when your application already represents execution as Steps or needs to inspect decisions without automatic exception handling:
evaluate() and evaluate_sync() return an EvaluationResult. They do not raise ControlViolationError or ControlSteerError; your application decides how to enforce the result.

Register a Custom Evaluator

Subclass Evaluator when the built-in evaluators and Dome Detectors do not cover your application policy:
Reference the registered name from a Control:
Import the module that registers your Evaluator before the first evaluation that references it.

Next Steps

Controls API Reference

Review every public class, method, model, evaluator, and result type

Trust Runtime

Add identity, tool access control, attestation, and structured audit events

Detection Methods

Choose Dome Detectors to invoke from your Controls

Protection Overview

Compare the available Dome protection interfaces
Last modified on July 30, 2026