Deterministic guardrails are rule-based security controls that provide predictable, verifiable authorization for AI agents. Unlike nondeterministic approaches that rely on LLM judgment, deterministic guardrails use explicit logic - RBAC, input validation, sequence enforcement - to control what AI agents can and cannot do.
Deterministic guardrails are security controls that enforce authorization decisions through explicit, repeatable rules. When an AI agent attempts an action, deterministic guardrails evaluate the request against predefined policies and make a binary decision: allow or deny.
The "deterministic" property means that given the same inputs (user context, function call, parameters), the guardrail will always produce the same decision. There's no ambiguity, no probabilistic reasoning - just pure logic.
Predictable, repeatable decisions
Rule-based authorization (RBAC)
Input validation against schemas
Sequence enforcement patterns
Auditable and explainable
Probabilistic, variable decisions
LLM-based judgment calls
Content moderation via AI
Intent classification
Harder to audit and explain
Agentic AI systems - where AI makes autonomous decisions and executes functions - face a fundamental authorization problem: how do you ensure an AI agent only does what it's allowed to do?
In production systems, you need guaranteed behavior. Deterministic guardrails ensure the same input always produces the same authorization decision.
Authorization is too critical to delegate to probabilistic systems. Deterministic guardrails provide cryptographic-level certainty about what AI agents can access.
Compliance and security teams need explainable decisions. Deterministic guardrails provide clear audit trails.
Traditional authorization systems operate at the API endpoint level. But agentic AI doesn't call endpoints - it calls individual functions based on natural language instructions.
This creates a massive security gap: even if your API is locked down, an AI agent with access to powerful functions can bypass all controls through prompt injection, data exfiltration, or multi-step attacks.
Deterministic guardrails solve this by moving authorization to the function level, where AI agents actually operate.
D2 implements deterministic guardrails through three complementary mechanisms:
Role-Based Access Control defines who can call which functions. Each function is protected by a declarative policy that maps roles to permissions.
# Weather API policytools:weather_api:allowed_roles:- developer- admindenied_roles:- guest
Result: Developers and admins can call get_weather(), guests cannot. The decision is deterministic and instant.
Input guardrails validate function arguments before execution. Output guardrails sanitize or validate return values after execution.
tools:database_query:guardrails:input:- type: schema_validationfield: queryschema:type: stringmax_length: 1000pattern: "^SELECT.*FROM users.*$"
Result: Any query exceeding 1000 characters or not matching the pattern is automatically denied before reaching the database.
Sequence enforcement prevents multi-step attacks by defining required or forbidden sequences of function calls.
# Prevent data exfiltrationsequences:prevent_exfiltration:forbidden_sequences:- [read_database, send_email]- [read_database, call_external_api]
Result: If an AI agent reads from the database, it cannot subsequently send email or call external APIs in the same session - preventing exfiltration attacks.
Both approaches have their place. The key is understanding which problems require determinism and which benefit from AI judgment.
D2's approach: Start with deterministic guardrails for all authorization and access control decisions. Layer nondeterministic guardrails on top for content-level safety. This defense-in-depth strategy ensures security is never probabilistic, while still leveraging AI for nuanced content decisions.
D2 provides a zero-infrastructure approach to deterministic guardrails. Add a single decorator to your functions, define policies in YAML, and authorization is enforced at runtime.
from d2 import d2_guard, set_user@d2_guard("database_query")def query_users(sql: str):return db.execute(sql)# Set user contextset_user("alice", roles=["developer"])# This call is deterministically evaluatedresult = query_users("SELECT * FROM users")
The @d2_guard decorator intercepts every function call and applies deterministic guardrails before execution.
tools:database_query:allowed_roles:- admin- developerguardrails:input:- type: schema_validationfield: sqlschema:type: stringmax_length: 2000pattern: "^SELECT.*"output:- type: pii_removalfields:- ssn- credit_card
All authorization logic lives in declarative policies. Update the policy file and changes propagate within seconds - no code deployment required.
A deterministic guardrail is idempotent: evaluating the same request multiple times produces identical results. This property is critical for retry logic, distributed systems, and debugging.
Multiple deterministic guardrails can be composed together. D2 evaluates RBAC, input guardrails, sequence checks, and output guardrails in a defined order, all deterministically.
Because deterministic guardrails don't require LLM calls, they add minimal overhead to function execution. This makes them suitable for high-throughput production systems.
Deterministic guardrails are fully testable. You can write unit tests that assert authorization behavior, with no mocks or test doubles required.