Implementing Policy Engine and Decision Rules in Semantica: Architecture and Code Examples

Semantica's policy engine provides a full-stack solution for rule lifecycle management, automated compliance checking, and versioned decision tracking through the PolicyEngine class located in semantica/context/policy_engine.py.

The semantica-agi/semantica repository delivers a graph-native framework that enables AI agents to enforce business rules without code changes. By abstracting the storage layer through the GraphStore interface, the system supports Neo4j, FalkorDB, and in-memory backends while maintaining complete audit trails for every policy decision and exception.

Core Architecture and Components

The policy engine orchestrates CRUD operations, versioning, compliance validation, and impact analysis within a unified architecture. Understanding these components is essential for implementing rule-driven decision making in your Semantica applications.

The PolicyEngine Class

The central orchestrator resides in semantica/context/policy_engine.py. When instantiated, PolicyEngine accepts a generic graph_store backend and automatically detects Cypher support via self._supports_cypher. This detection allows the engine to switch between optimized Cypher queries and generic node/edge APIs, ensuring compatibility across different graph databases.

Data Models and Types

Policy and decision structures are defined as dataclasses in semantica/context/decision_models.py. The Policy model (lines 74–87) captures rule sets, versioning metadata, and categorical tags, while the Decision model (lines 86–98) records outcomes, confidence scores, and arbitrary metadata fields. These models enforce type safety throughout the compliance pipeline.

Graph Store Abstraction

The engine relies on the GraphStore interface imported from semantica/graph_store.py. This abstraction provides methods like add_node, add_edge, find_nodes, and execute_query, allowing the policy engine to function independently of the underlying database technology.

Policy Lifecycle Management

Semantica treats policies as versioned entities, enabling immutable rule histories and safe iteration workflows.

Creating and Storing Policies

The add_policy method (lines 98–108) persists a Policy dataclass to the graph store. It validates unique policy_id values and timestamps the operation using datetime.utcnow(). When using a Cypher-enabled backend, the method executes a CREATE statement; otherwise, it falls back to the generic add_node API.

from semantica.context import PolicyEngine, Policy
from datetime import datetime

engine = PolicyEngine(graph_store=my_graph_store)

policy = Policy(
    policy_id="loan_policy_001",
    name="Standard Loan Approval",
    rules={"min_credit_score": 650, "max_loan_amount": 500_000},
    category="lending",
    version="1.0",
    created_at=datetime.utcnow(),
    updated_at=datetime.utcnow(),
    metadata={"entities": ["customer"]},
)
engine.add_policy(policy)

Version Control and Updates

Updating rules via update_policy (lines 166–190) automatically triggers the _generate_next_version logic. Rather than mutating existing nodes, the engine creates a new Policy instance with an incremented version string and links it to the previous version using a VERSION_OF edge. This immutable approach preserves historical decision contexts while enabling rollback capabilities.

To retrieve the active rule set, get_applicable_policies queries for the latest version by excluding any node that has a downstream VERSION_OF edge, ensuring only current policies affect new decisions.

Implementing Decision Rules and Compliance

The compliance engine evaluates decisions against policy rule sets using a flexible prefix-based syntax.

Rule Syntax and Operators

Rules are defined as dictionaries where keys use specific prefixes to indicate validation logic:

  • min_<field>: Validates that decision metadata meets or exceeds a numeric threshold
  • max_<field>: Ensures metadata values do not exceed specified limits
  • required_<field>: Confirms metadata contains all required items or matches a scalar value
  • min_confidence: Enforces a minimum confidence score on the decision itself
  • allowed_outcomes: Restricts decisions to specific outcome strings
  • required_categories: Validates that decision categories match policy scopes

Compliance Evaluation Flow

The check_compliance(decision, policy_id) method (lines 78–88) fetches the target policy and delegates evaluation to _evaluate_compliance (lines 996–1025). This internal method iterates through the policy's rule dictionary, applying the prefix logic to the decision's metadata and intrinsic fields.

from semantica.context import Decision

decision = Decision(
    decision_id="dec_123",
    category="loan_approval",
    outcome="approved",
    confidence=0.96,
    metadata={"credit_score": 720, "loan_amount": 350_000},
)

is_compliant = engine.check_compliance(decision, policy_id="loan_policy_001")

The _check_compliance_with_rules helper supports complex boolean logic, allowing policies to combine multiple constraints into a single validation pass.

Impact Analysis for Rule Changes

Before deploying policy updates, administrators can simulate effects using the impact analyzer. The analyze_policy_impact method (lines 712–777) executes a "what-if" query to identify all decisions linked to the target policy, then invokes _calculate_impact_metrics to compute:

  • The total number of affected historical decisions
  • Projected changes in compliance scores
  • Estimated risk increases based on rule differentials
  • Detailed diffs between current and proposed rule sets
new_rules = {"min_credit_score": 750, "max_loan_amount": 550_000}
impact = engine.analyze_policy_impact(
    policy_id="loan_policy_001", 
    proposed_rules=new_rules
)

This simulation enables data-driven policy adjustments without risking production decision quality.

Exception Handling and Audit Trails

When business constraints require bypassing standard policies, the record_exception method (lines 446–504) creates an immutable audit trail. The implementation generates an Exception node and creates two relationships: GRANTED_EXCEPTION linking to the decision, and OVERRIDDEN_POLICY linking to the waived policy.

exception_id = engine.record_exception(
    decision_id="dec_123",
    policy_id="loan_policy_001",
    reason="VIP customer waiver",
    approver="senior_manager",
    justification="Strategic partnership",
)

This graph structure enables complete lineage queries, showing which decisions received exceptions, who authorized them, and which policies were overridden.

Integration with Agent Workflows

The policy engine integrates seamlessly with Semantica's agent architecture through lazy initialization. The AgentContext class creates a PolicyEngine instance on first access via self._policy_engine = PolicyEngine(knowledge_graph), making enforcement available to every agent without upfront configuration overhead.

Higher-level APIs in semantica/context/decision_methods.py demonstrate production usage, automatically invoking check_compliance before persisting decisions and routing non-compliant outcomes for human review or exception recording.

Summary

  • PolicyEngine in semantica/context/policy_engine.py orchestrates all policy operations with backend-agnostic graph store support.
  • Immutable versioning creates new policy nodes linked by VERSION_OF edges rather than mutating existing rules.
  • Prefix-based rules (min_, max_, required_) enable declarative compliance logic without code deployment.
  • Impact analysis simulates rule changes against historical decisions to predict compliance deltas before production deployment.
  • Exception tracking maintains audit trails through dedicated nodes and relationships for regulatory compliance.

Frequently Asked Questions

How does Semantica handle policy versioning?

Semantica implements immutable versioning where update_policy creates a new node with an incremented version string and links it to the previous version via a VERSION_OF edge. The get_applicable_policies method automatically filters for the latest version by excluding nodes with outgoing VERSION_OF relationships, ensuring agents always evaluate against current rules while preserving complete historical context.

What rule types are supported by the compliance engine?

The engine supports metadata constraints through prefixes including min_<field>, max_<field>, and required_<field>, alongside decision-specific checks like min_confidence, allowed_outcomes, and required_categories. These rules are evaluated against both the decision's metadata dictionary and its intrinsic fields (confidence, outcome) within the _evaluate_compliance method.

Can the policy engine function without Neo4j?

Yes. The PolicyEngine class operates through the abstract GraphStore interface, automatically detecting Cypher support via self._supports_cypher. When Cypher is unavailable, the engine falls back to generic methods like add_node, find_nodes, and edge traversals, enabling operation with FalkorDB, in-memory stores, or any custom implementation of the graph store contract.

How are policy exceptions audited?

Exceptions are recorded as dedicated nodes with unique IDs via record_exception. The system creates GRANTED_EXCEPTION edges linking decisions to their exceptions and OVERRIDDEN_POLICY edges linking exceptions to the waived policies. This graph structure supports complete lineage queries, allowing auditors to trace which decisions bypassed specific rules, who authorized the waivers, and the business justifications provided.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →